diff --git a/resources/celerity/map.php b/resources/celerity/map.php index badb3d06fb..8c4ba2ef05 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -1,2514 +1,2468 @@ array( - 'conpherence.pkg.css' => '4601645d', - 'conpherence.pkg.js' => '11f3e07e', - 'core.pkg.css' => 'de918edf', - 'core.pkg.js' => '30185d95', + 'conpherence.pkg.css' => 'cea72e09', + 'conpherence.pkg.js' => '6249a1cf', + 'core.pkg.css' => '46d588e4', + 'core.pkg.js' => '035325a7', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => 'e1d704ce', 'differential.pkg.js' => '634399e9', 'diffusion.pkg.css' => '91c5d3a6', 'diffusion.pkg.js' => '84c8f8fd', + 'favicon.ico' => '30672e08', 'maniphest.pkg.css' => '4845691a', 'maniphest.pkg.js' => '949a7498', 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', 'rsrc/css/aphront/dark-console.css' => 'f54bf286', 'rsrc/css/aphront/dialog-view.css' => '593d3f67', 'rsrc/css/aphront/lightbox-attachment.css' => '7acac05d', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => '84cc6640', 'rsrc/css/aphront/notification.css' => '3f6c89c9', 'rsrc/css/aphront/panel-view.css' => '8427b78d', 'rsrc/css/aphront/phabricator-nav-view.css' => 'b29426e9', 'rsrc/css/aphront/table-view.css' => '3225137a', 'rsrc/css/aphront/tokenizer.css' => '056da01b', 'rsrc/css/aphront/tooltip.css' => '1a07aea8', 'rsrc/css/aphront/typeahead-browse.css' => '8904346a', 'rsrc/css/aphront/typeahead.css' => 'd4f16145', 'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af', 'rsrc/css/application/auth/auth.css' => '0877ed6e', 'rsrc/css/application/base/main-menu-view.css' => 'f03e17be', 'rsrc/css/application/base/notification-menu.css' => '1e055865', 'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601', 'rsrc/css/application/base/phui-theme.css' => '798c69b8', 'rsrc/css/application/base/standard-page-view.css' => '79176f5a', 'rsrc/css/application/chatlog/chatlog.css' => 'd295b020', 'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4', 'rsrc/css/application/config/config-options.css' => '0ede4c9b', - 'rsrc/css/application/config/config-page.css' => '8798e14f', + 'rsrc/css/application/config/config-page.css' => 'b80124ae', 'rsrc/css/application/config/config-template.css' => '8f18fa41', 'rsrc/css/application/config/setup-issue.css' => 'f794cfc3', 'rsrc/css/application/config/unhandled-exception.css' => '4c96257a', - 'rsrc/css/application/conpherence/durable-column.css' => '44bcaa19', - 'rsrc/css/application/conpherence/header-pane.css' => '20a7028c', + 'rsrc/css/application/conpherence/durable-column.css' => 'd82e130c', + 'rsrc/css/application/conpherence/header-pane.css' => '1c81cda6', 'rsrc/css/application/conpherence/menu.css' => '4f51db5a', - 'rsrc/css/application/conpherence/message-pane.css' => '0d7dff02', + 'rsrc/css/application/conpherence/message-pane.css' => '394ae8fa', 'rsrc/css/application/conpherence/notification.css' => '965db05b', - 'rsrc/css/application/conpherence/participant-pane.css' => '7bba0b56', - 'rsrc/css/application/conpherence/transaction.css' => '46253e19', - 'rsrc/css/application/conpherence/update.css' => '53bc527a', + 'rsrc/css/application/conpherence/participant-pane.css' => 'ac1baaa8', + 'rsrc/css/application/conpherence/transaction.css' => '85129c68', 'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4', 'rsrc/css/application/countdown/timer.css' => '16c52f5c', 'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a', 'rsrc/css/application/dashboard/dashboard.css' => 'bc6f2127', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', 'rsrc/css/application/differential/changeset-view.css' => '9ef7d354', 'rsrc/css/application/differential/core.css' => '5b7b8ff4', 'rsrc/css/application/differential/phui-inline-comment.css' => '5953c28e', 'rsrc/css/application/differential/revision-comment.css' => '14b8565a', 'rsrc/css/application/differential/revision-history.css' => '0e8eb855', 'rsrc/css/application/differential/revision-list.css' => 'f3c47d33', 'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55', 'rsrc/css/application/diffusion/diffusion-icons.css' => 'd678600a', 'rsrc/css/application/diffusion/diffusion-readme.css' => '297373eb', 'rsrc/css/application/diffusion/diffusion-source.css' => '68b30fd3', 'rsrc/css/application/feed/feed.css' => 'ecd4ec57', 'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2', 'rsrc/css/application/flag/flag.css' => '5337623f', 'rsrc/css/application/harbormaster/harbormaster.css' => 'f491c9f4', 'rsrc/css/application/herald/herald-test.css' => 'a52e323e', 'rsrc/css/application/herald/herald.css' => 'dc31f6e9', 'rsrc/css/application/maniphest/batch-editor.css' => 'b0f0b6d5', 'rsrc/css/application/maniphest/report.css' => '9b9580b7', 'rsrc/css/application/maniphest/task-edit.css' => 'fda62a9b', 'rsrc/css/application/maniphest/task-summary.css' => '11cc5344', 'rsrc/css/application/objectselector/object-selector.css' => '85ee8ce6', 'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b', 'rsrc/css/application/paste/paste.css' => '1898e534', 'rsrc/css/application/people/people-profile.css' => '2473d929', 'rsrc/css/application/phame/phame.css' => '8efb0729', 'rsrc/css/application/pholio/pholio-edit.css' => '07676f51', 'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49', 'rsrc/css/application/pholio/pholio.css' => 'ca89d380', 'rsrc/css/application/phortune/phortune-credit-card-form.css' => '8391eb02', 'rsrc/css/application/phortune/phortune.css' => '5b99dae0', 'rsrc/css/application/phrequent/phrequent.css' => 'ffc185ad', 'rsrc/css/application/phriction/phriction-document-css.css' => '4282e4ad', 'rsrc/css/application/policy/policy-edit.css' => '815c66f7', 'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43', 'rsrc/css/application/policy/policy.css' => '957ea14c', 'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96', 'rsrc/css/application/project/project-card-view.css' => '9418c97d', 'rsrc/css/application/project/project-view.css' => '55d99221', 'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733', 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', 'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd', 'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae', - 'rsrc/css/application/search/application-search-view.css' => 'be6454ec', + 'rsrc/css/application/search/application-search-view.css' => '8452c849', 'rsrc/css/application/search/search-results.css' => '7dea472c', 'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230', 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/core/core.css' => 'd0801452', 'rsrc/css/core/remarkup.css' => 'cd912f2c', 'rsrc/css/core/syntax.css' => '769d3498', - 'rsrc/css/core/z-index.css' => '0d4e5558', + 'rsrc/css/core/z-index.css' => 'd1270942', 'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa', 'rsrc/css/font/font-aleo.css' => '8bdb2835', 'rsrc/css/font/font-awesome.css' => '2b7ebbcc', 'rsrc/css/font/font-lato.css' => 'c7ccd872', 'rsrc/css/font/phui-font-icon-base.css' => '870a7360', 'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82', 'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983', 'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893', 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'fcc9fb41', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '8e10e92c', 'rsrc/css/phui/calendar/phui-calendar.css' => '477acfaa', 'rsrc/css/phui/phui-action-list.css' => 'c5eba19d', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => '3baef8db', 'rsrc/css/phui/phui-basic-nav-view.css' => '7093573b', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-box.css' => '5c8387cf', 'rsrc/css/phui/phui-button.css' => '4a5fbe3d', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-cms.css' => 'be43c8a8', 'rsrc/css/phui/phui-crumbs-view.css' => '195ac419', 'rsrc/css/phui/phui-curtain-view.css' => '947bf1a4', 'rsrc/css/phui/phui-document-pro.css' => 'ca1fed81', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', 'rsrc/css/phui/phui-document.css' => 'c32e8dec', - 'rsrc/css/phui/phui-feed-story.css' => 'aa49845d', + 'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9', 'rsrc/css/phui/phui-fontkit.css' => '9cda225e', 'rsrc/css/phui/phui-form-view.css' => '9e22b190', 'rsrc/css/phui/phui-form.css' => 'aac1d51d', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', 'rsrc/css/phui/phui-header-view.css' => '06385974', 'rsrc/css/phui/phui-hovercard.css' => 'de1a2119', 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', - 'rsrc/css/phui/phui-icon.css' => '9bab6f02', + 'rsrc/css/phui/phui-icon.css' => '417f80fb', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', 'rsrc/css/phui/phui-info-view.css' => '28efab79', 'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0', 'rsrc/css/phui/phui-list.css' => '9da2aa00', 'rsrc/css/phui/phui-object-box.css' => '6b487c57', 'rsrc/css/phui/phui-object-item-list-view.css' => '87278fa0', 'rsrc/css/phui/phui-pager.css' => 'bea33d23', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', 'rsrc/css/phui/phui-profile-menu.css' => '4768721a', 'rsrc/css/phui/phui-property-list-view.css' => '6d8e58ac', 'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591', 'rsrc/css/phui/phui-segment-bar-view.css' => '46342871', 'rsrc/css/phui/phui-spacing.css' => '042804d6', 'rsrc/css/phui/phui-status.css' => 'd5263e49', 'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2', 'rsrc/css/phui/phui-timeline-view.css' => 'bc523970', - 'rsrc/css/phui/phui-two-column-view.css' => 'fcfbe347', + 'rsrc/css/phui/phui-two-column-view.css' => 'bbe32c23', 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7', 'rsrc/css/phui/workboards/phui-workboard.css' => 'e09eb53a', 'rsrc/css/phui/workboards/phui-workcard.css' => '0c62d7c5', 'rsrc/css/phui/workboards/phui-workpanel.css' => '92197373', 'rsrc/css/sprite-login.css' => '6dbbbd97', 'rsrc/css/sprite-tokens.css' => '9cdfd599', 'rsrc/css/syntax/syntax-default.css' => '9923583c', 'rsrc/externals/d3/d3.min.js' => 'a11a5ff2', 'rsrc/externals/font/aleo/aleo-bold.eot' => 'd3d3bed7', 'rsrc/externals/font/aleo/aleo-bold.svg' => '45899c8e', 'rsrc/externals/font/aleo/aleo-bold.ttf' => '4b08bef0', 'rsrc/externals/font/aleo/aleo-bold.woff' => '93b513a1', 'rsrc/externals/font/aleo/aleo-bold.woff2' => '75fbf322', 'rsrc/externals/font/aleo/aleo-regular.eot' => 'a4e29e2f', 'rsrc/externals/font/aleo/aleo-regular.svg' => '42a86f7a', 'rsrc/externals/font/aleo/aleo-regular.ttf' => '751e7479', 'rsrc/externals/font/aleo/aleo-regular.woff' => 'c3744be9', 'rsrc/externals/font/aleo/aleo-regular.woff2' => '851aa0ee', 'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '59b3076c', 'rsrc/externals/font/fontawesome/fontawesome-webfont.ttf' => '45ad7e57', 'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => 'f861e2a8', 'rsrc/externals/font/fontawesome/fontawesome-webfont.woff2' => '0ee0f078', 'rsrc/externals/font/lato/lato-bold.eot' => '99fbcf8c', 'rsrc/externals/font/lato/lato-bold.svg' => '2aa83045', 'rsrc/externals/font/lato/lato-bold.ttf' => '0a7141f7', 'rsrc/externals/font/lato/lato-bold.woff' => 'f5db2061', 'rsrc/externals/font/lato/lato-bold.woff2' => '37a94ecd', 'rsrc/externals/font/lato/lato-bolditalic.eot' => 'b93389d0', 'rsrc/externals/font/lato/lato-bolditalic.svg' => '5442e1ef', 'rsrc/externals/font/lato/lato-bolditalic.ttf' => 'dad31252', 'rsrc/externals/font/lato/lato-bolditalic.woff' => 'e53bcf47', 'rsrc/externals/font/lato/lato-bolditalic.woff2' => 'd035007f', 'rsrc/externals/font/lato/lato-italic.eot' => '6a903f5d', 'rsrc/externals/font/lato/lato-italic.svg' => '0dc7cf2f', 'rsrc/externals/font/lato/lato-italic.ttf' => '629f64f0', 'rsrc/externals/font/lato/lato-italic.woff' => '678dc4bb', 'rsrc/externals/font/lato/lato-italic.woff2' => '7c8dd650', 'rsrc/externals/font/lato/lato-regular.eot' => '848dfb1e', 'rsrc/externals/font/lato/lato-regular.svg' => 'cbd5fd6b', 'rsrc/externals/font/lato/lato-regular.ttf' => 'e270165b', 'rsrc/externals/font/lato/lato-regular.woff' => '13d39fe2', 'rsrc/externals/font/lato/lato-regular.woff2' => '57a9f742', 'rsrc/externals/javelin/core/Event.js' => '2ee659ce', 'rsrc/externals/javelin/core/Stratcom.js' => '6ad39b6f', 'rsrc/externals/javelin/core/__tests__/event-stop-and-kill.js' => '717554e4', 'rsrc/externals/javelin/core/__tests__/install.js' => 'c432ee85', 'rsrc/externals/javelin/core/__tests__/stratcom.js' => '88bf7313', 'rsrc/externals/javelin/core/__tests__/util.js' => 'e251703d', 'rsrc/externals/javelin/core/init.js' => '3010e992', 'rsrc/externals/javelin/core/init_node.js' => 'c234aded', 'rsrc/externals/javelin/core/install.js' => '05270951', 'rsrc/externals/javelin/core/util.js' => '93cc50d6', 'rsrc/externals/javelin/docs/Base.js' => '74676256', 'rsrc/externals/javelin/docs/onload.js' => 'e819c479', 'rsrc/externals/javelin/ext/fx/Color.js' => '7e41274a', 'rsrc/externals/javelin/ext/fx/FX.js' => '54b612ba', 'rsrc/externals/javelin/ext/reactor/core/DynVal.js' => 'f6555212', 'rsrc/externals/javelin/ext/reactor/core/Reactor.js' => '2b8de964', 'rsrc/externals/javelin/ext/reactor/core/ReactorNode.js' => '1ad0a787', 'rsrc/externals/javelin/ext/reactor/core/ReactorNodeCalmer.js' => '76f4ebed', 'rsrc/externals/javelin/ext/reactor/dom/RDOM.js' => 'c90a04fc', 'rsrc/externals/javelin/ext/view/HTMLView.js' => 'fe287620', 'rsrc/externals/javelin/ext/view/View.js' => '0f764c35', 'rsrc/externals/javelin/ext/view/ViewInterpreter.js' => 'f829edb3', 'rsrc/externals/javelin/ext/view/ViewPlaceholder.js' => '47830651', 'rsrc/externals/javelin/ext/view/ViewRenderer.js' => '6c2b09a2', 'rsrc/externals/javelin/ext/view/ViewVisitor.js' => 'efe49472', 'rsrc/externals/javelin/ext/view/__tests__/HTMLView.js' => 'f92d7bcb', 'rsrc/externals/javelin/ext/view/__tests__/View.js' => '6450b38b', 'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5', 'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '6ea96ac9', 'rsrc/externals/javelin/lib/Cookie.js' => '62dfea03', 'rsrc/externals/javelin/lib/DOM.js' => '805b806a', 'rsrc/externals/javelin/lib/History.js' => 'd4505101', 'rsrc/externals/javelin/lib/JSON.js' => '69adf288', 'rsrc/externals/javelin/lib/Leader.js' => 'fea0eb47', 'rsrc/externals/javelin/lib/Mask.js' => '8a41885b', 'rsrc/externals/javelin/lib/Quicksand.js' => '6b8ef10b', 'rsrc/externals/javelin/lib/Request.js' => '94b750d2', 'rsrc/externals/javelin/lib/Resource.js' => '44959b73', 'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692', 'rsrc/externals/javelin/lib/Router.js' => '29274e2b', 'rsrc/externals/javelin/lib/Scrollbar.js' => '087e919c', 'rsrc/externals/javelin/lib/Sound.js' => '949c0fe5', 'rsrc/externals/javelin/lib/URI.js' => 'c989ade3', 'rsrc/externals/javelin/lib/Vector.js' => '2caa8fb8', 'rsrc/externals/javelin/lib/WebSocket.js' => 'e292eaf4', 'rsrc/externals/javelin/lib/Workflow.js' => '1e911d0f', 'rsrc/externals/javelin/lib/__tests__/Cookie.js' => '5ed109e8', 'rsrc/externals/javelin/lib/__tests__/DOM.js' => 'c984504b', 'rsrc/externals/javelin/lib/__tests__/JSON.js' => '837a7d68', 'rsrc/externals/javelin/lib/__tests__/URI.js' => '1e45fda9', 'rsrc/externals/javelin/lib/__tests__/behavior.js' => '1ea62783', 'rsrc/externals/javelin/lib/behavior.js' => '61cbc29a', 'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => '8d3bc1b2', 'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => '70baed2f', 'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => 'e6e25838', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '013ffff9', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => 'b25d5444', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa', 'rsrc/favicons/apple-touch-icon-114x114.png' => '12a24178', 'rsrc/favicons/apple-touch-icon-120x120.png' => '0d1543c7', 'rsrc/favicons/apple-touch-icon-144x144.png' => '8043b5a5', 'rsrc/favicons/apple-touch-icon-152x152.png' => '65905ecd', 'rsrc/favicons/apple-touch-icon-57x57.png' => '2bfc7b0a', 'rsrc/favicons/apple-touch-icon-60x60.png' => '8ff52925', 'rsrc/favicons/apple-touch-icon-72x72.png' => 'a2bb65d6', 'rsrc/favicons/apple-touch-icon-76x76.png' => '2d061a11', - 'rsrc/favicons/dark/apple-touch-icon-114x114.png' => 'd0c8978c', - 'rsrc/favicons/dark/apple-touch-icon-120x120.png' => '3a618bc0', - 'rsrc/favicons/dark/apple-touch-icon-144x144.png' => '92c1e188', - 'rsrc/favicons/dark/apple-touch-icon-152x152.png' => '7ce7e469', - 'rsrc/favicons/dark/apple-touch-icon-57x57.png' => 'e3f3f38b', - 'rsrc/favicons/dark/apple-touch-icon-60x60.png' => '1e0dcc72', - 'rsrc/favicons/dark/apple-touch-icon-72x72.png' => '7fb599b6', - 'rsrc/favicons/dark/apple-touch-icon-76x76.png' => '91146961', - 'rsrc/favicons/dark/favicon-128.png' => 'd6ac4346', - 'rsrc/favicons/dark/favicon-16x16.png' => '17434bb0', - 'rsrc/favicons/dark/favicon-196x196.png' => '5e06ee72', - 'rsrc/favicons/dark/favicon-32x32.png' => 'bdd7e16b', - 'rsrc/favicons/dark/favicon-96x96.png' => '0cf55978', - 'rsrc/favicons/dark/mstile-144x144.png' => '4dc9d42d', - 'rsrc/favicons/dark/mstile-150x150.png' => '2dc61c90', - 'rsrc/favicons/dark/mstile-310x150.png' => '4fe58ab2', - 'rsrc/favicons/dark/mstile-310x310.png' => 'e62c1677', - 'rsrc/favicons/dark/mstile-70x70.png' => '6d1f41b7', 'rsrc/favicons/favicon-128.png' => '72f7e812', 'rsrc/favicons/favicon-16x16.png' => 'fc6275ba', 'rsrc/favicons/favicon-196x196.png' => '95db275e', 'rsrc/favicons/favicon-32x32.png' => '5bd18b6c', 'rsrc/favicons/favicon-96x96.png' => '7242c8e9', + 'rsrc/favicons/favicon-mention.ico' => '1fdd0fa4', + 'rsrc/favicons/favicon-message.ico' => '115bc010', + 'rsrc/favicons/favicon.ico' => 'cdb11121', 'rsrc/favicons/mask-icon.svg' => 'e132a80f', 'rsrc/favicons/mstile-144x144.png' => '310c2ee5', 'rsrc/favicons/mstile-150x150.png' => '74bf5133', 'rsrc/favicons/mstile-310x150.png' => '4a49d3ee', 'rsrc/favicons/mstile-310x310.png' => 'a52ab264', 'rsrc/favicons/mstile-70x70.png' => '5edce7b8', - 'rsrc/favicons/red/apple-touch-icon-114x114.png' => '91e37d1d', - 'rsrc/favicons/red/apple-touch-icon-120x120.png' => '66687533', - 'rsrc/favicons/red/apple-touch-icon-144x144.png' => 'bc06002c', - 'rsrc/favicons/red/apple-touch-icon-152x152.png' => 'a713de42', - 'rsrc/favicons/red/apple-touch-icon-57x57.png' => '4729688b', - 'rsrc/favicons/red/apple-touch-icon-60x60.png' => '07b9b609', - 'rsrc/favicons/red/apple-touch-icon-72x72.png' => 'b20c3698', - 'rsrc/favicons/red/apple-touch-icon-76x76.png' => 'c6e7dd5c', - 'rsrc/favicons/red/favicon-128.png' => 'e2b2f8fe', - 'rsrc/favicons/red/favicon-16x16.png' => '929fbceb', - 'rsrc/favicons/red/favicon-196x196.png' => '94c089a5', - 'rsrc/favicons/red/favicon-32x32.png' => '5848673e', - 'rsrc/favicons/red/favicon-96x96.png' => '895d54e8', - 'rsrc/favicons/red/mstile-144x144.png' => '448639f5', - 'rsrc/favicons/red/mstile-150x150.png' => 'c2ba45d0', - 'rsrc/favicons/red/mstile-310x150.png' => 'b0e50799', - 'rsrc/favicons/red/mstile-310x310.png' => '2475c5a5', - 'rsrc/favicons/red/mstile-70x70.png' => '49b197e8', - 'rsrc/favicons/yellow/apple-touch-icon-114x114.png' => '5271fb3f', - 'rsrc/favicons/yellow/apple-touch-icon-120x120.png' => '6c3d9bf9', - 'rsrc/favicons/yellow/apple-touch-icon-144x144.png' => '6484472c', - 'rsrc/favicons/yellow/apple-touch-icon-152x152.png' => 'e305dda8', - 'rsrc/favicons/yellow/apple-touch-icon-57x57.png' => 'fa6c43d4', - 'rsrc/favicons/yellow/apple-touch-icon-60x60.png' => '2673f162', - 'rsrc/favicons/yellow/apple-touch-icon-72x72.png' => '3ad8020c', - 'rsrc/favicons/yellow/apple-touch-icon-76x76.png' => '58cffd81', - 'rsrc/favicons/yellow/favicon-128.png' => '3b2f8233', - 'rsrc/favicons/yellow/favicon-16x16.png' => 'f3a90518', - 'rsrc/favicons/yellow/favicon-196x196.png' => '932c7c65', - 'rsrc/favicons/yellow/favicon-32x32.png' => '005c9f92', - 'rsrc/favicons/yellow/favicon-96x96.png' => '3ad9bfa9', - 'rsrc/favicons/yellow/mstile-144x144.png' => 'fc52335c', - 'rsrc/favicons/yellow/mstile-150x150.png' => '9e556f80', - 'rsrc/favicons/yellow/mstile-310x150.png' => '2c915073', - 'rsrc/favicons/yellow/mstile-310x310.png' => 'ee49978d', - 'rsrc/favicons/yellow/mstile-70x70.png' => '85c7c939', 'rsrc/image/BFCFDA.png' => 'd5ec91f4', 'rsrc/image/actions/edit.png' => '2fc41442', 'rsrc/image/avatar.png' => 'e132bb6a', 'rsrc/image/checker_dark.png' => 'd8e65881', 'rsrc/image/checker_light.png' => 'a0155918', 'rsrc/image/checker_lighter.png' => 'd5da91b6', 'rsrc/image/d5d8e1.png' => '0c2a1497', 'rsrc/image/darkload.gif' => '1ffd3ec6', 'rsrc/image/divot.png' => '94dded62', 'rsrc/image/examples/hero.png' => '979a86ae', 'rsrc/image/grippy_texture.png' => 'aca81e2f', 'rsrc/image/icon/fatcow/arrow_branch.png' => '2537c01c', 'rsrc/image/icon/fatcow/arrow_merge.png' => '21b660e0', 'rsrc/image/icon/fatcow/bullet_black.png' => 'ff190031', 'rsrc/image/icon/fatcow/bullet_orange.png' => 'e273e5bb', 'rsrc/image/icon/fatcow/bullet_red.png' => 'c0b75434', 'rsrc/image/icon/fatcow/calendar_edit.png' => '24632275', 'rsrc/image/icon/fatcow/document_black.png' => '45fe1c60', 'rsrc/image/icon/fatcow/flag_blue.png' => 'a01abb1d', 'rsrc/image/icon/fatcow/flag_finish.png' => '67825cee', 'rsrc/image/icon/fatcow/flag_ghost.png' => '20ca8783', 'rsrc/image/icon/fatcow/flag_green.png' => '7e0eaa7a', 'rsrc/image/icon/fatcow/flag_orange.png' => '9e73df66', 'rsrc/image/icon/fatcow/flag_pink.png' => '7e92f3b2', 'rsrc/image/icon/fatcow/flag_purple.png' => 'cc517522', 'rsrc/image/icon/fatcow/flag_red.png' => '04ec726f', 'rsrc/image/icon/fatcow/flag_yellow.png' => '73946fd4', 'rsrc/image/icon/fatcow/key_question.png' => '52a0c26a', 'rsrc/image/icon/fatcow/link.png' => '7afd4d5e', 'rsrc/image/icon/fatcow/page_white_edit.png' => '39a2eed8', 'rsrc/image/icon/fatcow/page_white_put.png' => '08c95a0c', 'rsrc/image/icon/fatcow/source/conduit.png' => '4ea01d2f', 'rsrc/image/icon/fatcow/source/email.png' => '9bab3239', 'rsrc/image/icon/fatcow/source/fax.png' => '04195e68', 'rsrc/image/icon/fatcow/source/mobile.png' => 'f1321264', 'rsrc/image/icon/fatcow/source/tablet.png' => '49396799', 'rsrc/image/icon/fatcow/source/web.png' => '136ccb5d', 'rsrc/image/icon/lightbox/close-2.png' => 'cc40e7c8', 'rsrc/image/icon/lightbox/close-hover-2.png' => 'fb5d6d9e', 'rsrc/image/icon/lightbox/left-arrow-2.png' => '8426133b', 'rsrc/image/icon/lightbox/left-arrow-hover-2.png' => '701e5ee3', 'rsrc/image/icon/lightbox/right-arrow-2.png' => '6d5519a0', 'rsrc/image/icon/lightbox/right-arrow-hover-2.png' => '3a04aa21', 'rsrc/image/icon/subscribe.png' => 'd03ed5a5', 'rsrc/image/icon/tango/attachment.png' => 'ecc8022e', 'rsrc/image/icon/tango/edit.png' => '929a1363', 'rsrc/image/icon/tango/go-down.png' => '96d95e43', 'rsrc/image/icon/tango/log.png' => 'b08cc63a', 'rsrc/image/icon/tango/upload.png' => '7bbb7984', 'rsrc/image/icon/unsubscribe.png' => '25725013', 'rsrc/image/lightblue-header.png' => '5c168b6d', 'rsrc/image/logo/light-eye.png' => '1a576ddd', 'rsrc/image/main_texture.png' => '29a2c5ad', 'rsrc/image/menu_texture.png' => '5a17580d', 'rsrc/image/people/harding.png' => '45aa614e', 'rsrc/image/people/jefferson.png' => 'afca0e53', 'rsrc/image/people/lincoln.png' => '9369126d', 'rsrc/image/people/mckinley.png' => 'fb8f16ce', 'rsrc/image/people/taft.png' => 'd7bc402c', 'rsrc/image/people/user0.png' => '03dacaea', 'rsrc/image/people/user1.png' => '4a4e7702', 'rsrc/image/people/user2.png' => '47a0ee40', 'rsrc/image/people/user3.png' => '835ff627', 'rsrc/image/people/user4.png' => 'b0e830f1', 'rsrc/image/people/user5.png' => '9c95b369', 'rsrc/image/people/user6.png' => 'ba3fbfb0', 'rsrc/image/people/user7.png' => 'da613924', 'rsrc/image/people/user8.png' => 'f1035edf', 'rsrc/image/people/user9.png' => '66730be3', 'rsrc/image/people/washington.png' => '40dd301c', 'rsrc/image/phrequent_active.png' => 'a466a8ed', 'rsrc/image/phrequent_inactive.png' => 'bfc15a69', 'rsrc/image/resize.png' => 'fd476de4', 'rsrc/image/sprite-login-X2.png' => '4abee916', 'rsrc/image/sprite-login.png' => '2b9663fd', 'rsrc/image/sprite-tokens-X2.png' => '804a5232', 'rsrc/image/sprite-tokens.png' => 'b41d03da', 'rsrc/image/texture/card-gradient.png' => '815f26e8', 'rsrc/image/texture/dark-menu-hover.png' => '5fa7ece8', 'rsrc/image/texture/dark-menu.png' => '7e22296e', 'rsrc/image/texture/grip.png' => '719404f3', 'rsrc/image/texture/panel-header-gradient.png' => 'e3b8dcfe', 'rsrc/image/texture/phlnx-bg.png' => '8d819209', 'rsrc/image/texture/pholio-background.gif' => 'ba29239c', 'rsrc/image/texture/table_header.png' => '5c433037', 'rsrc/image/texture/table_header_hover.png' => '038ec3b9', 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', 'rsrc/js/application/aphlict/Aphlict.js' => '5359e785', - 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '49e20786', + 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '2a171a9d', 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'fb20ac8d', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9', 'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'edd1ba66', 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 'rsrc/js/application/calendar/behavior-day-view.js' => '4b3c4443', 'rsrc/js/application/calendar/behavior-event-all-day.js' => '937bb700', 'rsrc/js/application/calendar/behavior-month-view.js' => 'fe33e256', 'rsrc/js/application/calendar/behavior-recurring-edit.js' => '5f1c4d5f', 'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408', - 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2', - 'rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js' => 'cf86d16a', - 'rsrc/js/application/conpherence/behavior-durable-column.js' => 'c5238acb', - 'rsrc/js/application/conpherence/behavior-menu.js' => '9eb55204', + 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '358c717b', + 'rsrc/js/application/conpherence/behavior-conpherence-search.js' => '9bbf3762', + 'rsrc/js/application/conpherence/behavior-durable-column.js' => 'aa3bd034', + 'rsrc/js/application/conpherence/behavior-menu.js' => '7524fcfa', 'rsrc/js/application/conpherence/behavior-participant-pane.js' => '8604caa8', 'rsrc/js/application/conpherence/behavior-pontificate.js' => 'f2e58483', 'rsrc/js/application/conpherence/behavior-quicksand-blacklist.js' => '7927a7d3', - 'rsrc/js/application/conpherence/behavior-toggle-widget.js' => '9bdbbab0', + 'rsrc/js/application/conpherence/behavior-toggle-widget.js' => '3dbf94d5', 'rsrc/js/application/countdown/timer.js' => 'e4cc26b3', 'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => 'edf8a145', 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e', 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '019f36c4', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/differential/ChangesetViewManager.js' => 'a2828756', 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '64a5550f', 'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18', 'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d', 'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', 'rsrc/js/application/differential/behavior-dropdown-menus.js' => '9a6b9324', 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '4fbbc3e9', 'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492', 'rsrc/js/application/differential/behavior-populate.js' => '8694b1df', 'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb', 'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d', 'rsrc/js/application/diffusion/DiffusionLocateFileSource.js' => 'b42eddc7', 'rsrc/js/application/diffusion/behavior-audit-preview.js' => 'd835b03a', 'rsrc/js/application/diffusion/behavior-commit-branches.js' => 'bdaf4d04', 'rsrc/js/application/diffusion/behavior-commit-graph.js' => '49ae8328', 'rsrc/js/application/diffusion/behavior-diffusion-browse-file.js' => '054a0f0b', 'rsrc/js/application/diffusion/behavior-jump-to.js' => '73d09eef', 'rsrc/js/application/diffusion/behavior-load-blame.js' => '42126667', 'rsrc/js/application/diffusion/behavior-locate-file.js' => '6d3e1947', 'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc', 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781', 'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef', 'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab', 'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888', 'rsrc/js/application/herald/HeraldRuleEditor.js' => 'd6a7e717', 'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec', 'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3', 'rsrc/js/application/maniphest/behavior-batch-editor.js' => '782ab6e7', 'rsrc/js/application/maniphest/behavior-batch-selector.js' => '7b98d7c5', 'rsrc/js/application/maniphest/behavior-line-chart.js' => 'e4232876', 'rsrc/js/application/maniphest/behavior-list-edit.js' => 'a9f88de2', 'rsrc/js/application/maniphest/behavior-subpriorityeditor.js' => '71237763', 'rsrc/js/application/owners/OwnersPathEditor.js' => 'aa1733d0', 'rsrc/js/application/owners/owners-path-editor.js' => '7a68dda3', 'rsrc/js/application/passphrase/passphrase-credential-control.js' => '3cb0b2fc', 'rsrc/js/application/pholio/behavior-pholio-mock-edit.js' => 'bee502c8', 'rsrc/js/application/pholio/behavior-pholio-mock-view.js' => 'fbe497e7', 'rsrc/js/application/phortune/behavior-stripe-payment-form.js' => '3f5d6dbf', 'rsrc/js/application/phortune/behavior-test-payment-form.js' => 'fc91ab6c', 'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef', 'rsrc/js/application/policy/behavior-policy-control.js' => 'd0c516d5', 'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c', 'rsrc/js/application/projects/WorkboardBoard.js' => 'fe7cb52a', 'rsrc/js/application/projects/WorkboardCard.js' => 'c587b80f', 'rsrc/js/application/projects/WorkboardColumn.js' => '21df4ff5', 'rsrc/js/application/projects/WorkboardController.js' => '55baf5ed', 'rsrc/js/application/projects/behavior-project-boards.js' => '14a1faae', 'rsrc/js/application/projects/behavior-project-create.js' => '065227cc', 'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb', 'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf', 'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8', 'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f', 'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43', 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072', 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f', 'rsrc/js/application/transactions/behavior-comment-actions.js' => '0300eae6', 'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243', 'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96', 'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '94c65b72', 'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => 'b23b49e6', 'rsrc/js/application/transactions/behavior-transaction-list.js' => '13c739ea', 'rsrc/js/application/typeahead/behavior-typeahead-browse.js' => '635de1ec', 'rsrc/js/application/typeahead/behavior-typeahead-search.js' => '93d0c9e3', 'rsrc/js/application/uiexample/JavelinViewExample.js' => 'd4a14807', 'rsrc/js/application/uiexample/ReactorButtonExample.js' => 'd19198c8', 'rsrc/js/application/uiexample/ReactorCheckboxExample.js' => '519705ea', 'rsrc/js/application/uiexample/ReactorFocusExample.js' => '40a6a403', 'rsrc/js/application/uiexample/ReactorInputExample.js' => '886fd850', 'rsrc/js/application/uiexample/ReactorMouseoverExample.js' => '47c794d8', 'rsrc/js/application/uiexample/ReactorRadioExample.js' => '988040b4', 'rsrc/js/application/uiexample/ReactorSelectExample.js' => 'a155550f', 'rsrc/js/application/uiexample/ReactorSendClassExample.js' => '1def2711', 'rsrc/js/application/uiexample/ReactorSendPropertiesExample.js' => 'b1f0ccee', 'rsrc/js/application/uiexample/busy-example.js' => '60479091', 'rsrc/js/application/uiexample/gesture-example.js' => '558829c2', 'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5', 'rsrc/js/core/Busy.js' => '59a7976a', 'rsrc/js/core/DragAndDropFileUpload.js' => '58dea2fa', 'rsrc/js/core/DraggableList.js' => '5a13c79f', + 'rsrc/js/core/Favicon.js' => '1fe2510c', 'rsrc/js/core/FileUpload.js' => '680ea2c8', 'rsrc/js/core/Hovercard.js' => '1bd28176', 'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2', 'rsrc/js/core/KeyboardShortcutManager.js' => '4a021c10', 'rsrc/js/core/MultirowRowManager.js' => 'b5d57730', 'rsrc/js/core/Notification.js' => 'ccf1cbf8', 'rsrc/js/core/Prefab.js' => 'cfd23f37', 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 'rsrc/js/core/TextAreaUtils.js' => '320810c8', - 'rsrc/js/core/Title.js' => 'df5e11d2', + 'rsrc/js/core/Title.js' => '485aaa6c', 'rsrc/js/core/ToolTip.js' => '6323f942', 'rsrc/js/core/behavior-active-nav.js' => 'e379b58e', 'rsrc/js/core/behavior-audio-source.js' => '59b251eb', 'rsrc/js/core/behavior-autofocus.js' => '7319e029', 'rsrc/js/core/behavior-badge-view.js' => '8ff5e24c', 'rsrc/js/core/behavior-choose-control.js' => '327a00d1', 'rsrc/js/core/behavior-dark-console.js' => 'f411b6ae', 'rsrc/js/core/behavior-detect-timezone.js' => '4c193c96', 'rsrc/js/core/behavior-device.js' => 'bb1dd507', 'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '484a6e22', 'rsrc/js/core/behavior-error-log.js' => '6882e80a', 'rsrc/js/core/behavior-fancy-datepicker.js' => '568931f3', 'rsrc/js/core/behavior-file-tree.js' => '88236f00', 'rsrc/js/core/behavior-form.js' => '5c54cbf3', 'rsrc/js/core/behavior-gesture.js' => '3ab51e2c', - 'rsrc/js/core/behavior-global-drag-and-drop.js' => 'c8e57404', + 'rsrc/js/core/behavior-global-drag-and-drop.js' => '960f6a39', 'rsrc/js/core/behavior-high-security-warning.js' => 'a464fe03', 'rsrc/js/core/behavior-history-install.js' => '7ee2b591', 'rsrc/js/core/behavior-hovercard.js' => 'bcaccd64', 'rsrc/js/core/behavior-keyboard-pager.js' => 'a8da01f0', 'rsrc/js/core/behavior-keyboard-shortcuts.js' => '01fca1f0', 'rsrc/js/core/behavior-lightbox-attachments.js' => 'f8ba29d7', 'rsrc/js/core/behavior-line-linker.js' => '1499a8cb', 'rsrc/js/core/behavior-more.js' => 'a80d0378', 'rsrc/js/core/behavior-object-selector.js' => 'e0ec7f2f', 'rsrc/js/core/behavior-oncopy.js' => '2926fff2', 'rsrc/js/core/behavior-phabricator-nav.js' => '08675c6d', 'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '116cf19b', 'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207', 'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b', 'rsrc/js/core/behavior-remarkup-preview.js' => '4b700e9e', 'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e', 'rsrc/js/core/behavior-reveal-content.js' => '60821bc7', 'rsrc/js/core/behavior-scrollbar.js' => '834a1173', 'rsrc/js/core/behavior-search-typeahead.js' => '06c32383', 'rsrc/js/core/behavior-select-content.js' => 'bf5374ef', 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', 'rsrc/js/core/behavior-setup-check-https.js' => '491416b3', 'rsrc/js/core/behavior-time-typeahead.js' => '522431f7', 'rsrc/js/core/behavior-toggle-class.js' => '92b9ec77', 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', 'rsrc/js/core/behavior-tooltip.js' => '42fcb747', 'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d', 'rsrc/js/core/behavior-workflow.js' => '0a3f3021', 'rsrc/js/core/phtize.js' => 'd254d646', 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '1aa4c968', 'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb', 'rsrc/js/phui/behavior-phui-profile-menu.js' => '12884df9', 'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262', 'rsrc/js/phuix/PHUIXAutocomplete.js' => '6d86ce8b', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '82e270da', 'rsrc/js/phuix/PHUIXFormControl.js' => 'e15869a8', 'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b', ), 'symbols' => array( 'almanac-css' => 'dbb9b3af', 'aphront-bars' => '231ac33c', 'aphront-dark-console-css' => 'f54bf286', 'aphront-dialog-view-css' => '593d3f67', 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => '84cc6640', 'aphront-panel-view-css' => '8427b78d', 'aphront-table-view-css' => '3225137a', 'aphront-tokenizer-control-css' => '056da01b', 'aphront-tooltip-css' => '1a07aea8', 'aphront-typeahead-control-css' => 'd4f16145', - 'application-search-view-css' => 'be6454ec', + 'application-search-view-css' => '8452c849', 'auth-css' => '0877ed6e', 'bulk-job-css' => 'df9c1d4a', 'changeset-view-manager' => 'a2828756', 'conduit-api-css' => '7bc725c4', 'config-options-css' => '0ede4c9b', - 'config-page-css' => '8798e14f', - 'conpherence-durable-column-view' => '44bcaa19', - 'conpherence-header-pane-css' => '20a7028c', + 'config-page-css' => 'b80124ae', + 'conpherence-durable-column-view' => 'd82e130c', + 'conpherence-header-pane-css' => '1c81cda6', 'conpherence-menu-css' => '4f51db5a', - 'conpherence-message-pane-css' => '0d7dff02', + 'conpherence-message-pane-css' => '394ae8fa', 'conpherence-notification-css' => '965db05b', - 'conpherence-participant-pane-css' => '7bba0b56', - 'conpherence-thread-manager' => '01774ab2', - 'conpherence-transaction-css' => '46253e19', - 'conpherence-update-css' => '53bc527a', + 'conpherence-participant-pane-css' => 'ac1baaa8', + 'conpherence-thread-manager' => '358c717b', + 'conpherence-transaction-css' => '85129c68', 'd3' => 'a11a5ff2', 'differential-changeset-view-css' => '9ef7d354', 'differential-core-view-css' => '5b7b8ff4', 'differential-inline-comment-editor' => '64a5550f', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', 'differential-revision-history-css' => '0e8eb855', 'differential-revision-list-css' => 'f3c47d33', 'differential-table-of-contents-css' => 'ae4b7a55', 'diffusion-icons-css' => 'd678600a', 'diffusion-readme-css' => '297373eb', 'diffusion-source-css' => '68b30fd3', 'diviner-shared-css' => 'aa3656aa', 'font-aleo' => '8bdb2835', 'font-fontawesome' => '2b7ebbcc', 'font-lato' => 'c7ccd872', 'global-drag-and-drop-css' => '5c1b47c2', 'harbormaster-css' => 'f491c9f4', 'herald-css' => 'dc31f6e9', 'herald-rule-editor' => 'd6a7e717', 'herald-test-css' => 'a52e323e', 'inline-comment-summary-css' => '51efda3a', 'javelin-aphlict' => '5359e785', 'javelin-behavior' => '61cbc29a', - 'javelin-behavior-aphlict-dropdown' => '49e20786', + 'javelin-behavior-aphlict-dropdown' => '2a171a9d', 'javelin-behavior-aphlict-listen' => 'fb20ac8d', 'javelin-behavior-aphlict-status' => '5e2634b9', 'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', 'javelin-behavior-aphront-drag-and-drop-textarea' => '484a6e22', 'javelin-behavior-aphront-form-disable-on-submit' => '5c54cbf3', 'javelin-behavior-aphront-more' => 'a80d0378', 'javelin-behavior-audio-source' => '59b251eb', 'javelin-behavior-audit-preview' => 'd835b03a', 'javelin-behavior-badge-view' => '8ff5e24c', 'javelin-behavior-bulk-job-reload' => 'edf8a145', 'javelin-behavior-calendar-month-view' => 'fe33e256', 'javelin-behavior-choose-control' => '327a00d1', 'javelin-behavior-comment-actions' => '0300eae6', 'javelin-behavior-config-reorder-fields' => 'b6993408', - 'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a', - 'javelin-behavior-conpherence-menu' => '9eb55204', + 'javelin-behavior-conpherence-menu' => '7524fcfa', 'javelin-behavior-conpherence-participant-pane' => '8604caa8', 'javelin-behavior-conpherence-pontificate' => 'f2e58483', + 'javelin-behavior-conpherence-search' => '9bbf3762', 'javelin-behavior-countdown-timer' => 'e4cc26b3', 'javelin-behavior-dark-console' => 'f411b6ae', 'javelin-behavior-dashboard-async-panel' => '469c0d9e', 'javelin-behavior-dashboard-move-panels' => '019f36c4', 'javelin-behavior-dashboard-query-panel-select' => '453c5375', 'javelin-behavior-dashboard-tab-panel' => 'd4eecc63', 'javelin-behavior-day-view' => '4b3c4443', 'javelin-behavior-desktop-notifications-control' => 'edd1ba66', 'javelin-behavior-detect-timezone' => '4c193c96', 'javelin-behavior-device' => 'bb1dd507', 'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18', 'javelin-behavior-differential-comment-jump' => '4fdb476d', 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', 'javelin-behavior-differential-dropdown-menus' => '9a6b9324', 'javelin-behavior-differential-edit-inline-comments' => '4fbbc3e9', 'javelin-behavior-differential-feedback-preview' => 'b064af76', 'javelin-behavior-differential-keyboard-navigation' => '2c426492', 'javelin-behavior-differential-populate' => '8694b1df', 'javelin-behavior-differential-toggle-files' => 'ca3f91eb', 'javelin-behavior-differential-user-select' => 'a8d8459d', 'javelin-behavior-diffusion-browse-file' => '054a0f0b', 'javelin-behavior-diffusion-commit-branches' => 'bdaf4d04', 'javelin-behavior-diffusion-commit-graph' => '49ae8328', 'javelin-behavior-diffusion-jump-to' => '73d09eef', 'javelin-behavior-diffusion-locate-file' => '6d3e1947', 'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc', 'javelin-behavior-doorkeeper-tag' => 'e5822781', 'javelin-behavior-drydock-live-operation-status' => '901935ef', - 'javelin-behavior-durable-column' => 'c5238acb', + 'javelin-behavior-durable-column' => 'aa3bd034', 'javelin-behavior-editengine-reorder-configs' => 'd7a74243', 'javelin-behavior-editengine-reorder-fields' => 'b59e1e96', 'javelin-behavior-error-log' => '6882e80a', 'javelin-behavior-event-all-day' => '937bb700', 'javelin-behavior-fancy-datepicker' => '568931f3', - 'javelin-behavior-global-drag-and-drop' => 'c8e57404', + 'javelin-behavior-global-drag-and-drop' => '960f6a39', 'javelin-behavior-herald-rule-editor' => '7ebaeed3', 'javelin-behavior-high-security-warning' => 'a464fe03', 'javelin-behavior-history-install' => '7ee2b591', 'javelin-behavior-icon-composer' => '8499b6ab', 'javelin-behavior-launch-icon-composer' => '48086888', 'javelin-behavior-lightbox-attachments' => 'f8ba29d7', 'javelin-behavior-line-chart' => 'e4232876', 'javelin-behavior-load-blame' => '42126667', 'javelin-behavior-maniphest-batch-editor' => '782ab6e7', 'javelin-behavior-maniphest-batch-selector' => '7b98d7c5', 'javelin-behavior-maniphest-list-editor' => 'a9f88de2', 'javelin-behavior-maniphest-subpriority-editor' => '71237763', 'javelin-behavior-owners-path-editor' => '7a68dda3', 'javelin-behavior-passphrase-credential-control' => '3cb0b2fc', 'javelin-behavior-persona-login' => '9414ff18', 'javelin-behavior-phabricator-active-nav' => 'e379b58e', 'javelin-behavior-phabricator-autofocus' => '7319e029', 'javelin-behavior-phabricator-busy-example' => '60479091', 'javelin-behavior-phabricator-file-tree' => '88236f00', 'javelin-behavior-phabricator-gesture' => '3ab51e2c', 'javelin-behavior-phabricator-gesture-example' => '558829c2', 'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0', 'javelin-behavior-phabricator-keyboard-shortcuts' => '01fca1f0', 'javelin-behavior-phabricator-line-linker' => '1499a8cb', 'javelin-behavior-phabricator-nav' => '08675c6d', 'javelin-behavior-phabricator-notification-example' => '8ce821c5', 'javelin-behavior-phabricator-object-selector' => 'e0ec7f2f', 'javelin-behavior-phabricator-oncopy' => '2926fff2', 'javelin-behavior-phabricator-remarkup-assist' => '116cf19b', 'javelin-behavior-phabricator-reveal-content' => '60821bc7', 'javelin-behavior-phabricator-search-typeahead' => '06c32383', 'javelin-behavior-phabricator-show-older-transactions' => '94c65b72', 'javelin-behavior-phabricator-tooltips' => '42fcb747', 'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6', 'javelin-behavior-phabricator-transaction-list' => '13c739ea', 'javelin-behavior-phabricator-watch-anchor' => '9f36c42d', 'javelin-behavior-pholio-mock-edit' => 'bee502c8', 'javelin-behavior-pholio-mock-view' => 'fbe497e7', 'javelin-behavior-phui-dropdown-menu' => '1aa4c968', 'javelin-behavior-phui-file-upload' => 'b003d4fb', 'javelin-behavior-phui-hovercards' => 'bcaccd64', 'javelin-behavior-phui-profile-menu' => '12884df9', 'javelin-behavior-phui-submenu' => 'a6f7a73b', 'javelin-behavior-phui-tab-group' => '0a0b10e9', 'javelin-behavior-policy-control' => 'd0c516d5', 'javelin-behavior-policy-rule-editor' => '5e9f347c', 'javelin-behavior-project-boards' => '14a1faae', 'javelin-behavior-project-create' => '065227cc', 'javelin-behavior-quicksand-blacklist' => '7927a7d3', 'javelin-behavior-read-only-warning' => 'ba158207', 'javelin-behavior-recurring-edit' => '5f1c4d5f', 'javelin-behavior-refresh-csrf' => 'ab2f381b', 'javelin-behavior-releeph-preview-branch' => 'b2b4fbaf', 'javelin-behavior-releeph-request-state-change' => 'a0b57eb8', 'javelin-behavior-releeph-request-typeahead' => 'de2e896f', 'javelin-behavior-remarkup-preview' => '4b700e9e', 'javelin-behavior-reorder-applications' => '76b9fc3e', 'javelin-behavior-reorder-columns' => 'e1d25dfb', 'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072', 'javelin-behavior-repository-crossreference' => 'e5339c43', 'javelin-behavior-scrollbar' => '834a1173', 'javelin-behavior-search-reorder-queries' => 'e9581f08', 'javelin-behavior-select-content' => 'bf5374ef', 'javelin-behavior-select-on-click' => '4e3e79a6', 'javelin-behavior-setup-check-https' => '491416b3', 'javelin-behavior-slowvote-embed' => '887ad43f', 'javelin-behavior-stripe-payment-form' => '3f5d6dbf', 'javelin-behavior-test-payment-form' => 'fc91ab6c', 'javelin-behavior-time-typeahead' => '522431f7', 'javelin-behavior-toggle-class' => '92b9ec77', - 'javelin-behavior-toggle-widget' => '9bdbbab0', + 'javelin-behavior-toggle-widget' => '3dbf94d5', 'javelin-behavior-typeahead-browse' => '635de1ec', 'javelin-behavior-typeahead-search' => '93d0c9e3', 'javelin-behavior-view-placeholder' => '47830651', 'javelin-behavior-workflow' => '0a3f3021', 'javelin-color' => '7e41274a', 'javelin-cookie' => '62dfea03', 'javelin-diffusion-locate-file-source' => 'b42eddc7', 'javelin-dom' => '805b806a', 'javelin-dynval' => 'f6555212', 'javelin-event' => '2ee659ce', 'javelin-fx' => '54b612ba', 'javelin-history' => 'd4505101', 'javelin-install' => '05270951', 'javelin-json' => '69adf288', 'javelin-leader' => 'fea0eb47', 'javelin-magical-init' => '3010e992', 'javelin-mask' => '8a41885b', 'javelin-quicksand' => '6b8ef10b', 'javelin-reactor' => '2b8de964', 'javelin-reactor-dom' => 'c90a04fc', 'javelin-reactor-node-calmer' => '76f4ebed', 'javelin-reactornode' => '1ad0a787', 'javelin-request' => '94b750d2', 'javelin-resource' => '44959b73', 'javelin-routable' => 'b3e7d692', 'javelin-router' => '29274e2b', 'javelin-scrollbar' => '087e919c', 'javelin-sound' => '949c0fe5', 'javelin-stratcom' => '6ad39b6f', 'javelin-tokenizer' => '8d3bc1b2', 'javelin-typeahead' => '70baed2f', 'javelin-typeahead-composite-source' => '503e17fd', 'javelin-typeahead-normalizer' => 'e6e25838', 'javelin-typeahead-ondemand-source' => '013ffff9', 'javelin-typeahead-preloaded-source' => '54f314a0', 'javelin-typeahead-source' => 'b25d5444', 'javelin-typeahead-static-source' => '6c0e62fa', 'javelin-uri' => 'c989ade3', 'javelin-util' => '93cc50d6', 'javelin-vector' => '2caa8fb8', 'javelin-view' => '0f764c35', 'javelin-view-html' => 'fe287620', 'javelin-view-interpreter' => 'f829edb3', 'javelin-view-renderer' => '6c2b09a2', 'javelin-view-visitor' => 'efe49472', 'javelin-websocket' => 'e292eaf4', 'javelin-workboard-board' => 'fe7cb52a', 'javelin-workboard-card' => 'c587b80f', 'javelin-workboard-column' => '21df4ff5', 'javelin-workboard-controller' => '55baf5ed', 'javelin-workflow' => '1e911d0f', 'lightbox-attachment-css' => '7acac05d', 'maniphest-batch-editor' => 'b0f0b6d5', 'maniphest-report-css' => '9b9580b7', 'maniphest-task-edit-css' => 'fda62a9b', 'maniphest-task-summary-css' => '11cc5344', 'multirow-row-manager' => 'b5d57730', 'owners-path-editor' => 'aa1733d0', 'owners-path-editor-css' => '2f00933b', 'paste-css' => '1898e534', 'path-typeahead' => 'f7fc67ec', 'people-profile-css' => '2473d929', 'phabricator-action-list-view-css' => 'c5eba19d', 'phabricator-application-launch-view-css' => '95351601', 'phabricator-busy' => '59a7976a', 'phabricator-chatlog-css' => 'd295b020', 'phabricator-content-source-view-css' => '4b8b05d4', 'phabricator-core-css' => 'd0801452', 'phabricator-countdown-css' => '16c52f5c', 'phabricator-dashboard-css' => 'bc6f2127', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => '5a13c79f', 'phabricator-fatal-config-template-css' => '8f18fa41', + 'phabricator-favicon' => '1fe2510c', 'phabricator-feed-css' => 'ecd4ec57', 'phabricator-file-upload' => '680ea2c8', 'phabricator-filetree-view-css' => 'fccf9f82', 'phabricator-flag-css' => '5337623f', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => '4a021c10', 'phabricator-main-menu-view' => 'f03e17be', 'phabricator-nav-view-css' => 'b29426e9', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', 'phabricator-notification-menu-css' => '1e055865', 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => 'cfd23f37', 'phabricator-remarkup-css' => 'cd912f2c', 'phabricator-search-results-css' => '7dea472c', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', 'phabricator-source-code-view-css' => 'cbeef983', 'phabricator-standard-page-view' => '79176f5a', 'phabricator-textareautils' => '320810c8', - 'phabricator-title' => 'df5e11d2', + 'phabricator-title' => '485aaa6c', 'phabricator-tooltip' => '6323f942', 'phabricator-ui-example-css' => '528b19de', 'phabricator-uiexample-javelin-view' => 'd4a14807', 'phabricator-uiexample-reactor-button' => 'd19198c8', 'phabricator-uiexample-reactor-checkbox' => '519705ea', 'phabricator-uiexample-reactor-focus' => '40a6a403', 'phabricator-uiexample-reactor-input' => '886fd850', 'phabricator-uiexample-reactor-mouseover' => '47c794d8', 'phabricator-uiexample-reactor-radio' => '988040b4', 'phabricator-uiexample-reactor-select' => 'a155550f', 'phabricator-uiexample-reactor-sendclass' => '1def2711', 'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee', - 'phabricator-zindex-css' => '0d4e5558', + 'phabricator-zindex-css' => 'd1270942', 'phame-css' => '8efb0729', 'pholio-css' => 'ca89d380', 'pholio-edit-css' => '07676f51', 'pholio-inline-comments-css' => '8e545e49', 'phortune-credit-card-form' => '2290aeef', 'phortune-credit-card-form-css' => '8391eb02', 'phortune-css' => '5b99dae0', 'phrequent-css' => 'ffc185ad', 'phriction-document-css' => '4282e4ad', 'phui-action-panel-css' => '91c7b835', 'phui-badge-view-css' => '3baef8db', 'phui-basic-nav-view-css' => '7093573b', 'phui-big-info-view-css' => 'bd903741', 'phui-box-css' => '5c8387cf', 'phui-button-css' => '4a5fbe3d', 'phui-calendar-css' => '477acfaa', 'phui-calendar-day-css' => '572b1893', 'phui-calendar-list-css' => 'fcc9fb41', 'phui-calendar-month-css' => '8e10e92c', 'phui-chart-css' => '6bf6f78e', 'phui-cms-css' => 'be43c8a8', 'phui-crumbs-view-css' => '195ac419', 'phui-curtain-view-css' => '947bf1a4', 'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-view-css' => 'c32e8dec', 'phui-document-view-pro-css' => 'ca1fed81', - 'phui-feed-story-css' => 'aa49845d', + 'phui-feed-story-css' => '44a9c8e9', 'phui-font-icon-base-css' => '870a7360', 'phui-fontkit-css' => '9cda225e', 'phui-form-css' => 'aac1d51d', 'phui-form-view-css' => '9e22b190', 'phui-head-thing-view-css' => 'fd311e5f', 'phui-header-view-css' => '06385974', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'de1a2119', 'phui-icon-set-selector-css' => '1ab67aad', - 'phui-icon-view-css' => '9bab6f02', + 'phui-icon-view-css' => '417f80fb', 'phui-image-mask-css' => 'a8498f9c', 'phui-info-panel-css' => '27ea50a1', 'phui-info-view-css' => '28efab79', 'phui-inline-comment-view-css' => '5953c28e', 'phui-invisible-character-view-css' => '6993d9f0', 'phui-list-view-css' => '9da2aa00', 'phui-object-box-css' => '6b487c57', 'phui-object-item-list-view-css' => '87278fa0', 'phui-pager-css' => 'bea33d23', 'phui-pinboard-view-css' => '2495140e', 'phui-profile-menu-css' => '4768721a', 'phui-property-list-view-css' => '6d8e58ac', 'phui-remarkup-preview-css' => '1a8f2591', 'phui-segment-bar-view-css' => '46342871', 'phui-spacing-css' => '042804d6', 'phui-status-list-view-css' => 'd5263e49', 'phui-tag-view-css' => '6bbd83e2', 'phui-theme-css' => '798c69b8', 'phui-timeline-view-css' => 'bc523970', - 'phui-two-column-view-css' => 'fcfbe347', + 'phui-two-column-view-css' => 'bbe32c23', 'phui-workboard-color-css' => 'ac6fe6a7', 'phui-workboard-view-css' => 'e09eb53a', 'phui-workcard-view-css' => '0c62d7c5', 'phui-workpanel-view-css' => '92197373', 'phuix-action-list-view' => 'b5c256b8', 'phuix-action-view' => '8cf6d262', 'phuix-autocomplete' => '6d86ce8b', 'phuix-dropdown-menu' => '82e270da', 'phuix-form-control-view' => 'e15869a8', 'phuix-icon-view' => 'bff6884b', 'policy-css' => '957ea14c', 'policy-edit-css' => '815c66f7', 'policy-transaction-detail-css' => '82100a43', 'ponder-view-css' => 'fbd45f96', 'project-card-view-css' => '9418c97d', 'project-view-css' => '55d99221', 'releeph-core' => '9b3c5733', 'releeph-preview-branch' => 'b7a6f4a5', 'releeph-request-differential-create-dialog' => '8d8b92cd', 'releeph-request-typeahead-css' => '667a48ae', 'setup-issue-css' => 'f794cfc3', 'sprite-login-css' => '6dbbbd97', 'sprite-tokens-css' => '9cdfd599', 'syntax-default-css' => '9923583c', 'syntax-highlighting-css' => '769d3498', 'tokens-css' => '3d0f239e', 'typeahead-browse-css' => '8904346a', 'unhandled-exception-css' => '4c96257a', ), 'requires' => array( '013ffff9' => array( 'javelin-install', 'javelin-util', 'javelin-request', 'javelin-typeahead-source', ), - '01774ab2' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-aphlict', - 'javelin-workflow', - 'javelin-router', - 'javelin-behavior-device', - 'javelin-vector', - ), '019f36c4' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-workflow', 'phabricator-draggable-list', ), '01fca1f0' => array( 'javelin-behavior', 'javelin-workflow', 'javelin-json', 'javelin-dom', 'phabricator-keyboard-shortcut', ), '0300eae6' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phuix-form-control-view', 'phuix-icon-view', 'javelin-behavior-phabricator-gesture', ), '05270951' => array( 'javelin-util', 'javelin-magical-init', ), '054a0f0b' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phabricator-tooltip', ), '056da01b' => array( 'aphront-typeahead-control-css', 'phui-tag-view-css', ), '065227cc' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', ), '06c32383' => array( 'javelin-behavior', 'javelin-typeahead-ondemand-source', 'javelin-typeahead', 'javelin-dom', 'javelin-uri', 'javelin-util', 'javelin-stratcom', 'phabricator-prefab', 'phuix-icon-view', ), '08675c6d' => array( 'javelin-behavior', 'javelin-behavior-device', 'javelin-stratcom', 'javelin-dom', 'javelin-magical-init', 'javelin-vector', 'javelin-request', 'javelin-util', ), '087e919c' => array( 'javelin-install', 'javelin-dom', 'javelin-stratcom', 'javelin-vector', ), '0a0b10e9' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '0a3f3021' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'javelin-router', ), '0f764c35' => array( 'javelin-install', 'javelin-util', ), '116cf19b' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phabricator-phtize', 'phabricator-textareautils', 'javelin-workflow', 'javelin-vector', 'phuix-autocomplete', ), '12884df9' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '13c739ea' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'javelin-uri', 'phabricator-textareautils', ), '1499a8cb' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-history', ), '14a1faae' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-vector', 'javelin-stratcom', 'javelin-workflow', 'javelin-workboard-controller', ), '1aa4c968' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phuix-dropdown-menu', ), '1ad0a787' => array( 'javelin-install', 'javelin-reactor', 'javelin-util', 'javelin-reactor-node-calmer', ), '1ae869f2' => array( 'javelin-install', 'javelin-util', 'phabricator-keyboard-shortcut-manager', ), '1bd28176' => array( 'javelin-install', 'javelin-dom', 'javelin-vector', 'javelin-request', 'javelin-uri', ), '1def2711' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), '1e911d0f' => array( 'javelin-stratcom', 'javelin-request', 'javelin-dom', 'javelin-vector', 'javelin-install', 'javelin-util', 'javelin-mask', 'javelin-uri', 'javelin-routable', ), + '1fe2510c' => array( + 'javelin-install', + 'javelin-dom', + ), '21df4ff5' => array( 'javelin-install', 'javelin-workboard-card', ), '2290aeef' => array( 'javelin-install', 'javelin-dom', 'javelin-json', 'javelin-workflow', 'javelin-util', ), '2926fff2' => array( 'javelin-behavior', 'javelin-dom', ), '29274e2b' => array( 'javelin-install', 'javelin-util', ), + '2a171a9d' => array( + 'javelin-behavior', + 'javelin-request', + 'javelin-stratcom', + 'javelin-vector', + 'javelin-dom', + 'javelin-uri', + 'javelin-behavior-device', + 'phabricator-title', + 'phabricator-favicon', + ), '2b8de964' => array( 'javelin-install', 'javelin-util', ), '2c426492' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'phabricator-keyboard-shortcut', ), '2caa8fb8' => array( 'javelin-install', 'javelin-event', ), '2ee659ce' => array( 'javelin-install', ), '320810c8' => array( 'javelin-install', 'javelin-dom', 'javelin-vector', ), '327a00d1' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-workflow', ), + '358c717b' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-aphlict', + 'javelin-workflow', + 'javelin-router', + 'javelin-behavior-device', + 'javelin-vector', + ), '3ab51e2c' => array( 'javelin-behavior', 'javelin-behavior-device', 'javelin-stratcom', 'javelin-vector', 'javelin-dom', 'javelin-magical-init', ), '3cb0b2fc' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'javelin-util', 'javelin-uri', ), + '3dbf94d5' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-util', + 'javelin-workflow', + 'javelin-stratcom', + ), '3f5d6dbf' => array( 'javelin-behavior', 'javelin-dom', 'phortune-credit-card-form', ), '40a6a403' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), 42126667 => array( 'javelin-behavior', 'javelin-dom', 'javelin-request', ), '42fcb747' => array( 'javelin-behavior', 'javelin-behavior-device', 'javelin-stratcom', 'phabricator-tooltip', ), '44959b73' => array( 'javelin-util', 'javelin-uri', 'javelin-install', ), '453c5375' => array( 'javelin-behavior', 'javelin-dom', ), '469c0d9e' => array( 'javelin-behavior', 'javelin-dom', 'javelin-workflow', ), 47830651 => array( 'javelin-behavior', 'javelin-dom', 'javelin-view-renderer', 'javelin-install', ), '47c794d8' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), 48086888 => array( 'javelin-behavior', 'javelin-dom', 'javelin-workflow', ), '484a6e22' => array( 'javelin-behavior', 'javelin-dom', 'phabricator-drag-and-drop-file-upload', 'phabricator-textareautils', ), + '485aaa6c' => array( + 'javelin-install', + ), '491416b3' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-notification', ), '49ae8328' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', ), - '49e20786' => array( - 'javelin-behavior', - 'javelin-request', - 'javelin-stratcom', - 'javelin-vector', - 'javelin-dom', - 'javelin-uri', - 'javelin-behavior-device', - 'phabricator-title', - ), '4a021c10' => array( 'javelin-install', 'javelin-util', 'javelin-stratcom', 'javelin-dom', 'javelin-vector', ), '4b3c4443' => array( 'phuix-icon-view', ), '4b700e9e' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phabricator-shaped-request', ), '4c193c96' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-notification', ), '4e3e79a6' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '4fbbc3e9' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-util', 'javelin-vector', 'differential-inline-comment-editor', ), '4fdb476d' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '503e17fd' => array( 'javelin-install', 'javelin-typeahead-source', 'javelin-util', ), '519705ea' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), '522431f7' => array( 'javelin-behavior', 'javelin-util', 'javelin-dom', 'javelin-stratcom', 'javelin-vector', 'javelin-typeahead-static-source', ), '5359e785' => array( 'javelin-install', 'javelin-util', 'javelin-websocket', 'javelin-leader', 'javelin-json', ), '54b612ba' => array( 'javelin-color', 'javelin-install', 'javelin-util', ), '54f314a0' => array( 'javelin-install', 'javelin-util', 'javelin-request', 'javelin-typeahead-source', ), '558829c2' => array( 'javelin-stratcom', 'javelin-behavior', 'javelin-vector', 'javelin-dom', ), '55baf5ed' => array( 'javelin-install', 'javelin-dom', 'javelin-util', 'javelin-vector', 'javelin-stratcom', 'javelin-workflow', 'phabricator-drag-and-drop-file-upload', 'javelin-workboard-board', ), '568931f3' => array( 'javelin-behavior', 'javelin-util', 'javelin-dom', 'javelin-stratcom', 'javelin-vector', ), '58dea2fa' => array( 'javelin-install', 'javelin-util', 'javelin-request', 'javelin-dom', 'javelin-uri', 'phabricator-file-upload', ), '59a7976a' => array( 'javelin-install', 'javelin-dom', 'javelin-fx', ), '59b251eb' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-vector', 'javelin-dom', ), '5a13c79f' => array( 'javelin-install', 'javelin-dom', 'javelin-stratcom', 'javelin-util', 'javelin-vector', 'javelin-magical-init', ), '5c54cbf3' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '5e2634b9' => array( 'javelin-behavior', 'javelin-aphlict', 'phabricator-phtize', 'javelin-dom', ), '5e9f347c' => array( 'javelin-behavior', 'multirow-row-manager', 'javelin-dom', 'javelin-util', 'phabricator-prefab', 'javelin-json', ), 60479091 => array( 'phabricator-busy', 'javelin-behavior', ), '60821bc7' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '61cbc29a' => array( 'javelin-magical-init', 'javelin-util', ), '62dfea03' => array( 'javelin-install', 'javelin-util', ), '6323f942' => array( 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-vector', ), '635de1ec' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', ), '64a5550f' => array( 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-install', 'javelin-request', 'javelin-workflow', ), '680ea2c8' => array( 'javelin-install', 'javelin-dom', 'phabricator-notification', ), '6882e80a' => array( 'javelin-dom', ), '69adf288' => array( 'javelin-install', ), '6ad39b6f' => array( 'javelin-install', 'javelin-event', 'javelin-util', 'javelin-magical-init', ), '6b8ef10b' => array( 'javelin-install', ), '6c0e62fa' => array( 'javelin-install', 'javelin-typeahead-source', ), '6c2b09a2' => array( 'javelin-install', 'javelin-util', ), '6d3e1947' => array( 'javelin-behavior', 'javelin-diffusion-locate-file-source', 'javelin-dom', 'javelin-typeahead', 'javelin-uri', ), '6d86ce8b' => array( 'javelin-install', 'javelin-dom', 'phuix-icon-view', 'phabricator-prefab', ), '70baed2f' => array( 'javelin-install', 'javelin-dom', 'javelin-vector', 'javelin-util', ), 71237763 => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'phabricator-draggable-list', ), '7319e029' => array( 'javelin-behavior', 'javelin-dom', ), '73d09eef' => array( 'javelin-behavior', 'javelin-vector', 'javelin-dom', ), + '7524fcfa' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-workflow', + 'javelin-behavior-device', + 'javelin-history', + 'javelin-vector', + 'javelin-scrollbar', + 'phabricator-title', + 'phabricator-shaped-request', + 'conpherence-thread-manager', + ), '769d3498' => array( 'syntax-default-css', ), '76b9fc3e' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), '76f4ebed' => array( 'javelin-install', 'javelin-reactor', 'javelin-util', ), '782ab6e7' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phabricator-prefab', 'multirow-row-manager', 'javelin-json', ), '7927a7d3' => array( 'javelin-behavior', 'javelin-quicksand', ), '7a68dda3' => array( 'owners-path-editor', 'javelin-behavior', ), '7b98d7c5' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-util', ), '7cbe244b' => array( 'javelin-install', 'javelin-util', 'javelin-request', 'javelin-router', ), '7e41274a' => array( 'javelin-install', ), '7ebaeed3' => array( 'herald-rule-editor', 'javelin-behavior', ), '7ee2b591' => array( 'javelin-behavior', 'javelin-history', ), '805b806a' => array( 'javelin-magical-init', 'javelin-install', 'javelin-util', 'javelin-vector', 'javelin-stratcom', ), '82e270da' => array( 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-vector', 'javelin-stratcom', ), '834a1173' => array( 'javelin-behavior', 'javelin-scrollbar', ), '8499b6ab' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', ), '85ee8ce6' => array( 'aphront-dialog-view-css', ), '8604caa8' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'javelin-util', 'phabricator-notification', 'conpherence-thread-manager', ), '8694b1df' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'phabricator-tooltip', 'changeset-view-manager', ), '88236f00' => array( 'javelin-behavior', 'phabricator-keyboard-shortcut', 'javelin-stratcom', ), '886fd850' => array( 'javelin-install', 'javelin-reactor-dom', 'javelin-view-html', 'javelin-view-interpreter', 'javelin-view-renderer', ), '887ad43f' => array( 'javelin-behavior', 'javelin-request', 'javelin-stratcom', 'javelin-dom', ), '8a41885b' => array( 'javelin-install', 'javelin-dom', ), '8bdb2835' => array( 'phui-fontkit-css', ), '8ce821c5' => array( 'phabricator-notification', 'javelin-stratcom', 'javelin-behavior', ), '8cf6d262' => array( 'javelin-install', 'javelin-dom', 'javelin-util', ), '8d3bc1b2' => array( 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-install', ), '8ff5e24c' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '901935ef' => array( 'javelin-behavior', 'javelin-dom', 'javelin-request', ), 92197373 => array( 'phui-workcard-view-css', ), '92b9ec77' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), '93d0c9e3' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', ), '9414ff18' => array( 'javelin-behavior', 'javelin-resource', 'javelin-stratcom', 'javelin-workflow', 'javelin-util', ), '949c0fe5' => array( 'javelin-install', ), '94b750d2' => array( 'javelin-install', 'javelin-stratcom', 'javelin-util', 'javelin-behavior', 'javelin-json', 'javelin-dom', 'javelin-resource', 'javelin-routable', ), '94c65b72' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phabricator-busy', ), + '960f6a39' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-uri', + 'javelin-mask', + 'phabricator-drag-and-drop-file-upload', + ), '988040b4' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), '9a6b9324' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-workflow', 'phuix-dropdown-menu', 'phuix-action-list-view', 'phuix-action-view', 'phabricator-phtize', 'changeset-view-manager', ), - '9bdbbab0' => array( + '9bbf3762' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-workflow', 'javelin-stratcom', ), - '9eb55204' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-workflow', - 'javelin-behavior-device', - 'javelin-history', - 'javelin-vector', - 'javelin-scrollbar', - 'phabricator-title', - 'phabricator-shaped-request', - 'conpherence-thread-manager', - ), '9ef7d354' => array( 'phui-inline-comment-view-css', ), '9f36c42d' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-vector', ), 'a0b57eb8' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'javelin-util', 'phabricator-keyboard-shortcut', ), 'a155550f' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), 'a2828756' => array( 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-install', 'javelin-workflow', 'javelin-router', 'javelin-behavior-device', 'javelin-vector', ), 'a464fe03' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-notification', ), 'a6f7a73b' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), 'a80d0378' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), 'a8d8459d' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', ), 'a8da01f0' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-keyboard-shortcut', ), 'a9f88de2' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-workflow', 'javelin-fx', 'javelin-util', ), 'aa1733d0' => array( 'multirow-row-manager', 'javelin-install', 'path-typeahead', 'javelin-dom', 'javelin-util', 'phabricator-prefab', ), + 'aa3bd034' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-behavior-device', + 'javelin-scrollbar', + 'javelin-quicksand', + 'phabricator-keyboard-shortcut', + 'conpherence-thread-manager', + ), 'ab2f381b' => array( 'javelin-request', 'javelin-behavior', 'javelin-dom', 'javelin-router', 'javelin-util', 'phabricator-busy', ), 'b003d4fb' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phuix-dropdown-menu', ), 'b064af76' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-request', 'javelin-util', 'phabricator-shaped-request', ), 'b1f0ccee' => array( 'javelin-install', 'javelin-dom', 'javelin-reactor-dom', ), 'b23b49e6' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-request', 'phabricator-shaped-request', ), 'b25d5444' => array( 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-typeahead-normalizer', ), 'b2b4fbaf' => array( 'javelin-behavior', 'javelin-dom', 'javelin-uri', 'javelin-request', ), 'b3a4b884' => array( 'javelin-behavior', 'phabricator-prefab', ), 'b3e7d692' => array( 'javelin-install', ), 'b42eddc7' => array( 'javelin-install', 'javelin-dom', 'javelin-typeahead-preloaded-source', 'javelin-util', ), 'b59e1e96' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'b5c256b8' => array( 'javelin-install', 'javelin-dom', ), 'b5d57730' => array( 'javelin-install', 'javelin-stratcom', 'javelin-dom', 'javelin-util', ), 'b6993408' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-json', 'phabricator-draggable-list', ), 'ba158207' => array( 'javelin-behavior', 'javelin-uri', 'phabricator-notification', ), 'bb1dd507' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-vector', 'javelin-install', ), 'bcaccd64' => array( 'javelin-behavior', 'javelin-behavior-device', 'javelin-stratcom', 'javelin-vector', 'phui-hovercard', ), 'bdaf4d04' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-request', ), 'bee502c8' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-workflow', 'javelin-quicksand', 'phabricator-phtize', 'phabricator-drag-and-drop-file-upload', 'phabricator-draggable-list', ), 'bf5374ef' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), 'bff6884b' => array( 'javelin-install', 'javelin-dom', ), - 'c5238acb' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-behavior-device', - 'javelin-scrollbar', - 'javelin-quicksand', - 'phabricator-keyboard-shortcut', - 'conpherence-thread-manager', - ), 'c587b80f' => array( 'javelin-install', ), 'c7ccd872' => array( 'phui-fontkit-css', ), - 'c8e57404' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-uri', - 'javelin-mask', - 'phabricator-drag-and-drop-file-upload', - ), 'c90a04fc' => array( 'javelin-dom', 'javelin-dynval', 'javelin-reactor', 'javelin-reactornode', 'javelin-install', 'javelin-util', ), 'c989ade3' => array( 'javelin-install', 'javelin-util', 'javelin-stratcom', ), 'ca3f91eb' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'phabricator-phtize', ), 'ccf1cbf8' => array( 'javelin-install', 'javelin-dom', 'javelin-stratcom', 'javelin-util', 'phabricator-notification-css', ), - 'cf86d16a' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-workflow', - 'phabricator-drag-and-drop-file-upload', - ), 'cfd23f37' => array( 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-typeahead', 'javelin-tokenizer', 'javelin-typeahead-preloaded-source', 'javelin-typeahead-ondemand-source', 'javelin-dom', 'javelin-stratcom', 'javelin-util', ), 'd0c516d5' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phuix-dropdown-menu', 'phuix-action-list-view', 'phuix-action-view', 'javelin-workflow', 'phuix-icon-view', ), 'd19198c8' => array( 'javelin-install', 'javelin-dom', 'javelin-util', 'javelin-dynval', 'javelin-reactor-dom', ), 'd254d646' => array( 'javelin-util', ), 'd4505101' => array( 'javelin-stratcom', 'javelin-install', 'javelin-uri', 'javelin-util', ), 'd4a14807' => array( 'javelin-install', 'javelin-dom', 'javelin-view', ), 'd4eecc63' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', ), 'd6a7e717' => array( 'multirow-row-manager', 'javelin-install', 'javelin-util', 'javelin-dom', 'javelin-stratcom', 'javelin-json', 'phabricator-prefab', ), 'd7a74243' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'd835b03a' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'phabricator-shaped-request', ), 'de2e896f' => array( 'javelin-behavior', 'javelin-dom', 'javelin-typeahead', 'javelin-typeahead-ondemand-source', 'javelin-dom', ), - 'df5e11d2' => array( - 'javelin-install', - ), 'e0ec7f2f' => array( 'javelin-behavior', 'javelin-dom', 'javelin-request', 'javelin-util', ), 'e10f8e18' => array( 'javelin-behavior', 'javelin-dom', 'phabricator-prefab', ), 'e15869a8' => array( 'javelin-install', 'javelin-dom', ), 'e1d25dfb' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'e1ff79b1' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', ), 'e292eaf4' => array( 'javelin-install', ), 'e2e0a072' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'e379b58e' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-vector', 'javelin-dom', 'javelin-uri', ), 'e4232876' => array( 'javelin-behavior', 'javelin-dom', 'javelin-vector', 'phui-chart-css', ), 'e4cc26b3' => array( 'javelin-behavior', 'javelin-dom', ), 'e5339c43' => array( 'javelin-behavior', 'javelin-dom', 'javelin-stratcom', 'javelin-uri', ), 'e5822781' => array( 'javelin-behavior', 'javelin-dom', 'javelin-json', 'javelin-workflow', 'javelin-magical-init', ), 'e6e25838' => array( 'javelin-install', ), 'e9581f08' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-workflow', 'javelin-dom', 'phabricator-draggable-list', ), 'edd1ba66' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-uri', 'phabricator-notification', ), 'edf8a145' => array( 'javelin-behavior', 'javelin-uri', ), 'efe49472' => array( 'javelin-install', 'javelin-util', ), 'f01586dc' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-workflow', 'javelin-json', ), 'f03e17be' => array( 'phui-theme-css', ), 'f2e58483' => array( 'javelin-behavior', 'javelin-dom', 'javelin-util', 'javelin-workflow', 'javelin-stratcom', 'conpherence-thread-manager', ), 'f411b6ae' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-util', 'javelin-dom', 'javelin-request', 'phabricator-keyboard-shortcut', ), 'f6555212' => array( 'javelin-install', 'javelin-reactornode', 'javelin-util', 'javelin-reactor', ), 'f7fc67ec' => array( 'javelin-install', 'javelin-typeahead', 'javelin-dom', 'javelin-request', 'javelin-typeahead-ondemand-source', 'javelin-util', ), 'f829edb3' => array( 'javelin-view', 'javelin-install', 'javelin-dom', ), 'f8ba29d7' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'javelin-mask', 'javelin-util', 'phabricator-busy', ), 'fb20ac8d' => array( 'javelin-behavior', 'javelin-aphlict', 'javelin-stratcom', 'javelin-request', 'javelin-uri', 'javelin-dom', 'javelin-json', 'javelin-router', 'javelin-util', 'javelin-leader', 'javelin-sound', 'phabricator-notification', ), 'fbe497e7' => array( 'javelin-behavior', 'javelin-util', 'javelin-stratcom', 'javelin-dom', 'javelin-vector', 'javelin-magical-init', 'javelin-request', 'javelin-history', 'javelin-workflow', 'javelin-mask', 'javelin-behavior-device', 'phabricator-keyboard-shortcut', ), 'fc91ab6c' => array( 'javelin-behavior', 'javelin-dom', 'phortune-credit-card-form', ), 'fe287620' => array( 'javelin-install', 'javelin-dom', 'javelin-view-visitor', 'javelin-util', ), 'fe7cb52a' => array( 'javelin-install', 'javelin-dom', 'javelin-util', 'javelin-stratcom', 'javelin-workflow', 'phabricator-draggable-list', 'javelin-workboard-column', ), 'fea0eb47' => array( 'javelin-install', ), ), 'packages' => array( 'conpherence.pkg.css' => array( 'conpherence-durable-column-view', 'conpherence-menu-css', 'conpherence-message-pane-css', 'conpherence-notification-css', 'conpherence-transaction-css', - 'conpherence-update-css', 'conpherence-participant-pane-css', 'conpherence-header-pane-css', ), 'conpherence.pkg.js' => array( - 'javelin-behavior-conpherence-drag-and-drop-photo', 'javelin-behavior-conpherence-menu', 'javelin-behavior-conpherence-participant-pane', 'javelin-behavior-conpherence-pontificate', 'javelin-behavior-toggle-widget', ), 'core.pkg.css' => array( 'phabricator-core-css', 'phabricator-zindex-css', 'phui-button-css', 'phui-theme-css', 'phabricator-standard-page-view', 'aphront-dialog-view-css', 'phui-form-view-css', 'aphront-panel-view-css', 'aphront-table-view-css', 'aphront-tokenizer-control-css', 'aphront-typeahead-control-css', 'aphront-list-filter-view-css', 'application-search-view-css', 'phabricator-remarkup-css', 'syntax-highlighting-css', 'syntax-default-css', 'phui-pager-css', 'aphront-tooltip-css', 'phabricator-flag-css', 'phui-info-view-css', 'phabricator-main-menu-view', 'phabricator-notification-css', 'phabricator-notification-menu-css', 'lightbox-attachment-css', 'phui-header-view-css', 'phabricator-nav-view-css', 'phui-basic-nav-view-css', 'phui-crumbs-view-css', 'phui-object-item-list-view-css', 'global-drag-and-drop-css', 'phui-spacing-css', 'phui-form-css', 'phui-icon-view-css', 'phui-profile-menu-css', 'phabricator-application-launch-view-css', 'phabricator-action-list-view-css', 'phui-property-list-view-css', 'phui-tag-view-css', 'phui-list-view-css', 'font-fontawesome', 'font-lato', 'font-aleo', 'phui-font-icon-base-css', 'phui-fontkit-css', 'phui-box-css', 'phui-object-box-css', 'phui-timeline-view-css', 'phui-two-column-view-css', 'phui-curtain-view-css', 'sprite-login-css', 'sprite-tokens-css', 'tokens-css', 'auth-css', 'phui-status-list-view-css', 'phui-feed-story-css', 'phabricator-feed-css', 'phabricator-dashboard-css', 'aphront-multi-column-view-css', ), 'core.pkg.js' => array( 'javelin-util', 'javelin-install', 'javelin-event', 'javelin-stratcom', 'javelin-behavior', 'javelin-resource', 'javelin-request', 'javelin-vector', 'javelin-dom', 'javelin-json', 'javelin-uri', 'javelin-workflow', 'javelin-mask', 'javelin-typeahead', 'javelin-typeahead-normalizer', 'javelin-typeahead-source', 'javelin-typeahead-preloaded-source', 'javelin-typeahead-ondemand-source', 'javelin-tokenizer', 'javelin-history', 'javelin-router', 'javelin-routable', 'javelin-behavior-aphront-basic-tokenizer', 'javelin-behavior-workflow', 'javelin-behavior-aphront-form-disable-on-submit', 'phabricator-keyboard-shortcut-manager', 'phabricator-keyboard-shortcut', 'javelin-behavior-phabricator-keyboard-shortcuts', 'javelin-behavior-refresh-csrf', 'javelin-behavior-phabricator-watch-anchor', 'javelin-behavior-phabricator-autofocus', 'phuix-dropdown-menu', 'phuix-action-list-view', 'phuix-action-view', 'phuix-icon-view', 'phabricator-phtize', 'javelin-behavior-phabricator-oncopy', 'phabricator-tooltip', 'javelin-behavior-phabricator-tooltips', 'phabricator-prefab', 'javelin-behavior-device', 'javelin-behavior-toggle-class', 'javelin-behavior-lightbox-attachments', 'phabricator-busy', 'javelin-aphlict', 'phabricator-notification', 'javelin-behavior-aphlict-listen', 'javelin-behavior-phabricator-search-typeahead', 'javelin-behavior-aphlict-dropdown', 'javelin-behavior-history-install', 'javelin-behavior-phabricator-gesture', 'javelin-behavior-phabricator-active-nav', 'javelin-behavior-phabricator-nav', 'javelin-behavior-phabricator-remarkup-assist', 'phabricator-textareautils', 'phabricator-file-upload', 'javelin-behavior-global-drag-and-drop', 'javelin-behavior-phabricator-reveal-content', 'phui-hovercard', 'javelin-behavior-phui-hovercards', 'javelin-color', 'javelin-fx', 'phabricator-draggable-list', 'javelin-behavior-phabricator-transaction-list', 'javelin-behavior-phabricator-show-older-transactions', 'javelin-behavior-phui-dropdown-menu', 'javelin-behavior-doorkeeper-tag', 'phabricator-title', 'javelin-leader', 'javelin-websocket', 'javelin-behavior-dashboard-async-panel', 'javelin-behavior-dashboard-tab-panel', 'javelin-quicksand', 'javelin-behavior-quicksand-blacklist', 'javelin-behavior-high-security-warning', 'javelin-behavior-read-only-warning', 'javelin-scrollbar', 'javelin-behavior-scrollbar', 'javelin-behavior-durable-column', 'conpherence-thread-manager', 'javelin-behavior-detect-timezone', 'javelin-behavior-setup-check-https', ), 'darkconsole.pkg.js' => array( 'javelin-behavior-dark-console', 'javelin-behavior-error-log', ), 'differential.pkg.css' => array( 'differential-core-view-css', 'differential-changeset-view-css', 'differential-revision-history-css', 'differential-revision-list-css', 'differential-table-of-contents-css', 'differential-revision-comment-css', 'differential-revision-add-comment-css', 'phabricator-object-selector-css', 'phabricator-content-source-view-css', 'inline-comment-summary-css', 'phui-inline-comment-view-css', 'phabricator-filetree-view-css', ), 'differential.pkg.js' => array( 'phabricator-drag-and-drop-file-upload', 'phabricator-shaped-request', 'javelin-behavior-differential-feedback-preview', 'javelin-behavior-differential-edit-inline-comments', 'javelin-behavior-differential-populate', 'javelin-behavior-differential-diff-radios', 'javelin-behavior-differential-comment-jump', 'javelin-behavior-differential-add-reviewers-and-ccs', 'javelin-behavior-differential-keyboard-navigation', 'javelin-behavior-aphront-drag-and-drop-textarea', 'javelin-behavior-phabricator-object-selector', 'javelin-behavior-repository-crossreference', 'javelin-behavior-load-blame', 'differential-inline-comment-editor', 'javelin-behavior-differential-dropdown-menus', 'javelin-behavior-differential-toggle-files', 'javelin-behavior-differential-user-select', 'javelin-behavior-aphront-more', 'changeset-view-manager', ), 'diffusion.pkg.css' => array( 'diffusion-icons-css', ), 'diffusion.pkg.js' => array( 'javelin-behavior-diffusion-pull-lastmodified', 'javelin-behavior-diffusion-commit-graph', 'javelin-behavior-audit-preview', ), 'maniphest.pkg.css' => array( 'maniphest-task-summary-css', ), 'maniphest.pkg.js' => array( 'javelin-behavior-maniphest-batch-selector', 'javelin-behavior-maniphest-subpriority-editor', 'javelin-behavior-maniphest-list-editor', ), ), ); diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php index a3a2a6132a..8e7d339902 100644 --- a/resources/celerity/packages.php +++ b/resources/celerity/packages.php @@ -1,228 +1,226 @@ array( 'javelin-util', 'javelin-install', 'javelin-event', 'javelin-stratcom', 'javelin-behavior', 'javelin-resource', 'javelin-request', 'javelin-vector', 'javelin-dom', 'javelin-json', 'javelin-uri', 'javelin-workflow', 'javelin-mask', 'javelin-typeahead', 'javelin-typeahead-normalizer', 'javelin-typeahead-source', 'javelin-typeahead-preloaded-source', 'javelin-typeahead-ondemand-source', 'javelin-tokenizer', 'javelin-history', 'javelin-router', 'javelin-routable', 'javelin-behavior-aphront-basic-tokenizer', 'javelin-behavior-workflow', 'javelin-behavior-aphront-form-disable-on-submit', 'phabricator-keyboard-shortcut-manager', 'phabricator-keyboard-shortcut', 'javelin-behavior-phabricator-keyboard-shortcuts', 'javelin-behavior-refresh-csrf', 'javelin-behavior-phabricator-watch-anchor', 'javelin-behavior-phabricator-autofocus', 'phuix-dropdown-menu', 'phuix-action-list-view', 'phuix-action-view', 'phuix-icon-view', 'phabricator-phtize', 'javelin-behavior-phabricator-oncopy', 'phabricator-tooltip', 'javelin-behavior-phabricator-tooltips', 'phabricator-prefab', 'javelin-behavior-device', 'javelin-behavior-toggle-class', 'javelin-behavior-lightbox-attachments', 'phabricator-busy', 'javelin-aphlict', 'phabricator-notification', 'javelin-behavior-aphlict-listen', 'javelin-behavior-phabricator-search-typeahead', 'javelin-behavior-aphlict-dropdown', 'javelin-behavior-history-install', 'javelin-behavior-phabricator-gesture', 'javelin-behavior-phabricator-active-nav', 'javelin-behavior-phabricator-nav', 'javelin-behavior-phabricator-remarkup-assist', 'phabricator-textareautils', 'phabricator-file-upload', 'javelin-behavior-global-drag-and-drop', 'javelin-behavior-phabricator-reveal-content', 'phui-hovercard', 'javelin-behavior-phui-hovercards', 'javelin-color', 'javelin-fx', 'phabricator-draggable-list', 'javelin-behavior-phabricator-transaction-list', 'javelin-behavior-phabricator-show-older-transactions', 'javelin-behavior-phui-dropdown-menu', 'javelin-behavior-doorkeeper-tag', 'phabricator-title', 'javelin-leader', 'javelin-websocket', 'javelin-behavior-dashboard-async-panel', 'javelin-behavior-dashboard-tab-panel', 'javelin-quicksand', 'javelin-behavior-quicksand-blacklist', 'javelin-behavior-high-security-warning', 'javelin-behavior-read-only-warning', 'javelin-scrollbar', 'javelin-behavior-scrollbar', 'javelin-behavior-durable-column', 'conpherence-thread-manager', 'javelin-behavior-detect-timezone', 'javelin-behavior-setup-check-https', ), 'core.pkg.css' => array( 'phabricator-core-css', 'phabricator-zindex-css', 'phui-button-css', 'phui-theme-css', 'phabricator-standard-page-view', 'aphront-dialog-view-css', 'phui-form-view-css', 'aphront-panel-view-css', 'aphront-table-view-css', 'aphront-tokenizer-control-css', 'aphront-typeahead-control-css', 'aphront-list-filter-view-css', 'application-search-view-css', 'phabricator-remarkup-css', 'syntax-highlighting-css', 'syntax-default-css', 'phui-pager-css', 'aphront-tooltip-css', 'phabricator-flag-css', 'phui-info-view-css', 'phabricator-main-menu-view', 'phabricator-notification-css', 'phabricator-notification-menu-css', 'lightbox-attachment-css', 'phui-header-view-css', 'phabricator-nav-view-css', 'phui-basic-nav-view-css', 'phui-crumbs-view-css', 'phui-object-item-list-view-css', 'global-drag-and-drop-css', 'phui-spacing-css', 'phui-form-css', 'phui-icon-view-css', 'phui-profile-menu-css', 'phabricator-application-launch-view-css', 'phabricator-action-list-view-css', 'phui-property-list-view-css', 'phui-tag-view-css', 'phui-list-view-css', 'font-fontawesome', 'font-lato', 'font-aleo', 'phui-font-icon-base-css', 'phui-fontkit-css', 'phui-box-css', 'phui-object-box-css', 'phui-timeline-view-css', 'phui-two-column-view-css', 'phui-curtain-view-css', 'sprite-login-css', 'sprite-tokens-css', 'tokens-css', 'auth-css', 'phui-status-list-view-css', 'phui-feed-story-css', 'phabricator-feed-css', 'phabricator-dashboard-css', 'aphront-multi-column-view-css', ), 'conpherence.pkg.css' => array( 'conpherence-durable-column-view', 'conpherence-menu-css', 'conpherence-message-pane-css', 'conpherence-notification-css', 'conpherence-transaction-css', - 'conpherence-update-css', 'conpherence-participant-pane-css', 'conpherence-header-pane-css', ), 'conpherence.pkg.js' => array( - 'javelin-behavior-conpherence-drag-and-drop-photo', 'javelin-behavior-conpherence-menu', 'javelin-behavior-conpherence-participant-pane', 'javelin-behavior-conpherence-pontificate', 'javelin-behavior-toggle-widget', ), 'differential.pkg.css' => array( 'differential-core-view-css', 'differential-changeset-view-css', 'differential-revision-history-css', 'differential-revision-list-css', 'differential-table-of-contents-css', 'differential-revision-comment-css', 'differential-revision-add-comment-css', 'phabricator-object-selector-css', 'phabricator-content-source-view-css', 'inline-comment-summary-css', 'phui-inline-comment-view-css', 'phabricator-filetree-view-css', ), 'differential.pkg.js' => array( 'phabricator-drag-and-drop-file-upload', 'phabricator-shaped-request', 'javelin-behavior-differential-feedback-preview', 'javelin-behavior-differential-edit-inline-comments', 'javelin-behavior-differential-populate', 'javelin-behavior-differential-diff-radios', 'javelin-behavior-differential-comment-jump', 'javelin-behavior-differential-add-reviewers-and-ccs', 'javelin-behavior-differential-keyboard-navigation', 'javelin-behavior-aphront-drag-and-drop-textarea', 'javelin-behavior-phabricator-object-selector', 'javelin-behavior-repository-crossreference', 'javelin-behavior-load-blame', 'differential-inline-comment-editor', 'javelin-behavior-differential-dropdown-menus', 'javelin-behavior-differential-toggle-files', 'javelin-behavior-differential-user-select', 'javelin-behavior-aphront-more', 'changeset-view-manager', ), 'diffusion.pkg.css' => array( 'diffusion-icons-css', ), 'diffusion.pkg.js' => array( 'javelin-behavior-diffusion-pull-lastmodified', 'javelin-behavior-diffusion-commit-graph', 'javelin-behavior-audit-preview', ), 'maniphest.pkg.css' => array( 'maniphest-task-summary-css', ), 'maniphest.pkg.js' => array( 'javelin-behavior-maniphest-batch-selector', 'javelin-behavior-maniphest-subpriority-editor', 'javelin-behavior-maniphest-list-editor', ), 'darkconsole.pkg.js' => array( 'javelin-behavior-dark-console', 'javelin-behavior-error-log', ), ); diff --git a/resources/sql/autopatches/20161011.conpherence.ngrams.php b/resources/sql/autopatches/20161011.conpherence.ngrams.php new file mode 100644 index 0000000000..457143f6c7 --- /dev/null +++ b/resources/sql/autopatches/20161011.conpherence.ngrams.php @@ -0,0 +1,11 @@ +getPHID(), + array( + 'force' => true, + )); +} diff --git a/resources/sql/autopatches/20161011.conpherence.ngrams.sql b/resources/sql/autopatches/20161011.conpherence.ngrams.sql new file mode 100644 index 0000000000..e06c1489f7 --- /dev/null +++ b/resources/sql/autopatches/20161011.conpherence.ngrams.sql @@ -0,0 +1,7 @@ +CREATE TABLE {$NAMESPACE}_conpherence.conpherence_threadtitle_ngrams ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectID INT UNSIGNED NOT NULL, + ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT}, + KEY `key_object` (objectID), + KEY `key_ngram` (ngram, objectID) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20161012.cal.01.import.sql b/resources/sql/autopatches/20161012.cal.01.import.sql new file mode 100644 index 0000000000..aff544f015 --- /dev/null +++ b/resources/sql/autopatches/20161012.cal.01.import.sql @@ -0,0 +1,15 @@ +CREATE TABLE {$NAMESPACE}_calendar.calendar_import ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + phid VARBINARY(64) NOT NULL, + name LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, + authorPHID VARBINARY(64) NOT NULL, + viewPolicy VARBINARY(64) NOT NULL, + editPolicy VARBINARY(64) NOT NULL, + engineType VARCHAR(64) NOT NULL, + parameters LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, + isDisabled BOOL NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + UNIQUE KEY `key_phid` (phid), + KEY `key_author` (authorPHID) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20161012.cal.02.importxaction.sql b/resources/sql/autopatches/20161012.cal.02.importxaction.sql new file mode 100644 index 0000000000..e17474ac0b --- /dev/null +++ b/resources/sql/autopatches/20161012.cal.02.importxaction.sql @@ -0,0 +1,19 @@ +CREATE TABLE {$NAMESPACE}_calendar.calendar_importtransaction ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + phid VARBINARY(64) NOT NULL, + authorPHID VARBINARY(64) NOT NULL, + objectPHID VARBINARY(64) NOT NULL, + viewPolicy VARBINARY(64) NOT NULL, + editPolicy VARBINARY(64) NOT NULL, + commentPHID VARBINARY(64) DEFAULT NULL, + commentVersion INT UNSIGNED NOT NULL, + transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL, + oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + UNIQUE KEY `key_phid` (`phid`), + KEY `key_object` (`objectPHID`) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20161012.cal.03.eventimport.sql b/resources/sql/autopatches/20161012.cal.03.eventimport.sql new file mode 100644 index 0000000000..968b40e00b --- /dev/null +++ b/resources/sql/autopatches/20161012.cal.03.eventimport.sql @@ -0,0 +1,11 @@ +ALTER TABLE {$NAMESPACE}_calendar.calendar_event + ADD importAuthorPHID VARBINARY(64); + +ALTER TABLE {$NAMESPACE}_calendar.calendar_event + ADD importSourcePHID VARBINARY(64); + +ALTER TABLE {$NAMESPACE}_calendar.calendar_event + ADD importUIDIndex BINARY(12); + +ALTER TABLE {$NAMESPACE}_calendar.calendar_event + ADD importUID LONGTEXT COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20161013.cal.01.importlog.sql b/resources/sql/autopatches/20161013.cal.01.importlog.sql new file mode 100644 index 0000000000..938f0c8d72 --- /dev/null +++ b/resources/sql/autopatches/20161013.cal.01.importlog.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_calendar.calendar_importlog ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + importPHID VARBINARY(64) NOT NULL, + parameters LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + KEY `key_import` (`importPHID`) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20161016.conpherence.imagephids.sql b/resources/sql/autopatches/20161016.conpherence.imagephids.sql new file mode 100644 index 0000000000..98ba1ef5ce --- /dev/null +++ b/resources/sql/autopatches/20161016.conpherence.imagephids.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_conpherence.conpherence_thread + DROP COLUMN imagePHIDs; diff --git a/scripts/ssh/ssh-auth.php b/scripts/ssh/ssh-auth.php index af6f7f7f43..b25905668b 100755 --- a/scripts/ssh/ssh-auth.php +++ b/scripts/ssh/ssh-auth.php @@ -1,77 +1,87 @@ #!/usr/bin/env php setViewer(PhabricatorUser::getOmnipotentUser()) - ->withIsActive(true) - ->execute(); - -if (!$keys) { - echo pht('No keys found.')."\n"; - exit(1); -} +$cache = PhabricatorCaches::getMutableCache(); +$authfile_key = PhabricatorAuthSSHKeyQuery::AUTHFILE_CACHEKEY; +$authfile = $cache->getKey($authfile_key); + +if ($authfile === null) { + $keys = id(new PhabricatorAuthSSHKeyQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withIsActive(true) + ->execute(); + + if (!$keys) { + echo pht('No keys found.')."\n"; + exit(1); + } -$bin = $root.'/bin/ssh-exec'; -foreach ($keys as $ssh_key) { - $key_argv = array(); - $object = $ssh_key->getObject(); - if ($object instanceof PhabricatorUser) { - $key_argv[] = '--phabricator-ssh-user'; - $key_argv[] = $object->getUsername(); - } else if ($object instanceof AlmanacDevice) { - if (!$ssh_key->getIsTrusted()) { - // If this key is not a trusted device key, don't allow SSH - // authentication. + $bin = $root.'/bin/ssh-exec'; + foreach ($keys as $ssh_key) { + $key_argv = array(); + $object = $ssh_key->getObject(); + if ($object instanceof PhabricatorUser) { + $key_argv[] = '--phabricator-ssh-user'; + $key_argv[] = $object->getUsername(); + } else if ($object instanceof AlmanacDevice) { + if (!$ssh_key->getIsTrusted()) { + // If this key is not a trusted device key, don't allow SSH + // authentication. + continue; + } + $key_argv[] = '--phabricator-ssh-device'; + $key_argv[] = $object->getName(); + } else { + // We don't know what sort of key this is; don't permit SSH auth. continue; } - $key_argv[] = '--phabricator-ssh-device'; - $key_argv[] = $object->getName(); - } else { - // We don't know what sort of key this is; don't permit SSH auth. - continue; - } - $key_argv[] = '--phabricator-ssh-key'; - $key_argv[] = $ssh_key->getID(); + $key_argv[] = '--phabricator-ssh-key'; + $key_argv[] = $ssh_key->getID(); - $cmd = csprintf('%s %Ls', $bin, $key_argv); + $cmd = csprintf('%s %Ls', $bin, $key_argv); - $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); - if (strlen($instance)) { - $cmd = csprintf('PHABRICATOR_INSTANCE=%s %C', $instance, $cmd); - } + $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); + if (strlen($instance)) { + $cmd = csprintf('PHABRICATOR_INSTANCE=%s %C', $instance, $cmd); + } - // This is additional escaping for the SSH 'command="..."' string. - $cmd = addcslashes($cmd, '"\\'); + // This is additional escaping for the SSH 'command="..."' string. + $cmd = addcslashes($cmd, '"\\'); - // Strip out newlines and other nonsense from the key type and key body. + // Strip out newlines and other nonsense from the key type and key body. - $type = $ssh_key->getKeyType(); - $type = preg_replace('@[\x00-\x20]+@', '', $type); - if (!strlen($type)) { - continue; - } + $type = $ssh_key->getKeyType(); + $type = preg_replace('@[\x00-\x20]+@', '', $type); + if (!strlen($type)) { + continue; + } - $key = $ssh_key->getKeyBody(); - $key = preg_replace('@[\x00-\x20]+@', '', $key); - if (!strlen($key)) { - continue; - } + $key = $ssh_key->getKeyBody(); + $key = preg_replace('@[\x00-\x20]+@', '', $key); + if (!strlen($key)) { + continue; + } + + $options = array( + 'command="'.$cmd.'"', + 'no-port-forwarding', + 'no-X11-forwarding', + 'no-agent-forwarding', + 'no-pty', + ); + $options = implode(',', $options); - $options = array( - 'command="'.$cmd.'"', - 'no-port-forwarding', - 'no-X11-forwarding', - 'no-agent-forwarding', - 'no-pty', - ); - $options = implode(',', $options); + $lines[] = $options.' '.$type.' '.$key."\n"; + } - $lines[] = $options.' '.$type.' '.$key."\n"; + $authfile = implode('', $lines); + $ttl = phutil_units('24 hours in seconds'); + $cache->setKey($authfile_key, $authfile, $ttl); } -echo implode('', $lines); +echo $authfile; exit(0); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 085e86c84b..eafb0acdd5 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,9677 +1,9806 @@ 2, 'class' => array( 'AlmanacAddress' => 'applications/almanac/util/AlmanacAddress.php', 'AlmanacBinding' => 'applications/almanac/storage/AlmanacBinding.php', 'AlmanacBindingDisableController' => 'applications/almanac/controller/AlmanacBindingDisableController.php', 'AlmanacBindingEditController' => 'applications/almanac/controller/AlmanacBindingEditController.php', 'AlmanacBindingEditor' => 'applications/almanac/editor/AlmanacBindingEditor.php', 'AlmanacBindingPHIDType' => 'applications/almanac/phid/AlmanacBindingPHIDType.php', 'AlmanacBindingPropertyEditEngine' => 'applications/almanac/editor/AlmanacBindingPropertyEditEngine.php', 'AlmanacBindingQuery' => 'applications/almanac/query/AlmanacBindingQuery.php', 'AlmanacBindingTableView' => 'applications/almanac/view/AlmanacBindingTableView.php', 'AlmanacBindingTransaction' => 'applications/almanac/storage/AlmanacBindingTransaction.php', 'AlmanacBindingTransactionQuery' => 'applications/almanac/query/AlmanacBindingTransactionQuery.php', 'AlmanacBindingViewController' => 'applications/almanac/controller/AlmanacBindingViewController.php', 'AlmanacBindingsSearchEngineAttachment' => 'applications/almanac/engineextension/AlmanacBindingsSearchEngineAttachment.php', 'AlmanacClusterDatabaseServiceType' => 'applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php', 'AlmanacClusterRepositoryServiceType' => 'applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php', 'AlmanacClusterServiceType' => 'applications/almanac/servicetype/AlmanacClusterServiceType.php', 'AlmanacConsoleController' => 'applications/almanac/controller/AlmanacConsoleController.php', 'AlmanacController' => 'applications/almanac/controller/AlmanacController.php', 'AlmanacCreateDevicesCapability' => 'applications/almanac/capability/AlmanacCreateDevicesCapability.php', 'AlmanacCreateNamespacesCapability' => 'applications/almanac/capability/AlmanacCreateNamespacesCapability.php', 'AlmanacCreateNetworksCapability' => 'applications/almanac/capability/AlmanacCreateNetworksCapability.php', 'AlmanacCreateServicesCapability' => 'applications/almanac/capability/AlmanacCreateServicesCapability.php', 'AlmanacCustomServiceType' => 'applications/almanac/servicetype/AlmanacCustomServiceType.php', 'AlmanacDAO' => 'applications/almanac/storage/AlmanacDAO.php', 'AlmanacDevice' => 'applications/almanac/storage/AlmanacDevice.php', 'AlmanacDeviceController' => 'applications/almanac/controller/AlmanacDeviceController.php', 'AlmanacDeviceEditController' => 'applications/almanac/controller/AlmanacDeviceEditController.php', 'AlmanacDeviceEditEngine' => 'applications/almanac/editor/AlmanacDeviceEditEngine.php', 'AlmanacDeviceEditor' => 'applications/almanac/editor/AlmanacDeviceEditor.php', 'AlmanacDeviceListController' => 'applications/almanac/controller/AlmanacDeviceListController.php', 'AlmanacDeviceNameNgrams' => 'applications/almanac/storage/AlmanacDeviceNameNgrams.php', 'AlmanacDevicePHIDType' => 'applications/almanac/phid/AlmanacDevicePHIDType.php', 'AlmanacDevicePropertyEditEngine' => 'applications/almanac/editor/AlmanacDevicePropertyEditEngine.php', 'AlmanacDeviceQuery' => 'applications/almanac/query/AlmanacDeviceQuery.php', 'AlmanacDeviceSearchConduitAPIMethod' => 'applications/almanac/conduit/AlmanacDeviceSearchConduitAPIMethod.php', 'AlmanacDeviceSearchEngine' => 'applications/almanac/query/AlmanacDeviceSearchEngine.php', 'AlmanacDeviceTransaction' => 'applications/almanac/storage/AlmanacDeviceTransaction.php', 'AlmanacDeviceTransactionQuery' => 'applications/almanac/query/AlmanacDeviceTransactionQuery.php', 'AlmanacDeviceViewController' => 'applications/almanac/controller/AlmanacDeviceViewController.php', 'AlmanacDrydockPoolServiceType' => 'applications/almanac/servicetype/AlmanacDrydockPoolServiceType.php', 'AlmanacEditor' => 'applications/almanac/editor/AlmanacEditor.php', 'AlmanacInterface' => 'applications/almanac/storage/AlmanacInterface.php', 'AlmanacInterfaceDatasource' => 'applications/almanac/typeahead/AlmanacInterfaceDatasource.php', 'AlmanacInterfaceDeleteController' => 'applications/almanac/controller/AlmanacInterfaceDeleteController.php', 'AlmanacInterfaceEditController' => 'applications/almanac/controller/AlmanacInterfaceEditController.php', 'AlmanacInterfacePHIDType' => 'applications/almanac/phid/AlmanacInterfacePHIDType.php', 'AlmanacInterfaceQuery' => 'applications/almanac/query/AlmanacInterfaceQuery.php', 'AlmanacInterfaceTableView' => 'applications/almanac/view/AlmanacInterfaceTableView.php', 'AlmanacKeys' => 'applications/almanac/util/AlmanacKeys.php', 'AlmanacManageClusterServicesCapability' => 'applications/almanac/capability/AlmanacManageClusterServicesCapability.php', 'AlmanacManagementRegisterWorkflow' => 'applications/almanac/management/AlmanacManagementRegisterWorkflow.php', 'AlmanacManagementTrustKeyWorkflow' => 'applications/almanac/management/AlmanacManagementTrustKeyWorkflow.php', 'AlmanacManagementUntrustKeyWorkflow' => 'applications/almanac/management/AlmanacManagementUntrustKeyWorkflow.php', 'AlmanacManagementWorkflow' => 'applications/almanac/management/AlmanacManagementWorkflow.php', 'AlmanacNames' => 'applications/almanac/util/AlmanacNames.php', 'AlmanacNamesTestCase' => 'applications/almanac/util/__tests__/AlmanacNamesTestCase.php', 'AlmanacNamespace' => 'applications/almanac/storage/AlmanacNamespace.php', 'AlmanacNamespaceController' => 'applications/almanac/controller/AlmanacNamespaceController.php', 'AlmanacNamespaceEditController' => 'applications/almanac/controller/AlmanacNamespaceEditController.php', 'AlmanacNamespaceEditEngine' => 'applications/almanac/editor/AlmanacNamespaceEditEngine.php', 'AlmanacNamespaceEditor' => 'applications/almanac/editor/AlmanacNamespaceEditor.php', 'AlmanacNamespaceListController' => 'applications/almanac/controller/AlmanacNamespaceListController.php', 'AlmanacNamespaceNameNgrams' => 'applications/almanac/storage/AlmanacNamespaceNameNgrams.php', 'AlmanacNamespacePHIDType' => 'applications/almanac/phid/AlmanacNamespacePHIDType.php', 'AlmanacNamespaceQuery' => 'applications/almanac/query/AlmanacNamespaceQuery.php', 'AlmanacNamespaceSearchEngine' => 'applications/almanac/query/AlmanacNamespaceSearchEngine.php', 'AlmanacNamespaceTransaction' => 'applications/almanac/storage/AlmanacNamespaceTransaction.php', 'AlmanacNamespaceTransactionQuery' => 'applications/almanac/query/AlmanacNamespaceTransactionQuery.php', 'AlmanacNamespaceViewController' => 'applications/almanac/controller/AlmanacNamespaceViewController.php', 'AlmanacNetwork' => 'applications/almanac/storage/AlmanacNetwork.php', 'AlmanacNetworkController' => 'applications/almanac/controller/AlmanacNetworkController.php', 'AlmanacNetworkEditController' => 'applications/almanac/controller/AlmanacNetworkEditController.php', 'AlmanacNetworkEditEngine' => 'applications/almanac/editor/AlmanacNetworkEditEngine.php', 'AlmanacNetworkEditor' => 'applications/almanac/editor/AlmanacNetworkEditor.php', 'AlmanacNetworkListController' => 'applications/almanac/controller/AlmanacNetworkListController.php', 'AlmanacNetworkNameNgrams' => 'applications/almanac/storage/AlmanacNetworkNameNgrams.php', 'AlmanacNetworkPHIDType' => 'applications/almanac/phid/AlmanacNetworkPHIDType.php', 'AlmanacNetworkQuery' => 'applications/almanac/query/AlmanacNetworkQuery.php', 'AlmanacNetworkSearchEngine' => 'applications/almanac/query/AlmanacNetworkSearchEngine.php', 'AlmanacNetworkTransaction' => 'applications/almanac/storage/AlmanacNetworkTransaction.php', 'AlmanacNetworkTransactionQuery' => 'applications/almanac/query/AlmanacNetworkTransactionQuery.php', 'AlmanacNetworkViewController' => 'applications/almanac/controller/AlmanacNetworkViewController.php', 'AlmanacPropertiesDestructionEngineExtension' => 'applications/almanac/engineextension/AlmanacPropertiesDestructionEngineExtension.php', 'AlmanacPropertiesSearchEngineAttachment' => 'applications/almanac/engineextension/AlmanacPropertiesSearchEngineAttachment.php', 'AlmanacProperty' => 'applications/almanac/storage/AlmanacProperty.php', 'AlmanacPropertyController' => 'applications/almanac/controller/AlmanacPropertyController.php', 'AlmanacPropertyDeleteController' => 'applications/almanac/controller/AlmanacPropertyDeleteController.php', 'AlmanacPropertyEditController' => 'applications/almanac/controller/AlmanacPropertyEditController.php', 'AlmanacPropertyEditEngine' => 'applications/almanac/editor/AlmanacPropertyEditEngine.php', 'AlmanacPropertyInterface' => 'applications/almanac/property/AlmanacPropertyInterface.php', 'AlmanacPropertyQuery' => 'applications/almanac/query/AlmanacPropertyQuery.php', 'AlmanacQuery' => 'applications/almanac/query/AlmanacQuery.php', 'AlmanacSchemaSpec' => 'applications/almanac/storage/AlmanacSchemaSpec.php', 'AlmanacSearchEngineAttachment' => 'applications/almanac/engineextension/AlmanacSearchEngineAttachment.php', 'AlmanacService' => 'applications/almanac/storage/AlmanacService.php', 'AlmanacServiceController' => 'applications/almanac/controller/AlmanacServiceController.php', 'AlmanacServiceDatasource' => 'applications/almanac/typeahead/AlmanacServiceDatasource.php', 'AlmanacServiceEditController' => 'applications/almanac/controller/AlmanacServiceEditController.php', 'AlmanacServiceEditEngine' => 'applications/almanac/editor/AlmanacServiceEditEngine.php', 'AlmanacServiceEditor' => 'applications/almanac/editor/AlmanacServiceEditor.php', 'AlmanacServiceListController' => 'applications/almanac/controller/AlmanacServiceListController.php', 'AlmanacServiceNameNgrams' => 'applications/almanac/storage/AlmanacServiceNameNgrams.php', 'AlmanacServicePHIDType' => 'applications/almanac/phid/AlmanacServicePHIDType.php', 'AlmanacServicePropertyEditEngine' => 'applications/almanac/editor/AlmanacServicePropertyEditEngine.php', 'AlmanacServiceQuery' => 'applications/almanac/query/AlmanacServiceQuery.php', 'AlmanacServiceSearchConduitAPIMethod' => 'applications/almanac/conduit/AlmanacServiceSearchConduitAPIMethod.php', 'AlmanacServiceSearchEngine' => 'applications/almanac/query/AlmanacServiceSearchEngine.php', 'AlmanacServiceTransaction' => 'applications/almanac/storage/AlmanacServiceTransaction.php', 'AlmanacServiceTransactionQuery' => 'applications/almanac/query/AlmanacServiceTransactionQuery.php', 'AlmanacServiceType' => 'applications/almanac/servicetype/AlmanacServiceType.php', 'AlmanacServiceTypeDatasource' => 'applications/almanac/typeahead/AlmanacServiceTypeDatasource.php', 'AlmanacServiceTypeTestCase' => 'applications/almanac/servicetype/__tests__/AlmanacServiceTypeTestCase.php', 'AlmanacServiceViewController' => 'applications/almanac/controller/AlmanacServiceViewController.php', 'AlmanacTransaction' => 'applications/almanac/storage/AlmanacTransaction.php', 'AphlictDropdownDataQuery' => 'applications/aphlict/query/AphlictDropdownDataQuery.php', 'Aphront304Response' => 'aphront/response/Aphront304Response.php', 'Aphront400Response' => 'aphront/response/Aphront400Response.php', 'Aphront403Response' => 'aphront/response/Aphront403Response.php', 'Aphront404Response' => 'aphront/response/Aphront404Response.php', 'AphrontAjaxResponse' => 'aphront/response/AphrontAjaxResponse.php', 'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php', 'AphrontBarView' => 'view/widget/bars/AphrontBarView.php', 'AphrontBoolHTTPParameterType' => 'aphront/httpparametertype/AphrontBoolHTTPParameterType.php', 'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php', 'AphrontController' => 'aphront/AphrontController.php', 'AphrontCursorPagerView' => 'view/control/AphrontCursorPagerView.php', 'AphrontDefaultApplicationConfiguration' => 'aphront/configuration/AphrontDefaultApplicationConfiguration.php', 'AphrontDialogResponse' => 'aphront/response/AphrontDialogResponse.php', 'AphrontDialogView' => 'view/AphrontDialogView.php', 'AphrontEpochHTTPParameterType' => 'aphront/httpparametertype/AphrontEpochHTTPParameterType.php', 'AphrontException' => 'aphront/exception/AphrontException.php', + 'AphrontFileHTTPParameterType' => 'aphront/httpparametertype/AphrontFileHTTPParameterType.php', 'AphrontFileResponse' => 'aphront/response/AphrontFileResponse.php', 'AphrontFormCheckboxControl' => 'view/form/control/AphrontFormCheckboxControl.php', 'AphrontFormControl' => 'view/form/control/AphrontFormControl.php', 'AphrontFormDateControl' => 'view/form/control/AphrontFormDateControl.php', 'AphrontFormDateControlValue' => 'view/form/control/AphrontFormDateControlValue.php', 'AphrontFormDividerControl' => 'view/form/control/AphrontFormDividerControl.php', 'AphrontFormFileControl' => 'view/form/control/AphrontFormFileControl.php', 'AphrontFormHandlesControl' => 'view/form/control/AphrontFormHandlesControl.php', 'AphrontFormMarkupControl' => 'view/form/control/AphrontFormMarkupControl.php', 'AphrontFormPasswordControl' => 'view/form/control/AphrontFormPasswordControl.php', 'AphrontFormPolicyControl' => 'view/form/control/AphrontFormPolicyControl.php', 'AphrontFormRadioButtonControl' => 'view/form/control/AphrontFormRadioButtonControl.php', 'AphrontFormRecaptchaControl' => 'view/form/control/AphrontFormRecaptchaControl.php', 'AphrontFormSelectControl' => 'view/form/control/AphrontFormSelectControl.php', 'AphrontFormStaticControl' => 'view/form/control/AphrontFormStaticControl.php', 'AphrontFormSubmitControl' => 'view/form/control/AphrontFormSubmitControl.php', 'AphrontFormTextAreaControl' => 'view/form/control/AphrontFormTextAreaControl.php', 'AphrontFormTextControl' => 'view/form/control/AphrontFormTextControl.php', 'AphrontFormTextWithSubmitControl' => 'view/form/control/AphrontFormTextWithSubmitControl.php', 'AphrontFormTokenizerControl' => 'view/form/control/AphrontFormTokenizerControl.php', 'AphrontFormTypeaheadControl' => 'view/form/control/AphrontFormTypeaheadControl.php', 'AphrontFormView' => 'view/form/AphrontFormView.php', 'AphrontGlyphBarView' => 'view/widget/bars/AphrontGlyphBarView.php', 'AphrontHTMLResponse' => 'aphront/response/AphrontHTMLResponse.php', 'AphrontHTTPParameterType' => 'aphront/httpparametertype/AphrontHTTPParameterType.php', 'AphrontHTTPProxyResponse' => 'aphront/response/AphrontHTTPProxyResponse.php', 'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php', 'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php', 'AphrontIntHTTPParameterType' => 'aphront/httpparametertype/AphrontIntHTTPParameterType.php', 'AphrontIsolatedDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontIsolatedDatabaseConnectionTestCase.php', 'AphrontIsolatedHTTPSink' => 'aphront/sink/AphrontIsolatedHTTPSink.php', 'AphrontJSONResponse' => 'aphront/response/AphrontJSONResponse.php', 'AphrontJavelinView' => 'view/AphrontJavelinView.php', 'AphrontKeyboardShortcutsAvailableView' => 'view/widget/AphrontKeyboardShortcutsAvailableView.php', 'AphrontListFilterView' => 'view/layout/AphrontListFilterView.php', 'AphrontListHTTPParameterType' => 'aphront/httpparametertype/AphrontListHTTPParameterType.php', 'AphrontMalformedRequestException' => 'aphront/exception/AphrontMalformedRequestException.php', 'AphrontMoreView' => 'view/layout/AphrontMoreView.php', 'AphrontMultiColumnView' => 'view/layout/AphrontMultiColumnView.php', 'AphrontMySQLDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontMySQLDatabaseConnectionTestCase.php', 'AphrontNullView' => 'view/AphrontNullView.php', 'AphrontPHIDHTTPParameterType' => 'aphront/httpparametertype/AphrontPHIDHTTPParameterType.php', 'AphrontPHIDListHTTPParameterType' => 'aphront/httpparametertype/AphrontPHIDListHTTPParameterType.php', 'AphrontPHPHTTPSink' => 'aphront/sink/AphrontPHPHTTPSink.php', 'AphrontPageView' => 'view/page/AphrontPageView.php', 'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php', 'AphrontProgressBarView' => 'view/widget/bars/AphrontProgressBarView.php', 'AphrontProjectListHTTPParameterType' => 'aphront/httpparametertype/AphrontProjectListHTTPParameterType.php', 'AphrontProxyResponse' => 'aphront/response/AphrontProxyResponse.php', 'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php', 'AphrontRedirectResponseTestCase' => 'aphront/response/__tests__/AphrontRedirectResponseTestCase.php', 'AphrontReloadResponse' => 'aphront/response/AphrontReloadResponse.php', 'AphrontRequest' => 'aphront/AphrontRequest.php', 'AphrontRequestExceptionHandler' => 'aphront/handler/AphrontRequestExceptionHandler.php', 'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php', 'AphrontResponse' => 'aphront/response/AphrontResponse.php', 'AphrontResponseProducerInterface' => 'aphront/interface/AphrontResponseProducerInterface.php', 'AphrontRoutingMap' => 'aphront/site/AphrontRoutingMap.php', 'AphrontRoutingResult' => 'aphront/site/AphrontRoutingResult.php', 'AphrontSelectHTTPParameterType' => 'aphront/httpparametertype/AphrontSelectHTTPParameterType.php', 'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php', 'AphrontSite' => 'aphront/site/AphrontSite.php', 'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php', 'AphrontStandaloneHTMLResponse' => 'aphront/response/AphrontStandaloneHTMLResponse.php', 'AphrontStringHTTPParameterType' => 'aphront/httpparametertype/AphrontStringHTTPParameterType.php', 'AphrontStringListHTTPParameterType' => 'aphront/httpparametertype/AphrontStringListHTTPParameterType.php', 'AphrontTableView' => 'view/control/AphrontTableView.php', 'AphrontTagView' => 'view/AphrontTagView.php', 'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php', 'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php', 'AphrontUnhandledExceptionResponse' => 'aphront/response/AphrontUnhandledExceptionResponse.php', 'AphrontUserListHTTPParameterType' => 'aphront/httpparametertype/AphrontUserListHTTPParameterType.php', 'AphrontView' => 'view/AphrontView.php', 'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php', 'ArcanistConduitAPIMethod' => 'applications/arcanist/conduit/ArcanistConduitAPIMethod.php', 'AuditConduitAPIMethod' => 'applications/audit/conduit/AuditConduitAPIMethod.php', 'AuditQueryConduitAPIMethod' => 'applications/audit/conduit/AuditQueryConduitAPIMethod.php', 'AuthManageProvidersCapability' => 'applications/auth/capability/AuthManageProvidersCapability.php', 'CalendarTimeUtil' => 'applications/calendar/util/CalendarTimeUtil.php', 'CalendarTimeUtilTestCase' => 'applications/calendar/__tests__/CalendarTimeUtilTestCase.php', 'CelerityAPI' => 'applications/celerity/CelerityAPI.php', 'CelerityDefaultPostprocessor' => 'applications/celerity/postprocessor/CelerityDefaultPostprocessor.php', 'CelerityHighContrastPostprocessor' => 'applications/celerity/postprocessor/CelerityHighContrastPostprocessor.php', 'CelerityLargeFontPostprocessor' => 'applications/celerity/postprocessor/CelerityLargeFontPostprocessor.php', 'CelerityManagementMapWorkflow' => 'applications/celerity/management/CelerityManagementMapWorkflow.php', 'CelerityManagementSyntaxWorkflow' => 'applications/celerity/management/CelerityManagementSyntaxWorkflow.php', 'CelerityManagementWorkflow' => 'applications/celerity/management/CelerityManagementWorkflow.php', 'CelerityPhabricatorResourceController' => 'applications/celerity/controller/CelerityPhabricatorResourceController.php', 'CelerityPhabricatorResources' => 'applications/celerity/resources/CelerityPhabricatorResources.php', 'CelerityPhysicalResources' => 'applications/celerity/resources/CelerityPhysicalResources.php', 'CelerityPhysicalResourcesTestCase' => 'applications/celerity/resources/__tests__/CelerityPhysicalResourcesTestCase.php', 'CelerityPostprocessor' => 'applications/celerity/postprocessor/CelerityPostprocessor.php', 'CelerityPostprocessorTestCase' => 'applications/celerity/__tests__/CelerityPostprocessorTestCase.php', 'CelerityResourceController' => 'applications/celerity/controller/CelerityResourceController.php', 'CelerityResourceGraph' => 'applications/celerity/CelerityResourceGraph.php', 'CelerityResourceMap' => 'applications/celerity/CelerityResourceMap.php', 'CelerityResourceMapGenerator' => 'applications/celerity/CelerityResourceMapGenerator.php', 'CelerityResourceTransformer' => 'applications/celerity/CelerityResourceTransformer.php', 'CelerityResourceTransformerTestCase' => 'applications/celerity/__tests__/CelerityResourceTransformerTestCase.php', 'CelerityResources' => 'applications/celerity/resources/CelerityResources.php', 'CelerityResourcesOnDisk' => 'applications/celerity/resources/CelerityResourcesOnDisk.php', 'CeleritySpriteGenerator' => 'applications/celerity/CeleritySpriteGenerator.php', 'CelerityStaticResourceResponse' => 'applications/celerity/CelerityStaticResourceResponse.php', 'ChatLogConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogConduitAPIMethod.php', 'ChatLogQueryConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php', 'ChatLogRecordConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php', 'ConduitAPIMethod' => 'applications/conduit/method/ConduitAPIMethod.php', 'ConduitAPIMethodTestCase' => 'applications/conduit/method/__tests__/ConduitAPIMethodTestCase.php', 'ConduitAPIRequest' => 'applications/conduit/protocol/ConduitAPIRequest.php', 'ConduitAPIResponse' => 'applications/conduit/protocol/ConduitAPIResponse.php', 'ConduitApplicationNotInstalledException' => 'applications/conduit/protocol/exception/ConduitApplicationNotInstalledException.php', 'ConduitBoolParameterType' => 'applications/conduit/parametertype/ConduitBoolParameterType.php', 'ConduitCall' => 'applications/conduit/call/ConduitCall.php', 'ConduitCallTestCase' => 'applications/conduit/call/__tests__/ConduitCallTestCase.php', 'ConduitColumnsParameterType' => 'applications/conduit/parametertype/ConduitColumnsParameterType.php', 'ConduitConnectConduitAPIMethod' => 'applications/conduit/method/ConduitConnectConduitAPIMethod.php', 'ConduitEpochParameterType' => 'applications/conduit/parametertype/ConduitEpochParameterType.php', 'ConduitException' => 'applications/conduit/protocol/exception/ConduitException.php', 'ConduitGetCapabilitiesConduitAPIMethod' => 'applications/conduit/method/ConduitGetCapabilitiesConduitAPIMethod.php', 'ConduitGetCertificateConduitAPIMethod' => 'applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php', 'ConduitIntListParameterType' => 'applications/conduit/parametertype/ConduitIntListParameterType.php', 'ConduitIntParameterType' => 'applications/conduit/parametertype/ConduitIntParameterType.php', 'ConduitListParameterType' => 'applications/conduit/parametertype/ConduitListParameterType.php', 'ConduitLogGarbageCollector' => 'applications/conduit/garbagecollector/ConduitLogGarbageCollector.php', 'ConduitMethodDoesNotExistException' => 'applications/conduit/protocol/exception/ConduitMethodDoesNotExistException.php', 'ConduitMethodNotFoundException' => 'applications/conduit/protocol/exception/ConduitMethodNotFoundException.php', 'ConduitPHIDListParameterType' => 'applications/conduit/parametertype/ConduitPHIDListParameterType.php', 'ConduitPHIDParameterType' => 'applications/conduit/parametertype/ConduitPHIDParameterType.php', 'ConduitParameterType' => 'applications/conduit/parametertype/ConduitParameterType.php', 'ConduitPingConduitAPIMethod' => 'applications/conduit/method/ConduitPingConduitAPIMethod.php', 'ConduitPointsParameterType' => 'applications/conduit/parametertype/ConduitPointsParameterType.php', 'ConduitProjectListParameterType' => 'applications/conduit/parametertype/ConduitProjectListParameterType.php', 'ConduitQueryConduitAPIMethod' => 'applications/conduit/method/ConduitQueryConduitAPIMethod.php', 'ConduitResultSearchEngineExtension' => 'applications/conduit/query/ConduitResultSearchEngineExtension.php', 'ConduitSSHWorkflow' => 'applications/conduit/ssh/ConduitSSHWorkflow.php', 'ConduitStringListParameterType' => 'applications/conduit/parametertype/ConduitStringListParameterType.php', 'ConduitStringParameterType' => 'applications/conduit/parametertype/ConduitStringParameterType.php', 'ConduitTokenGarbageCollector' => 'applications/conduit/garbagecollector/ConduitTokenGarbageCollector.php', 'ConduitUserListParameterType' => 'applications/conduit/parametertype/ConduitUserListParameterType.php', 'ConduitUserParameterType' => 'applications/conduit/parametertype/ConduitUserParameterType.php', 'ConduitWildParameterType' => 'applications/conduit/parametertype/ConduitWildParameterType.php', 'ConpherenceColumnViewController' => 'applications/conpherence/controller/ConpherenceColumnViewController.php', 'ConpherenceConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceConduitAPIMethod.php', 'ConpherenceConfigOptions' => 'applications/conpherence/config/ConpherenceConfigOptions.php', 'ConpherenceConstants' => 'applications/conpherence/constants/ConpherenceConstants.php', 'ConpherenceController' => 'applications/conpherence/controller/ConpherenceController.php', 'ConpherenceCreateThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php', 'ConpherenceDAO' => 'applications/conpherence/storage/ConpherenceDAO.php', 'ConpherenceDurableColumnView' => 'applications/conpherence/view/ConpherenceDurableColumnView.php', 'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php', - 'ConpherenceFormDragAndDropUploadControl' => 'applications/conpherence/view/ConpherenceFormDragAndDropUploadControl.php', 'ConpherenceFulltextQuery' => 'applications/conpherence/query/ConpherenceFulltextQuery.php', 'ConpherenceIndex' => 'applications/conpherence/storage/ConpherenceIndex.php', 'ConpherenceLayoutView' => 'applications/conpherence/view/ConpherenceLayoutView.php', 'ConpherenceListController' => 'applications/conpherence/controller/ConpherenceListController.php', 'ConpherenceMenuItemView' => 'applications/conpherence/view/ConpherenceMenuItemView.php', 'ConpherenceNewRoomController' => 'applications/conpherence/controller/ConpherenceNewRoomController.php', 'ConpherenceNotificationPanelController' => 'applications/conpherence/controller/ConpherenceNotificationPanelController.php', 'ConpherenceParticipant' => 'applications/conpherence/storage/ConpherenceParticipant.php', 'ConpherenceParticipantController' => 'applications/conpherence/controller/ConpherenceParticipantController.php', 'ConpherenceParticipantCountQuery' => 'applications/conpherence/query/ConpherenceParticipantCountQuery.php', 'ConpherenceParticipantQuery' => 'applications/conpherence/query/ConpherenceParticipantQuery.php', 'ConpherenceParticipantView' => 'applications/conpherence/view/ConpherenceParticipantView.php', 'ConpherenceParticipationStatus' => 'applications/conpherence/constants/ConpherenceParticipationStatus.php', 'ConpherenceQueryThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryThreadConduitAPIMethod.php', 'ConpherenceQueryTransactionConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php', 'ConpherenceReplyHandler' => 'applications/conpherence/mail/ConpherenceReplyHandler.php', 'ConpherenceRoomListController' => 'applications/conpherence/controller/ConpherenceRoomListController.php', 'ConpherenceRoomPictureController' => 'applications/conpherence/controller/ConpherenceRoomPictureController.php', 'ConpherenceRoomTestCase' => 'applications/conpherence/__tests__/ConpherenceRoomTestCase.php', 'ConpherenceSchemaSpec' => 'applications/conpherence/storage/ConpherenceSchemaSpec.php', 'ConpherenceTestCase' => 'applications/conpherence/__tests__/ConpherenceTestCase.php', 'ConpherenceThread' => 'applications/conpherence/storage/ConpherenceThread.php', + 'ConpherenceThreadDatasource' => 'applications/conpherence/typeahead/ConpherenceThreadDatasource.php', 'ConpherenceThreadIndexEngineExtension' => 'applications/conpherence/engineextension/ConpherenceThreadIndexEngineExtension.php', 'ConpherenceThreadListView' => 'applications/conpherence/view/ConpherenceThreadListView.php', 'ConpherenceThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceThreadMailReceiver.php', 'ConpherenceThreadMembersPolicyRule' => 'applications/conpherence/policyrule/ConpherenceThreadMembersPolicyRule.php', 'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php', 'ConpherenceThreadRemarkupRule' => 'applications/conpherence/remarkup/ConpherenceThreadRemarkupRule.php', + 'ConpherenceThreadSearchController' => 'applications/conpherence/controller/ConpherenceThreadSearchController.php', 'ConpherenceThreadSearchEngine' => 'applications/conpherence/query/ConpherenceThreadSearchEngine.php', + 'ConpherenceThreadTitleNgrams' => 'applications/conpherence/storage/ConpherenceThreadTitleNgrams.php', 'ConpherenceTransaction' => 'applications/conpherence/storage/ConpherenceTransaction.php', 'ConpherenceTransactionComment' => 'applications/conpherence/storage/ConpherenceTransactionComment.php', 'ConpherenceTransactionQuery' => 'applications/conpherence/query/ConpherenceTransactionQuery.php', 'ConpherenceTransactionRenderer' => 'applications/conpherence/ConpherenceTransactionRenderer.php', 'ConpherenceTransactionView' => 'applications/conpherence/view/ConpherenceTransactionView.php', 'ConpherenceUpdateActions' => 'applications/conpherence/constants/ConpherenceUpdateActions.php', 'ConpherenceUpdateController' => 'applications/conpherence/controller/ConpherenceUpdateController.php', 'ConpherenceUpdateThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php', 'ConpherenceViewController' => 'applications/conpherence/controller/ConpherenceViewController.php', 'DarkConsoleController' => 'applications/console/controller/DarkConsoleController.php', 'DarkConsoleCore' => 'applications/console/core/DarkConsoleCore.php', 'DarkConsoleDataController' => 'applications/console/controller/DarkConsoleDataController.php', 'DarkConsoleErrorLogPlugin' => 'applications/console/plugin/DarkConsoleErrorLogPlugin.php', 'DarkConsoleErrorLogPluginAPI' => 'applications/console/plugin/errorlog/DarkConsoleErrorLogPluginAPI.php', 'DarkConsoleEventPlugin' => 'applications/console/plugin/DarkConsoleEventPlugin.php', 'DarkConsoleEventPluginAPI' => 'applications/console/plugin/event/DarkConsoleEventPluginAPI.php', 'DarkConsolePlugin' => 'applications/console/plugin/DarkConsolePlugin.php', 'DarkConsoleRequestPlugin' => 'applications/console/plugin/DarkConsoleRequestPlugin.php', 'DarkConsoleServicesPlugin' => 'applications/console/plugin/DarkConsoleServicesPlugin.php', 'DarkConsoleStartupPlugin' => 'applications/console/plugin/DarkConsoleStartupPlugin.php', 'DarkConsoleXHProfPlugin' => 'applications/console/plugin/DarkConsoleXHProfPlugin.php', 'DarkConsoleXHProfPluginAPI' => 'applications/console/plugin/xhprof/DarkConsoleXHProfPluginAPI.php', 'DatabaseConfigurationProvider' => 'infrastructure/storage/configuration/DatabaseConfigurationProvider.php', 'DefaultDatabaseConfigurationProvider' => 'infrastructure/storage/configuration/DefaultDatabaseConfigurationProvider.php', 'DifferentialAction' => 'applications/differential/constants/DifferentialAction.php', 'DifferentialActionEmailCommand' => 'applications/differential/command/DifferentialActionEmailCommand.php', 'DifferentialAddCommentView' => 'applications/differential/view/DifferentialAddCommentView.php', 'DifferentialAdjustmentMapTestCase' => 'applications/differential/storage/__tests__/DifferentialAdjustmentMapTestCase.php', 'DifferentialAffectedPath' => 'applications/differential/storage/DifferentialAffectedPath.php', 'DifferentialApplyPatchField' => 'applications/differential/customfield/DifferentialApplyPatchField.php', 'DifferentialAsanaRepresentationField' => 'applications/differential/customfield/DifferentialAsanaRepresentationField.php', 'DifferentialAuditorsField' => 'applications/differential/customfield/DifferentialAuditorsField.php', 'DifferentialAuthorField' => 'applications/differential/customfield/DifferentialAuthorField.php', 'DifferentialBlameRevisionField' => 'applications/differential/customfield/DifferentialBlameRevisionField.php', 'DifferentialBlockHeraldAction' => 'applications/differential/herald/DifferentialBlockHeraldAction.php', 'DifferentialBlockingReviewerDatasource' => 'applications/differential/typeahead/DifferentialBlockingReviewerDatasource.php', 'DifferentialBranchField' => 'applications/differential/customfield/DifferentialBranchField.php', 'DifferentialChangeDetailMailView' => 'applications/differential/mail/DifferentialChangeDetailMailView.php', 'DifferentialChangeHeraldFieldGroup' => 'applications/differential/herald/DifferentialChangeHeraldFieldGroup.php', 'DifferentialChangeType' => 'applications/differential/constants/DifferentialChangeType.php', 'DifferentialChangesSinceLastUpdateField' => 'applications/differential/customfield/DifferentialChangesSinceLastUpdateField.php', 'DifferentialChangeset' => 'applications/differential/storage/DifferentialChangeset.php', 'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php', 'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php', 'DifferentialChangesetHTMLRenderer' => 'applications/differential/render/DifferentialChangesetHTMLRenderer.php', 'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php', 'DifferentialChangesetOneUpMailRenderer' => 'applications/differential/render/DifferentialChangesetOneUpMailRenderer.php', 'DifferentialChangesetOneUpRenderer' => 'applications/differential/render/DifferentialChangesetOneUpRenderer.php', 'DifferentialChangesetOneUpTestRenderer' => 'applications/differential/render/DifferentialChangesetOneUpTestRenderer.php', 'DifferentialChangesetParser' => 'applications/differential/parser/DifferentialChangesetParser.php', 'DifferentialChangesetParserTestCase' => 'applications/differential/parser/__tests__/DifferentialChangesetParserTestCase.php', 'DifferentialChangesetQuery' => 'applications/differential/query/DifferentialChangesetQuery.php', 'DifferentialChangesetRenderer' => 'applications/differential/render/DifferentialChangesetRenderer.php', 'DifferentialChangesetTestRenderer' => 'applications/differential/render/DifferentialChangesetTestRenderer.php', 'DifferentialChangesetTwoUpRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpRenderer.php', 'DifferentialChangesetTwoUpTestRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpTestRenderer.php', 'DifferentialChangesetViewController' => 'applications/differential/controller/DifferentialChangesetViewController.php', 'DifferentialChildRevisionsField' => 'applications/differential/customfield/DifferentialChildRevisionsField.php', 'DifferentialCloseConduitAPIMethod' => 'applications/differential/conduit/DifferentialCloseConduitAPIMethod.php', 'DifferentialCommentPreviewController' => 'applications/differential/controller/DifferentialCommentPreviewController.php', 'DifferentialCommentSaveController' => 'applications/differential/controller/DifferentialCommentSaveController.php', 'DifferentialCommitMessageParser' => 'applications/differential/parser/DifferentialCommitMessageParser.php', 'DifferentialCommitMessageParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCommitMessageParserTestCase.php', 'DifferentialCommitsField' => 'applications/differential/customfield/DifferentialCommitsField.php', 'DifferentialConduitAPIMethod' => 'applications/differential/conduit/DifferentialConduitAPIMethod.php', 'DifferentialConflictsField' => 'applications/differential/customfield/DifferentialConflictsField.php', 'DifferentialController' => 'applications/differential/controller/DifferentialController.php', 'DifferentialCoreCustomField' => 'applications/differential/customfield/DifferentialCoreCustomField.php', 'DifferentialCreateCommentConduitAPIMethod' => 'applications/differential/conduit/DifferentialCreateCommentConduitAPIMethod.php', 'DifferentialCreateDiffConduitAPIMethod' => 'applications/differential/conduit/DifferentialCreateDiffConduitAPIMethod.php', 'DifferentialCreateInlineConduitAPIMethod' => 'applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php', 'DifferentialCreateMailReceiver' => 'applications/differential/mail/DifferentialCreateMailReceiver.php', 'DifferentialCreateRawDiffConduitAPIMethod' => 'applications/differential/conduit/DifferentialCreateRawDiffConduitAPIMethod.php', 'DifferentialCreateRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialCreateRevisionConduitAPIMethod.php', 'DifferentialCustomField' => 'applications/differential/customfield/DifferentialCustomField.php', 'DifferentialCustomFieldDependsOnParser' => 'applications/differential/parser/DifferentialCustomFieldDependsOnParser.php', 'DifferentialCustomFieldDependsOnParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCustomFieldDependsOnParserTestCase.php', 'DifferentialCustomFieldNumericIndex' => 'applications/differential/storage/DifferentialCustomFieldNumericIndex.php', 'DifferentialCustomFieldRevertsParser' => 'applications/differential/parser/DifferentialCustomFieldRevertsParser.php', 'DifferentialCustomFieldRevertsParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCustomFieldRevertsParserTestCase.php', 'DifferentialCustomFieldStorage' => 'applications/differential/storage/DifferentialCustomFieldStorage.php', 'DifferentialCustomFieldStringIndex' => 'applications/differential/storage/DifferentialCustomFieldStringIndex.php', 'DifferentialDAO' => 'applications/differential/storage/DifferentialDAO.php', 'DifferentialDefaultViewCapability' => 'applications/differential/capability/DifferentialDefaultViewCapability.php', 'DifferentialDiff' => 'applications/differential/storage/DifferentialDiff.php', 'DifferentialDiffAffectedFilesHeraldField' => 'applications/differential/herald/DifferentialDiffAffectedFilesHeraldField.php', 'DifferentialDiffAuthorHeraldField' => 'applications/differential/herald/DifferentialDiffAuthorHeraldField.php', 'DifferentialDiffAuthorProjectsHeraldField' => 'applications/differential/herald/DifferentialDiffAuthorProjectsHeraldField.php', 'DifferentialDiffContentAddedHeraldField' => 'applications/differential/herald/DifferentialDiffContentAddedHeraldField.php', 'DifferentialDiffContentHeraldField' => 'applications/differential/herald/DifferentialDiffContentHeraldField.php', 'DifferentialDiffContentRemovedHeraldField' => 'applications/differential/herald/DifferentialDiffContentRemovedHeraldField.php', 'DifferentialDiffCreateController' => 'applications/differential/controller/DifferentialDiffCreateController.php', 'DifferentialDiffEditor' => 'applications/differential/editor/DifferentialDiffEditor.php', 'DifferentialDiffExtractionEngine' => 'applications/differential/engine/DifferentialDiffExtractionEngine.php', 'DifferentialDiffHeraldField' => 'applications/differential/herald/DifferentialDiffHeraldField.php', 'DifferentialDiffHeraldFieldGroup' => 'applications/differential/herald/DifferentialDiffHeraldFieldGroup.php', 'DifferentialDiffInlineCommentQuery' => 'applications/differential/query/DifferentialDiffInlineCommentQuery.php', 'DifferentialDiffPHIDType' => 'applications/differential/phid/DifferentialDiffPHIDType.php', 'DifferentialDiffProperty' => 'applications/differential/storage/DifferentialDiffProperty.php', 'DifferentialDiffQuery' => 'applications/differential/query/DifferentialDiffQuery.php', 'DifferentialDiffRepositoryHeraldField' => 'applications/differential/herald/DifferentialDiffRepositoryHeraldField.php', 'DifferentialDiffRepositoryProjectsHeraldField' => 'applications/differential/herald/DifferentialDiffRepositoryProjectsHeraldField.php', 'DifferentialDiffTestCase' => 'applications/differential/storage/__tests__/DifferentialDiffTestCase.php', 'DifferentialDiffTransaction' => 'applications/differential/storage/DifferentialDiffTransaction.php', 'DifferentialDiffTransactionQuery' => 'applications/differential/query/DifferentialDiffTransactionQuery.php', 'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php', 'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php', 'DifferentialDraft' => 'applications/differential/storage/DifferentialDraft.php', 'DifferentialEditPolicyField' => 'applications/differential/customfield/DifferentialEditPolicyField.php', 'DifferentialExactUserFunctionDatasource' => 'applications/differential/typeahead/DifferentialExactUserFunctionDatasource.php', 'DifferentialFieldParseException' => 'applications/differential/exception/DifferentialFieldParseException.php', 'DifferentialFieldValidationException' => 'applications/differential/exception/DifferentialFieldValidationException.php', 'DifferentialFindConduitAPIMethod' => 'applications/differential/conduit/DifferentialFindConduitAPIMethod.php', 'DifferentialGetAllDiffsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetAllDiffsConduitAPIMethod.php', 'DifferentialGetCommitMessageConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php', 'DifferentialGetCommitPathsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetCommitPathsConduitAPIMethod.php', 'DifferentialGetDiffConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetDiffConduitAPIMethod.php', 'DifferentialGetRawDiffConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRawDiffConduitAPIMethod.php', 'DifferentialGetRevisionCommentsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php', 'DifferentialGetRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php', 'DifferentialGetWorkingCopy' => 'applications/differential/DifferentialGetWorkingCopy.php', 'DifferentialGitHubLandingStrategy' => 'applications/differential/landing/DifferentialGitHubLandingStrategy.php', 'DifferentialGitSVNIDField' => 'applications/differential/customfield/DifferentialGitSVNIDField.php', 'DifferentialHarbormasterField' => 'applications/differential/customfield/DifferentialHarbormasterField.php', 'DifferentialHiddenComment' => 'applications/differential/storage/DifferentialHiddenComment.php', 'DifferentialHostField' => 'applications/differential/customfield/DifferentialHostField.php', 'DifferentialHostedGitLandingStrategy' => 'applications/differential/landing/DifferentialHostedGitLandingStrategy.php', 'DifferentialHostedMercurialLandingStrategy' => 'applications/differential/landing/DifferentialHostedMercurialLandingStrategy.php', 'DifferentialHovercardEngineExtension' => 'applications/differential/engineextension/DifferentialHovercardEngineExtension.php', 'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php', 'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php', 'DifferentialHunkParserTestCase' => 'applications/differential/parser/__tests__/DifferentialHunkParserTestCase.php', 'DifferentialHunkQuery' => 'applications/differential/query/DifferentialHunkQuery.php', 'DifferentialHunkTestCase' => 'applications/differential/storage/__tests__/DifferentialHunkTestCase.php', 'DifferentialInlineComment' => 'applications/differential/storage/DifferentialInlineComment.php', 'DifferentialInlineCommentEditController' => 'applications/differential/controller/DifferentialInlineCommentEditController.php', 'DifferentialInlineCommentMailView' => 'applications/differential/mail/DifferentialInlineCommentMailView.php', 'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/DifferentialInlineCommentPreviewController.php', 'DifferentialInlineCommentQuery' => 'applications/differential/query/DifferentialInlineCommentQuery.php', 'DifferentialJIRAIssuesField' => 'applications/differential/customfield/DifferentialJIRAIssuesField.php', 'DifferentialLandingActionMenuEventListener' => 'applications/differential/landing/DifferentialLandingActionMenuEventListener.php', 'DifferentialLandingStrategy' => 'applications/differential/landing/DifferentialLandingStrategy.php', 'DifferentialLegacyHunk' => 'applications/differential/storage/DifferentialLegacyHunk.php', 'DifferentialLineAdjustmentMap' => 'applications/differential/parser/DifferentialLineAdjustmentMap.php', 'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php', 'DifferentialLintStatus' => 'applications/differential/constants/DifferentialLintStatus.php', 'DifferentialLocalCommitsView' => 'applications/differential/view/DifferentialLocalCommitsView.php', 'DifferentialMailView' => 'applications/differential/mail/DifferentialMailView.php', 'DifferentialManiphestTasksField' => 'applications/differential/customfield/DifferentialManiphestTasksField.php', 'DifferentialModernHunk' => 'applications/differential/storage/DifferentialModernHunk.php', 'DifferentialNextStepField' => 'applications/differential/customfield/DifferentialNextStepField.php', 'DifferentialParentRevisionsField' => 'applications/differential/customfield/DifferentialParentRevisionsField.php', 'DifferentialParseCacheGarbageCollector' => 'applications/differential/garbagecollector/DifferentialParseCacheGarbageCollector.php', 'DifferentialParseCommitMessageConduitAPIMethod' => 'applications/differential/conduit/DifferentialParseCommitMessageConduitAPIMethod.php', 'DifferentialParseRenderTestCase' => 'applications/differential/__tests__/DifferentialParseRenderTestCase.php', 'DifferentialPathField' => 'applications/differential/customfield/DifferentialPathField.php', 'DifferentialProjectReviewersField' => 'applications/differential/customfield/DifferentialProjectReviewersField.php', 'DifferentialProjectsField' => 'applications/differential/customfield/DifferentialProjectsField.php', 'DifferentialQueryConduitAPIMethod' => 'applications/differential/conduit/DifferentialQueryConduitAPIMethod.php', 'DifferentialQueryDiffsConduitAPIMethod' => 'applications/differential/conduit/DifferentialQueryDiffsConduitAPIMethod.php', 'DifferentialRawDiffRenderer' => 'applications/differential/render/DifferentialRawDiffRenderer.php', 'DifferentialReleephRequestFieldSpecification' => 'applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php', 'DifferentialRemarkupRule' => 'applications/differential/remarkup/DifferentialRemarkupRule.php', 'DifferentialReplyHandler' => 'applications/differential/mail/DifferentialReplyHandler.php', 'DifferentialRepositoryDatasource' => 'applications/differential/typeahead/DifferentialRepositoryDatasource.php', 'DifferentialRepositoryField' => 'applications/differential/customfield/DifferentialRepositoryField.php', 'DifferentialRepositoryLookup' => 'applications/differential/query/DifferentialRepositoryLookup.php', 'DifferentialRequiredSignaturesField' => 'applications/differential/customfield/DifferentialRequiredSignaturesField.php', 'DifferentialResponsibleDatasource' => 'applications/differential/typeahead/DifferentialResponsibleDatasource.php', 'DifferentialResponsibleUserDatasource' => 'applications/differential/typeahead/DifferentialResponsibleUserDatasource.php', 'DifferentialResponsibleViewerFunctionDatasource' => 'applications/differential/typeahead/DifferentialResponsibleViewerFunctionDatasource.php', 'DifferentialRevertPlanField' => 'applications/differential/customfield/DifferentialRevertPlanField.php', 'DifferentialReviewedByField' => 'applications/differential/customfield/DifferentialReviewedByField.php', 'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php', 'DifferentialReviewerDatasource' => 'applications/differential/typeahead/DifferentialReviewerDatasource.php', 'DifferentialReviewerForRevisionEdgeType' => 'applications/differential/edge/DifferentialReviewerForRevisionEdgeType.php', 'DifferentialReviewerStatus' => 'applications/differential/constants/DifferentialReviewerStatus.php', 'DifferentialReviewersAddBlockingReviewersHeraldAction' => 'applications/differential/herald/DifferentialReviewersAddBlockingReviewersHeraldAction.php', 'DifferentialReviewersAddBlockingSelfHeraldAction' => 'applications/differential/herald/DifferentialReviewersAddBlockingSelfHeraldAction.php', 'DifferentialReviewersAddReviewersHeraldAction' => 'applications/differential/herald/DifferentialReviewersAddReviewersHeraldAction.php', 'DifferentialReviewersAddSelfHeraldAction' => 'applications/differential/herald/DifferentialReviewersAddSelfHeraldAction.php', 'DifferentialReviewersField' => 'applications/differential/customfield/DifferentialReviewersField.php', 'DifferentialReviewersHeraldAction' => 'applications/differential/herald/DifferentialReviewersHeraldAction.php', 'DifferentialReviewersView' => 'applications/differential/view/DifferentialReviewersView.php', 'DifferentialRevision' => 'applications/differential/storage/DifferentialRevision.php', 'DifferentialRevisionAffectedFilesHeraldField' => 'applications/differential/herald/DifferentialRevisionAffectedFilesHeraldField.php', 'DifferentialRevisionAuthorHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorHeraldField.php', 'DifferentialRevisionAuthorProjectsHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorProjectsHeraldField.php', 'DifferentialRevisionCloseDetailsController' => 'applications/differential/controller/DifferentialRevisionCloseDetailsController.php', 'DifferentialRevisionContentAddedHeraldField' => 'applications/differential/herald/DifferentialRevisionContentAddedHeraldField.php', 'DifferentialRevisionContentHeraldField' => 'applications/differential/herald/DifferentialRevisionContentHeraldField.php', 'DifferentialRevisionContentRemovedHeraldField' => 'applications/differential/herald/DifferentialRevisionContentRemovedHeraldField.php', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/DifferentialRevisionControlSystem.php', 'DifferentialRevisionDependedOnByRevisionEdgeType' => 'applications/differential/edge/DifferentialRevisionDependedOnByRevisionEdgeType.php', 'DifferentialRevisionDependsOnRevisionEdgeType' => 'applications/differential/edge/DifferentialRevisionDependsOnRevisionEdgeType.php', 'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php', 'DifferentialRevisionFulltextEngine' => 'applications/differential/search/DifferentialRevisionFulltextEngine.php', 'DifferentialRevisionGraph' => 'infrastructure/graph/DifferentialRevisionGraph.php', 'DifferentialRevisionHasChildRelationship' => 'applications/differential/relationships/DifferentialRevisionHasChildRelationship.php', 'DifferentialRevisionHasCommitEdgeType' => 'applications/differential/edge/DifferentialRevisionHasCommitEdgeType.php', 'DifferentialRevisionHasCommitRelationship' => 'applications/differential/relationships/DifferentialRevisionHasCommitRelationship.php', 'DifferentialRevisionHasParentRelationship' => 'applications/differential/relationships/DifferentialRevisionHasParentRelationship.php', 'DifferentialRevisionHasReviewerEdgeType' => 'applications/differential/edge/DifferentialRevisionHasReviewerEdgeType.php', 'DifferentialRevisionHasTaskEdgeType' => 'applications/differential/edge/DifferentialRevisionHasTaskEdgeType.php', 'DifferentialRevisionHasTaskRelationship' => 'applications/differential/relationships/DifferentialRevisionHasTaskRelationship.php', 'DifferentialRevisionHeraldField' => 'applications/differential/herald/DifferentialRevisionHeraldField.php', 'DifferentialRevisionHeraldFieldGroup' => 'applications/differential/herald/DifferentialRevisionHeraldFieldGroup.php', 'DifferentialRevisionIDField' => 'applications/differential/customfield/DifferentialRevisionIDField.php', 'DifferentialRevisionLandController' => 'applications/differential/controller/DifferentialRevisionLandController.php', 'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php', 'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php', 'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php', 'DifferentialRevisionOperationController' => 'applications/differential/controller/DifferentialRevisionOperationController.php', 'DifferentialRevisionPHIDType' => 'applications/differential/phid/DifferentialRevisionPHIDType.php', 'DifferentialRevisionPackageHeraldField' => 'applications/differential/herald/DifferentialRevisionPackageHeraldField.php', 'DifferentialRevisionPackageOwnerHeraldField' => 'applications/differential/herald/DifferentialRevisionPackageOwnerHeraldField.php', 'DifferentialRevisionQuery' => 'applications/differential/query/DifferentialRevisionQuery.php', 'DifferentialRevisionRelationship' => 'applications/differential/relationships/DifferentialRevisionRelationship.php', 'DifferentialRevisionRelationshipSource' => 'applications/search/relationship/DifferentialRevisionRelationshipSource.php', 'DifferentialRevisionRepositoryHeraldField' => 'applications/differential/herald/DifferentialRevisionRepositoryHeraldField.php', 'DifferentialRevisionRepositoryProjectsHeraldField' => 'applications/differential/herald/DifferentialRevisionRepositoryProjectsHeraldField.php', 'DifferentialRevisionRequiredActionResultBucket' => 'applications/differential/query/DifferentialRevisionRequiredActionResultBucket.php', 'DifferentialRevisionResultBucket' => 'applications/differential/query/DifferentialRevisionResultBucket.php', 'DifferentialRevisionReviewersHeraldField' => 'applications/differential/herald/DifferentialRevisionReviewersHeraldField.php', 'DifferentialRevisionSearchConduitAPIMethod' => 'applications/differential/conduit/DifferentialRevisionSearchConduitAPIMethod.php', 'DifferentialRevisionSearchEngine' => 'applications/differential/query/DifferentialRevisionSearchEngine.php', 'DifferentialRevisionStatus' => 'applications/differential/constants/DifferentialRevisionStatus.php', 'DifferentialRevisionSummaryHeraldField' => 'applications/differential/herald/DifferentialRevisionSummaryHeraldField.php', 'DifferentialRevisionTitleHeraldField' => 'applications/differential/herald/DifferentialRevisionTitleHeraldField.php', 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/DifferentialRevisionUpdateHistoryView.php', 'DifferentialRevisionViewController' => 'applications/differential/controller/DifferentialRevisionViewController.php', 'DifferentialSchemaSpec' => 'applications/differential/storage/DifferentialSchemaSpec.php', 'DifferentialSetDiffPropertyConduitAPIMethod' => 'applications/differential/conduit/DifferentialSetDiffPropertyConduitAPIMethod.php', 'DifferentialStoredCustomField' => 'applications/differential/customfield/DifferentialStoredCustomField.php', 'DifferentialSubscribersField' => 'applications/differential/customfield/DifferentialSubscribersField.php', 'DifferentialSummaryField' => 'applications/differential/customfield/DifferentialSummaryField.php', 'DifferentialTestPlanField' => 'applications/differential/customfield/DifferentialTestPlanField.php', 'DifferentialTitleField' => 'applications/differential/customfield/DifferentialTitleField.php', 'DifferentialTransaction' => 'applications/differential/storage/DifferentialTransaction.php', 'DifferentialTransactionComment' => 'applications/differential/storage/DifferentialTransactionComment.php', 'DifferentialTransactionEditor' => 'applications/differential/editor/DifferentialTransactionEditor.php', 'DifferentialTransactionQuery' => 'applications/differential/query/DifferentialTransactionQuery.php', 'DifferentialTransactionView' => 'applications/differential/view/DifferentialTransactionView.php', 'DifferentialUnitField' => 'applications/differential/customfield/DifferentialUnitField.php', 'DifferentialUnitStatus' => 'applications/differential/constants/DifferentialUnitStatus.php', 'DifferentialUnitTestResult' => 'applications/differential/constants/DifferentialUnitTestResult.php', 'DifferentialUpdateRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialUpdateRevisionConduitAPIMethod.php', 'DifferentialViewPolicyField' => 'applications/differential/customfield/DifferentialViewPolicyField.php', 'DiffusionAuditorDatasource' => 'applications/diffusion/typeahead/DiffusionAuditorDatasource.php', 'DiffusionAuditorFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionAuditorFunctionDatasource.php', 'DiffusionAuditorsAddAuditorsHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsAddAuditorsHeraldAction.php', 'DiffusionAuditorsAddSelfHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsAddSelfHeraldAction.php', 'DiffusionAuditorsHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsHeraldAction.php', 'DiffusionBlameConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php', 'DiffusionBlameQuery' => 'applications/diffusion/query/blame/DiffusionBlameQuery.php', 'DiffusionBlockHeraldAction' => 'applications/diffusion/herald/DiffusionBlockHeraldAction.php', 'DiffusionBranchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php', 'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php', 'DiffusionBranchTableView' => 'applications/diffusion/view/DiffusionBranchTableView.php', 'DiffusionBrowseController' => 'applications/diffusion/controller/DiffusionBrowseController.php', 'DiffusionBrowseQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php', 'DiffusionBrowseResultSet' => 'applications/diffusion/data/DiffusionBrowseResultSet.php', 'DiffusionBrowseTableView' => 'applications/diffusion/view/DiffusionBrowseTableView.php', 'DiffusionCachedResolveRefsQuery' => 'applications/diffusion/query/DiffusionCachedResolveRefsQuery.php', 'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php', 'DiffusionChangeHeraldFieldGroup' => 'applications/diffusion/herald/DiffusionChangeHeraldFieldGroup.php', 'DiffusionCloneURIView' => 'applications/diffusion/view/DiffusionCloneURIView.php', 'DiffusionCommandEngine' => 'applications/diffusion/protocol/DiffusionCommandEngine.php', 'DiffusionCommandEngineTestCase' => 'applications/diffusion/protocol/__tests__/DiffusionCommandEngineTestCase.php', 'DiffusionCommitAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionCommitAffectedFilesHeraldField.php', 'DiffusionCommitAuthorHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuthorHeraldField.php', 'DiffusionCommitAutocloseHeraldField' => 'applications/diffusion/herald/DiffusionCommitAutocloseHeraldField.php', 'DiffusionCommitBranchesController' => 'applications/diffusion/controller/DiffusionCommitBranchesController.php', 'DiffusionCommitBranchesHeraldField' => 'applications/diffusion/herald/DiffusionCommitBranchesHeraldField.php', 'DiffusionCommitCommitterHeraldField' => 'applications/diffusion/herald/DiffusionCommitCommitterHeraldField.php', 'DiffusionCommitController' => 'applications/diffusion/controller/DiffusionCommitController.php', 'DiffusionCommitDiffContentAddedHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffContentAddedHeraldField.php', 'DiffusionCommitDiffContentHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffContentHeraldField.php', 'DiffusionCommitDiffContentRemovedHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffContentRemovedHeraldField.php', 'DiffusionCommitDiffEnormousHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffEnormousHeraldField.php', 'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', 'DiffusionCommitFulltextEngine' => 'applications/repository/search/DiffusionCommitFulltextEngine.php', 'DiffusionCommitHasRevisionEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasRevisionEdgeType.php', 'DiffusionCommitHasRevisionRelationship' => 'applications/diffusion/relationships/DiffusionCommitHasRevisionRelationship.php', 'DiffusionCommitHasTaskEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasTaskEdgeType.php', 'DiffusionCommitHasTaskRelationship' => 'applications/diffusion/relationships/DiffusionCommitHasTaskRelationship.php', 'DiffusionCommitHash' => 'applications/diffusion/data/DiffusionCommitHash.php', 'DiffusionCommitHeraldField' => 'applications/diffusion/herald/DiffusionCommitHeraldField.php', 'DiffusionCommitHeraldFieldGroup' => 'applications/diffusion/herald/DiffusionCommitHeraldFieldGroup.php', 'DiffusionCommitHintQuery' => 'applications/diffusion/query/DiffusionCommitHintQuery.php', 'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php', 'DiffusionCommitHookRejectException' => 'applications/diffusion/exception/DiffusionCommitHookRejectException.php', 'DiffusionCommitMergeHeraldField' => 'applications/diffusion/herald/DiffusionCommitMergeHeraldField.php', 'DiffusionCommitMessageHeraldField' => 'applications/diffusion/herald/DiffusionCommitMessageHeraldField.php', 'DiffusionCommitPackageAuditHeraldField' => 'applications/diffusion/herald/DiffusionCommitPackageAuditHeraldField.php', 'DiffusionCommitPackageHeraldField' => 'applications/diffusion/herald/DiffusionCommitPackageHeraldField.php', 'DiffusionCommitPackageOwnerHeraldField' => 'applications/diffusion/herald/DiffusionCommitPackageOwnerHeraldField.php', 'DiffusionCommitParentsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCommitParentsQueryConduitAPIMethod.php', 'DiffusionCommitQuery' => 'applications/diffusion/query/DiffusionCommitQuery.php', 'DiffusionCommitRef' => 'applications/diffusion/data/DiffusionCommitRef.php', 'DiffusionCommitRelationship' => 'applications/diffusion/relationships/DiffusionCommitRelationship.php', 'DiffusionCommitRelationshipSource' => 'applications/search/relationship/DiffusionCommitRelationshipSource.php', 'DiffusionCommitRemarkupRule' => 'applications/diffusion/remarkup/DiffusionCommitRemarkupRule.php', 'DiffusionCommitRemarkupRuleTestCase' => 'applications/diffusion/remarkup/__tests__/DiffusionCommitRemarkupRuleTestCase.php', 'DiffusionCommitRepositoryHeraldField' => 'applications/diffusion/herald/DiffusionCommitRepositoryHeraldField.php', 'DiffusionCommitRepositoryProjectsHeraldField' => 'applications/diffusion/herald/DiffusionCommitRepositoryProjectsHeraldField.php', 'DiffusionCommitRevertedByCommitEdgeType' => 'applications/diffusion/edge/DiffusionCommitRevertedByCommitEdgeType.php', 'DiffusionCommitRevertsCommitEdgeType' => 'applications/diffusion/edge/DiffusionCommitRevertsCommitEdgeType.php', 'DiffusionCommitReviewerHeraldField' => 'applications/diffusion/herald/DiffusionCommitReviewerHeraldField.php', 'DiffusionCommitRevisionAcceptedHeraldField' => 'applications/diffusion/herald/DiffusionCommitRevisionAcceptedHeraldField.php', 'DiffusionCommitRevisionHeraldField' => 'applications/diffusion/herald/DiffusionCommitRevisionHeraldField.php', 'DiffusionCommitRevisionReviewersHeraldField' => 'applications/diffusion/herald/DiffusionCommitRevisionReviewersHeraldField.php', 'DiffusionCommitRevisionSubscribersHeraldField' => 'applications/diffusion/herald/DiffusionCommitRevisionSubscribersHeraldField.php', 'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', 'DiffusionConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionConduitAPIMethod.php', 'DiffusionController' => 'applications/diffusion/controller/DiffusionController.php', 'DiffusionCreateCommentConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCreateCommentConduitAPIMethod.php', 'DiffusionCreateRepositoriesCapability' => 'applications/diffusion/capability/DiffusionCreateRepositoriesCapability.php', 'DiffusionDaemonLockException' => 'applications/diffusion/exception/DiffusionDaemonLockException.php', 'DiffusionDefaultEditCapability' => 'applications/diffusion/capability/DiffusionDefaultEditCapability.php', 'DiffusionDefaultPushCapability' => 'applications/diffusion/capability/DiffusionDefaultPushCapability.php', 'DiffusionDefaultViewCapability' => 'applications/diffusion/capability/DiffusionDefaultViewCapability.php', 'DiffusionDiffController' => 'applications/diffusion/controller/DiffusionDiffController.php', 'DiffusionDiffInlineCommentQuery' => 'applications/diffusion/query/DiffusionDiffInlineCommentQuery.php', 'DiffusionDiffQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php', 'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php', 'DiffusionEmptyResultView' => 'applications/diffusion/view/DiffusionEmptyResultView.php', 'DiffusionExistsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php', 'DiffusionExternalController' => 'applications/diffusion/controller/DiffusionExternalController.php', 'DiffusionExternalSymbolQuery' => 'applications/diffusion/symbol/DiffusionExternalSymbolQuery.php', 'DiffusionExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionExternalSymbolsSource.php', 'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionFileContentQuery.php', 'DiffusionFileContentQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php', 'DiffusionFileFutureQuery' => 'applications/diffusion/query/DiffusionFileFutureQuery.php', 'DiffusionFindSymbolsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php', 'DiffusionGetLintMessagesConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionGetLintMessagesConduitAPIMethod.php', 'DiffusionGetRecentCommitsByPathConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionGetRecentCommitsByPathConduitAPIMethod.php', 'DiffusionGitBlameQuery' => 'applications/diffusion/query/blame/DiffusionGitBlameQuery.php', 'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php', 'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php', 'DiffusionGitCommandEngine' => 'applications/diffusion/protocol/DiffusionGitCommandEngine.php', 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php', 'DiffusionGitLFSAuthenticateWorkflow' => 'applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php', 'DiffusionGitLFSResponse' => 'applications/diffusion/response/DiffusionGitLFSResponse.php', 'DiffusionGitLFSTemporaryTokenType' => 'applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php', 'DiffusionGitRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php', 'DiffusionGitReceivePackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php', 'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php', 'DiffusionGitResponse' => 'applications/diffusion/response/DiffusionGitResponse.php', 'DiffusionGitSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitSSHWorkflow.php', 'DiffusionGitUploadPackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php', 'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php', 'DiffusionHistoryQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php', 'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php', 'DiffusionHovercardEngineExtension' => 'applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php', 'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php', 'DiffusionInlineCommentPreviewController' => 'applications/diffusion/controller/DiffusionInlineCommentPreviewController.php', 'DiffusionInternalGitRawDiffQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php', 'DiffusionLastModifiedController' => 'applications/diffusion/controller/DiffusionLastModifiedController.php', 'DiffusionLastModifiedQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php', 'DiffusionLintController' => 'applications/diffusion/controller/DiffusionLintController.php', 'DiffusionLintCountQuery' => 'applications/diffusion/query/DiffusionLintCountQuery.php', 'DiffusionLintSaveRunner' => 'applications/diffusion/DiffusionLintSaveRunner.php', 'DiffusionLocalRepositoryFilter' => 'applications/diffusion/data/DiffusionLocalRepositoryFilter.php', 'DiffusionLookSoonConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php', 'DiffusionLowLevelCommitFieldsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitFieldsQuery.php', 'DiffusionLowLevelCommitQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php', 'DiffusionLowLevelGitRefQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelGitRefQuery.php', 'DiffusionLowLevelMercurialBranchesQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelMercurialBranchesQuery.php', 'DiffusionLowLevelMercurialPathsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelMercurialPathsQuery.php', 'DiffusionLowLevelMercurialPathsQueryTests' => 'applications/diffusion/query/lowlevel/__tests__/DiffusionLowLevelMercurialPathsQueryTests.php', 'DiffusionLowLevelParentsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php', 'DiffusionLowLevelQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelQuery.php', 'DiffusionLowLevelResolveRefsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php', 'DiffusionMercurialBlameQuery' => 'applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php', 'DiffusionMercurialCommandEngine' => 'applications/diffusion/protocol/DiffusionMercurialCommandEngine.php', 'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionMercurialFileContentQuery.php', 'DiffusionMercurialRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionMercurialRawDiffQuery.php', 'DiffusionMercurialRequest' => 'applications/diffusion/request/DiffusionMercurialRequest.php', 'DiffusionMercurialResponse' => 'applications/diffusion/response/DiffusionMercurialResponse.php', 'DiffusionMercurialSSHWorkflow' => 'applications/diffusion/ssh/DiffusionMercurialSSHWorkflow.php', 'DiffusionMercurialServeSSHWorkflow' => 'applications/diffusion/ssh/DiffusionMercurialServeSSHWorkflow.php', 'DiffusionMercurialWireClientSSHProtocolChannel' => 'applications/diffusion/ssh/DiffusionMercurialWireClientSSHProtocolChannel.php', 'DiffusionMercurialWireProtocol' => 'applications/diffusion/protocol/DiffusionMercurialWireProtocol.php', 'DiffusionMercurialWireProtocolTests' => 'applications/diffusion/protocol/__tests__/DiffusionMercurialWireProtocolTests.php', 'DiffusionMercurialWireSSHTestCase' => 'applications/diffusion/ssh/__tests__/DiffusionMercurialWireSSHTestCase.php', 'DiffusionMergedCommitsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php', 'DiffusionPathChange' => 'applications/diffusion/data/DiffusionPathChange.php', 'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php', 'DiffusionPathCompleteController' => 'applications/diffusion/controller/DiffusionPathCompleteController.php', 'DiffusionPathIDQuery' => 'applications/diffusion/query/pathid/DiffusionPathIDQuery.php', 'DiffusionPathQuery' => 'applications/diffusion/query/DiffusionPathQuery.php', 'DiffusionPathQueryTestCase' => 'applications/diffusion/query/pathid/__tests__/DiffusionPathQueryTestCase.php', 'DiffusionPathTreeController' => 'applications/diffusion/controller/DiffusionPathTreeController.php', 'DiffusionPathValidateController' => 'applications/diffusion/controller/DiffusionPathValidateController.php', 'DiffusionPhpExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPhpExternalSymbolsSource.php', 'DiffusionPreCommitContentAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentAffectedFilesHeraldField.php', 'DiffusionPreCommitContentAuthorHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentAuthorHeraldField.php', 'DiffusionPreCommitContentAuthorRawHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentAuthorRawHeraldField.php', 'DiffusionPreCommitContentBranchesHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentBranchesHeraldField.php', 'DiffusionPreCommitContentCommitterHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentCommitterHeraldField.php', 'DiffusionPreCommitContentCommitterRawHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentCommitterRawHeraldField.php', 'DiffusionPreCommitContentDiffContentAddedHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentDiffContentAddedHeraldField.php', 'DiffusionPreCommitContentDiffContentHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentDiffContentHeraldField.php', 'DiffusionPreCommitContentDiffContentRemovedHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentDiffContentRemovedHeraldField.php', 'DiffusionPreCommitContentDiffEnormousHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentDiffEnormousHeraldField.php', 'DiffusionPreCommitContentHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentHeraldField.php', 'DiffusionPreCommitContentMergeHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentMergeHeraldField.php', 'DiffusionPreCommitContentMessageHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentMessageHeraldField.php', 'DiffusionPreCommitContentPusherHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentPusherHeraldField.php', 'DiffusionPreCommitContentPusherIsCommitterHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentPusherIsCommitterHeraldField.php', 'DiffusionPreCommitContentPusherProjectsHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentPusherProjectsHeraldField.php', 'DiffusionPreCommitContentRepositoryHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentRepositoryHeraldField.php', 'DiffusionPreCommitContentRepositoryProjectsHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentRepositoryProjectsHeraldField.php', 'DiffusionPreCommitContentRevisionAcceptedHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentRevisionAcceptedHeraldField.php', 'DiffusionPreCommitContentRevisionHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentRevisionHeraldField.php', 'DiffusionPreCommitContentRevisionReviewersHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentRevisionReviewersHeraldField.php', 'DiffusionPreCommitContentRevisionSubscribersHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitContentRevisionSubscribersHeraldField.php', 'DiffusionPreCommitRefChangeHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefChangeHeraldField.php', 'DiffusionPreCommitRefHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefHeraldField.php', 'DiffusionPreCommitRefHeraldFieldGroup' => 'applications/diffusion/herald/DiffusionPreCommitRefHeraldFieldGroup.php', 'DiffusionPreCommitRefNameHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefNameHeraldField.php', 'DiffusionPreCommitRefPusherHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefPusherHeraldField.php', 'DiffusionPreCommitRefPusherProjectsHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefPusherProjectsHeraldField.php', 'DiffusionPreCommitRefRepositoryHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefRepositoryHeraldField.php', 'DiffusionPreCommitRefRepositoryProjectsHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefRepositoryProjectsHeraldField.php', 'DiffusionPreCommitRefTypeHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefTypeHeraldField.php', 'DiffusionPullEventGarbageCollector' => 'applications/diffusion/garbagecollector/DiffusionPullEventGarbageCollector.php', 'DiffusionPushCapability' => 'applications/diffusion/capability/DiffusionPushCapability.php', 'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php', 'DiffusionPushLogController' => 'applications/diffusion/controller/DiffusionPushLogController.php', 'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php', 'DiffusionPushLogListView' => 'applications/diffusion/view/DiffusionPushLogListView.php', 'DiffusionPythonExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPythonExternalSymbolsSource.php', 'DiffusionQuery' => 'applications/diffusion/query/DiffusionQuery.php', 'DiffusionQueryCommitsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionQueryCommitsConduitAPIMethod.php', 'DiffusionQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php', 'DiffusionQueryPathsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php', 'DiffusionRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionRawDiffQuery.php', 'DiffusionRawDiffQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRawDiffQueryConduitAPIMethod.php', 'DiffusionReadmeView' => 'applications/diffusion/view/DiffusionReadmeView.php', 'DiffusionRefDatasource' => 'applications/diffusion/typeahead/DiffusionRefDatasource.php', 'DiffusionRefNotFoundException' => 'applications/diffusion/exception/DiffusionRefNotFoundException.php', 'DiffusionRefTableController' => 'applications/diffusion/controller/DiffusionRefTableController.php', 'DiffusionRefsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php', 'DiffusionRenameHistoryQuery' => 'applications/diffusion/query/DiffusionRenameHistoryQuery.php', 'DiffusionRepositoryActionsManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php', 'DiffusionRepositoryAutomationManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php', 'DiffusionRepositoryBasicsManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php', 'DiffusionRepositoryBranchesManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php', 'DiffusionRepositoryByIDRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryByIDRemarkupRule.php', 'DiffusionRepositoryClusterEngine' => 'applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php', 'DiffusionRepositoryClusterEngineLogInterface' => 'applications/diffusion/protocol/DiffusionRepositoryClusterEngineLogInterface.php', 'DiffusionRepositoryController' => 'applications/diffusion/controller/DiffusionRepositoryController.php', 'DiffusionRepositoryDatasource' => 'applications/diffusion/typeahead/DiffusionRepositoryDatasource.php', 'DiffusionRepositoryDefaultController' => 'applications/diffusion/controller/DiffusionRepositoryDefaultController.php', 'DiffusionRepositoryDocumentationManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryDocumentationManagementPanel.php', 'DiffusionRepositoryEditActivateController' => 'applications/diffusion/controller/DiffusionRepositoryEditActivateController.php', 'DiffusionRepositoryEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositoryEditConduitAPIMethod.php', 'DiffusionRepositoryEditController' => 'applications/diffusion/controller/DiffusionRepositoryEditController.php', 'DiffusionRepositoryEditDangerousController' => 'applications/diffusion/controller/DiffusionRepositoryEditDangerousController.php', 'DiffusionRepositoryEditDeleteController' => 'applications/diffusion/controller/DiffusionRepositoryEditDeleteController.php', 'DiffusionRepositoryEditEngine' => 'applications/diffusion/editor/DiffusionRepositoryEditEngine.php', 'DiffusionRepositoryEditUpdateController' => 'applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php', 'DiffusionRepositoryHistoryManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryHistoryManagementPanel.php', 'DiffusionRepositoryListController' => 'applications/diffusion/controller/DiffusionRepositoryListController.php', 'DiffusionRepositoryManageController' => 'applications/diffusion/controller/DiffusionRepositoryManageController.php', 'DiffusionRepositoryManagePanelsController' => 'applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php', 'DiffusionRepositoryManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryManagementPanel.php', 'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php', 'DiffusionRepositoryPoliciesManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php', 'DiffusionRepositoryRef' => 'applications/diffusion/data/DiffusionRepositoryRef.php', 'DiffusionRepositoryRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php', 'DiffusionRepositorySearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositorySearchConduitAPIMethod.php', 'DiffusionRepositoryStagingManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php', 'DiffusionRepositoryStatusManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php', 'DiffusionRepositoryStorageManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php', 'DiffusionRepositorySubversionManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySubversionManagementPanel.php', 'DiffusionRepositorySymbolsManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php', 'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php', 'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php', 'DiffusionRepositoryURICredentialController' => 'applications/diffusion/controller/DiffusionRepositoryURICredentialController.php', 'DiffusionRepositoryURIDisableController' => 'applications/diffusion/controller/DiffusionRepositoryURIDisableController.php', 'DiffusionRepositoryURIEditController' => 'applications/diffusion/controller/DiffusionRepositoryURIEditController.php', 'DiffusionRepositoryURIViewController' => 'applications/diffusion/controller/DiffusionRepositoryURIViewController.php', 'DiffusionRepositoryURIsIndexEngineExtension' => 'applications/diffusion/engineextension/DiffusionRepositoryURIsIndexEngineExtension.php', 'DiffusionRepositoryURIsManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php', 'DiffusionRepositoryURIsSearchEngineAttachment' => 'applications/diffusion/engineextension/DiffusionRepositoryURIsSearchEngineAttachment.php', 'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php', 'DiffusionResolveRefsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php', 'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php', 'DiffusionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSSHWorkflow.php', 'DiffusionSearchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php', 'DiffusionServeController' => 'applications/diffusion/controller/DiffusionServeController.php', 'DiffusionSetPasswordSettingsPanel' => 'applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php', 'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php', 'DiffusionSubversionCommandEngine' => 'applications/diffusion/protocol/DiffusionSubversionCommandEngine.php', 'DiffusionSubversionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionSSHWorkflow.php', 'DiffusionSubversionServeSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php', 'DiffusionSubversionWireProtocol' => 'applications/diffusion/protocol/DiffusionSubversionWireProtocol.php', 'DiffusionSubversionWireProtocolTestCase' => 'applications/diffusion/protocol/__tests__/DiffusionSubversionWireProtocolTestCase.php', 'DiffusionSvnBlameQuery' => 'applications/diffusion/query/blame/DiffusionSvnBlameQuery.php', 'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionSvnFileContentQuery.php', 'DiffusionSvnRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionSvnRawDiffQuery.php', 'DiffusionSvnRequest' => 'applications/diffusion/request/DiffusionSvnRequest.php', 'DiffusionSymbolController' => 'applications/diffusion/controller/DiffusionSymbolController.php', 'DiffusionSymbolDatasource' => 'applications/diffusion/typeahead/DiffusionSymbolDatasource.php', 'DiffusionSymbolQuery' => 'applications/diffusion/query/DiffusionSymbolQuery.php', 'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php', 'DiffusionTagListView' => 'applications/diffusion/view/DiffusionTagListView.php', 'DiffusionTaggedRepositoriesFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionTaggedRepositoriesFunctionDatasource.php', 'DiffusionTagsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php', 'DiffusionURIEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionURIEditConduitAPIMethod.php', 'DiffusionURIEditEngine' => 'applications/diffusion/editor/DiffusionURIEditEngine.php', 'DiffusionURIEditor' => 'applications/diffusion/editor/DiffusionURIEditor.php', 'DiffusionURITestCase' => 'applications/diffusion/request/__tests__/DiffusionURITestCase.php', 'DiffusionUpdateCoverageConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionUpdateCoverageConduitAPIMethod.php', 'DiffusionView' => 'applications/diffusion/view/DiffusionView.php', 'DivinerArticleAtomizer' => 'applications/diviner/atomizer/DivinerArticleAtomizer.php', 'DivinerAtom' => 'applications/diviner/atom/DivinerAtom.php', 'DivinerAtomCache' => 'applications/diviner/cache/DivinerAtomCache.php', 'DivinerAtomController' => 'applications/diviner/controller/DivinerAtomController.php', 'DivinerAtomListController' => 'applications/diviner/controller/DivinerAtomListController.php', 'DivinerAtomPHIDType' => 'applications/diviner/phid/DivinerAtomPHIDType.php', 'DivinerAtomQuery' => 'applications/diviner/query/DivinerAtomQuery.php', 'DivinerAtomRef' => 'applications/diviner/atom/DivinerAtomRef.php', 'DivinerAtomSearchEngine' => 'applications/diviner/query/DivinerAtomSearchEngine.php', 'DivinerAtomizeWorkflow' => 'applications/diviner/workflow/DivinerAtomizeWorkflow.php', 'DivinerAtomizer' => 'applications/diviner/atomizer/DivinerAtomizer.php', 'DivinerBookController' => 'applications/diviner/controller/DivinerBookController.php', 'DivinerBookDatasource' => 'applications/diviner/typeahead/DivinerBookDatasource.php', 'DivinerBookEditController' => 'applications/diviner/controller/DivinerBookEditController.php', 'DivinerBookItemView' => 'applications/diviner/view/DivinerBookItemView.php', 'DivinerBookPHIDType' => 'applications/diviner/phid/DivinerBookPHIDType.php', 'DivinerBookQuery' => 'applications/diviner/query/DivinerBookQuery.php', 'DivinerController' => 'applications/diviner/controller/DivinerController.php', 'DivinerDAO' => 'applications/diviner/storage/DivinerDAO.php', 'DivinerDefaultEditCapability' => 'applications/diviner/capability/DivinerDefaultEditCapability.php', 'DivinerDefaultRenderer' => 'applications/diviner/renderer/DivinerDefaultRenderer.php', 'DivinerDefaultViewCapability' => 'applications/diviner/capability/DivinerDefaultViewCapability.php', 'DivinerDiskCache' => 'applications/diviner/cache/DivinerDiskCache.php', 'DivinerFileAtomizer' => 'applications/diviner/atomizer/DivinerFileAtomizer.php', 'DivinerFindController' => 'applications/diviner/controller/DivinerFindController.php', 'DivinerGenerateWorkflow' => 'applications/diviner/workflow/DivinerGenerateWorkflow.php', 'DivinerLiveAtom' => 'applications/diviner/storage/DivinerLiveAtom.php', 'DivinerLiveBook' => 'applications/diviner/storage/DivinerLiveBook.php', 'DivinerLiveBookEditor' => 'applications/diviner/editor/DivinerLiveBookEditor.php', 'DivinerLiveBookFulltextEngine' => 'applications/diviner/search/DivinerLiveBookFulltextEngine.php', 'DivinerLiveBookTransaction' => 'applications/diviner/storage/DivinerLiveBookTransaction.php', 'DivinerLiveBookTransactionQuery' => 'applications/diviner/query/DivinerLiveBookTransactionQuery.php', 'DivinerLivePublisher' => 'applications/diviner/publisher/DivinerLivePublisher.php', 'DivinerLiveSymbol' => 'applications/diviner/storage/DivinerLiveSymbol.php', 'DivinerLiveSymbolFulltextEngine' => 'applications/diviner/search/DivinerLiveSymbolFulltextEngine.php', 'DivinerMainController' => 'applications/diviner/controller/DivinerMainController.php', 'DivinerPHPAtomizer' => 'applications/diviner/atomizer/DivinerPHPAtomizer.php', 'DivinerParameterTableView' => 'applications/diviner/view/DivinerParameterTableView.php', 'DivinerPublishCache' => 'applications/diviner/cache/DivinerPublishCache.php', 'DivinerPublisher' => 'applications/diviner/publisher/DivinerPublisher.php', 'DivinerRenderer' => 'applications/diviner/renderer/DivinerRenderer.php', 'DivinerReturnTableView' => 'applications/diviner/view/DivinerReturnTableView.php', 'DivinerSchemaSpec' => 'applications/diviner/storage/DivinerSchemaSpec.php', 'DivinerSectionView' => 'applications/diviner/view/DivinerSectionView.php', 'DivinerStaticPublisher' => 'applications/diviner/publisher/DivinerStaticPublisher.php', 'DivinerSymbolRemarkupRule' => 'applications/diviner/markup/DivinerSymbolRemarkupRule.php', 'DivinerWorkflow' => 'applications/diviner/workflow/DivinerWorkflow.php', 'DoorkeeperAsanaFeedWorker' => 'applications/doorkeeper/worker/DoorkeeperAsanaFeedWorker.php', 'DoorkeeperAsanaRemarkupRule' => 'applications/doorkeeper/remarkup/DoorkeeperAsanaRemarkupRule.php', 'DoorkeeperBridge' => 'applications/doorkeeper/bridge/DoorkeeperBridge.php', 'DoorkeeperBridgeAsana' => 'applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php', 'DoorkeeperBridgeGitHub' => 'applications/doorkeeper/bridge/DoorkeeperBridgeGitHub.php', 'DoorkeeperBridgeGitHubIssue' => 'applications/doorkeeper/bridge/DoorkeeperBridgeGitHubIssue.php', 'DoorkeeperBridgeGitHubUser' => 'applications/doorkeeper/bridge/DoorkeeperBridgeGitHubUser.php', 'DoorkeeperBridgeJIRA' => 'applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php', 'DoorkeeperBridgeJIRATestCase' => 'applications/doorkeeper/bridge/__tests__/DoorkeeperBridgeJIRATestCase.php', 'DoorkeeperBridgedObjectCurtainExtension' => 'applications/doorkeeper/engineextension/DoorkeeperBridgedObjectCurtainExtension.php', 'DoorkeeperBridgedObjectInterface' => 'applications/doorkeeper/bridge/DoorkeeperBridgedObjectInterface.php', 'DoorkeeperDAO' => 'applications/doorkeeper/storage/DoorkeeperDAO.php', 'DoorkeeperExternalObject' => 'applications/doorkeeper/storage/DoorkeeperExternalObject.php', 'DoorkeeperExternalObjectPHIDType' => 'applications/doorkeeper/phid/DoorkeeperExternalObjectPHIDType.php', 'DoorkeeperExternalObjectQuery' => 'applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php', 'DoorkeeperFeedStoryPublisher' => 'applications/doorkeeper/engine/DoorkeeperFeedStoryPublisher.php', 'DoorkeeperFeedWorker' => 'applications/doorkeeper/worker/DoorkeeperFeedWorker.php', 'DoorkeeperImportEngine' => 'applications/doorkeeper/engine/DoorkeeperImportEngine.php', 'DoorkeeperJIRAFeedWorker' => 'applications/doorkeeper/worker/DoorkeeperJIRAFeedWorker.php', 'DoorkeeperJIRARemarkupRule' => 'applications/doorkeeper/remarkup/DoorkeeperJIRARemarkupRule.php', 'DoorkeeperMissingLinkException' => 'applications/doorkeeper/exception/DoorkeeperMissingLinkException.php', 'DoorkeeperObjectRef' => 'applications/doorkeeper/engine/DoorkeeperObjectRef.php', 'DoorkeeperRemarkupRule' => 'applications/doorkeeper/remarkup/DoorkeeperRemarkupRule.php', 'DoorkeeperSchemaSpec' => 'applications/doorkeeper/storage/DoorkeeperSchemaSpec.php', 'DoorkeeperTagView' => 'applications/doorkeeper/view/DoorkeeperTagView.php', 'DoorkeeperTagsController' => 'applications/doorkeeper/controller/DoorkeeperTagsController.php', 'DrydockAlmanacServiceHostBlueprintImplementation' => 'applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php', 'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/DrydockApacheWebrootInterface.php', 'DrydockAuthorization' => 'applications/drydock/storage/DrydockAuthorization.php', 'DrydockAuthorizationAuthorizeController' => 'applications/drydock/controller/DrydockAuthorizationAuthorizeController.php', 'DrydockAuthorizationListController' => 'applications/drydock/controller/DrydockAuthorizationListController.php', 'DrydockAuthorizationListView' => 'applications/drydock/view/DrydockAuthorizationListView.php', 'DrydockAuthorizationPHIDType' => 'applications/drydock/phid/DrydockAuthorizationPHIDType.php', 'DrydockAuthorizationQuery' => 'applications/drydock/query/DrydockAuthorizationQuery.php', + 'DrydockAuthorizationSearchConduitAPIMethod' => 'applications/drydock/conduit/DrydockAuthorizationSearchConduitAPIMethod.php', 'DrydockAuthorizationSearchEngine' => 'applications/drydock/query/DrydockAuthorizationSearchEngine.php', 'DrydockAuthorizationViewController' => 'applications/drydock/controller/DrydockAuthorizationViewController.php', 'DrydockBlueprint' => 'applications/drydock/storage/DrydockBlueprint.php', 'DrydockBlueprintController' => 'applications/drydock/controller/DrydockBlueprintController.php', 'DrydockBlueprintCoreCustomField' => 'applications/drydock/customfield/DrydockBlueprintCoreCustomField.php', 'DrydockBlueprintCustomField' => 'applications/drydock/customfield/DrydockBlueprintCustomField.php', 'DrydockBlueprintDatasource' => 'applications/drydock/typeahead/DrydockBlueprintDatasource.php', 'DrydockBlueprintDisableController' => 'applications/drydock/controller/DrydockBlueprintDisableController.php', 'DrydockBlueprintEditController' => 'applications/drydock/controller/DrydockBlueprintEditController.php', 'DrydockBlueprintEditEngine' => 'applications/drydock/editor/DrydockBlueprintEditEngine.php', 'DrydockBlueprintEditor' => 'applications/drydock/editor/DrydockBlueprintEditor.php', 'DrydockBlueprintImplementation' => 'applications/drydock/blueprint/DrydockBlueprintImplementation.php', 'DrydockBlueprintImplementationTestCase' => 'applications/drydock/blueprint/__tests__/DrydockBlueprintImplementationTestCase.php', 'DrydockBlueprintListController' => 'applications/drydock/controller/DrydockBlueprintListController.php', 'DrydockBlueprintNameNgrams' => 'applications/drydock/storage/DrydockBlueprintNameNgrams.php', 'DrydockBlueprintPHIDType' => 'applications/drydock/phid/DrydockBlueprintPHIDType.php', 'DrydockBlueprintQuery' => 'applications/drydock/query/DrydockBlueprintQuery.php', + 'DrydockBlueprintSearchConduitAPIMethod' => 'applications/drydock/conduit/DrydockBlueprintSearchConduitAPIMethod.php', 'DrydockBlueprintSearchEngine' => 'applications/drydock/query/DrydockBlueprintSearchEngine.php', 'DrydockBlueprintTransaction' => 'applications/drydock/storage/DrydockBlueprintTransaction.php', 'DrydockBlueprintTransactionQuery' => 'applications/drydock/query/DrydockBlueprintTransactionQuery.php', 'DrydockBlueprintViewController' => 'applications/drydock/controller/DrydockBlueprintViewController.php', 'DrydockCommand' => 'applications/drydock/storage/DrydockCommand.php', 'DrydockCommandError' => 'applications/drydock/exception/DrydockCommandError.php', 'DrydockCommandInterface' => 'applications/drydock/interface/command/DrydockCommandInterface.php', 'DrydockCommandQuery' => 'applications/drydock/query/DrydockCommandQuery.php', 'DrydockConsoleController' => 'applications/drydock/controller/DrydockConsoleController.php', 'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php', 'DrydockController' => 'applications/drydock/controller/DrydockController.php', 'DrydockCreateBlueprintsCapability' => 'applications/drydock/capability/DrydockCreateBlueprintsCapability.php', 'DrydockDAO' => 'applications/drydock/storage/DrydockDAO.php', 'DrydockDefaultEditCapability' => 'applications/drydock/capability/DrydockDefaultEditCapability.php', 'DrydockDefaultViewCapability' => 'applications/drydock/capability/DrydockDefaultViewCapability.php', 'DrydockFilesystemInterface' => 'applications/drydock/interface/filesystem/DrydockFilesystemInterface.php', 'DrydockInterface' => 'applications/drydock/interface/DrydockInterface.php', 'DrydockLandRepositoryOperation' => 'applications/drydock/operation/DrydockLandRepositoryOperation.php', 'DrydockLease' => 'applications/drydock/storage/DrydockLease.php', 'DrydockLeaseAcquiredLogType' => 'applications/drydock/logtype/DrydockLeaseAcquiredLogType.php', 'DrydockLeaseActivatedLogType' => 'applications/drydock/logtype/DrydockLeaseActivatedLogType.php', 'DrydockLeaseActivationFailureLogType' => 'applications/drydock/logtype/DrydockLeaseActivationFailureLogType.php', 'DrydockLeaseActivationYieldLogType' => 'applications/drydock/logtype/DrydockLeaseActivationYieldLogType.php', 'DrydockLeaseController' => 'applications/drydock/controller/DrydockLeaseController.php', 'DrydockLeaseDatasource' => 'applications/drydock/typeahead/DrydockLeaseDatasource.php', 'DrydockLeaseDestroyedLogType' => 'applications/drydock/logtype/DrydockLeaseDestroyedLogType.php', 'DrydockLeaseListController' => 'applications/drydock/controller/DrydockLeaseListController.php', 'DrydockLeaseListView' => 'applications/drydock/view/DrydockLeaseListView.php', 'DrydockLeaseNoAuthorizationsLogType' => 'applications/drydock/logtype/DrydockLeaseNoAuthorizationsLogType.php', 'DrydockLeaseNoBlueprintsLogType' => 'applications/drydock/logtype/DrydockLeaseNoBlueprintsLogType.php', 'DrydockLeasePHIDType' => 'applications/drydock/phid/DrydockLeasePHIDType.php', 'DrydockLeaseQuery' => 'applications/drydock/query/DrydockLeaseQuery.php', 'DrydockLeaseQueuedLogType' => 'applications/drydock/logtype/DrydockLeaseQueuedLogType.php', 'DrydockLeaseReclaimLogType' => 'applications/drydock/logtype/DrydockLeaseReclaimLogType.php', 'DrydockLeaseReleaseController' => 'applications/drydock/controller/DrydockLeaseReleaseController.php', 'DrydockLeaseReleasedLogType' => 'applications/drydock/logtype/DrydockLeaseReleasedLogType.php', 'DrydockLeaseSearchEngine' => 'applications/drydock/query/DrydockLeaseSearchEngine.php', 'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php', 'DrydockLeaseUpdateWorker' => 'applications/drydock/worker/DrydockLeaseUpdateWorker.php', 'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.php', 'DrydockLeaseWaitingForResourcesLogType' => 'applications/drydock/logtype/DrydockLeaseWaitingForResourcesLogType.php', 'DrydockLog' => 'applications/drydock/storage/DrydockLog.php', 'DrydockLogController' => 'applications/drydock/controller/DrydockLogController.php', 'DrydockLogGarbageCollector' => 'applications/drydock/garbagecollector/DrydockLogGarbageCollector.php', 'DrydockLogListController' => 'applications/drydock/controller/DrydockLogListController.php', 'DrydockLogListView' => 'applications/drydock/view/DrydockLogListView.php', 'DrydockLogQuery' => 'applications/drydock/query/DrydockLogQuery.php', 'DrydockLogSearchEngine' => 'applications/drydock/query/DrydockLogSearchEngine.php', 'DrydockLogType' => 'applications/drydock/logtype/DrydockLogType.php', 'DrydockManagementCommandWorkflow' => 'applications/drydock/management/DrydockManagementCommandWorkflow.php', 'DrydockManagementLeaseWorkflow' => 'applications/drydock/management/DrydockManagementLeaseWorkflow.php', 'DrydockManagementReclaimWorkflow' => 'applications/drydock/management/DrydockManagementReclaimWorkflow.php', 'DrydockManagementReleaseLeaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php', 'DrydockManagementReleaseResourceWorkflow' => 'applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php', 'DrydockManagementUpdateLeaseWorkflow' => 'applications/drydock/management/DrydockManagementUpdateLeaseWorkflow.php', 'DrydockManagementUpdateResourceWorkflow' => 'applications/drydock/management/DrydockManagementUpdateResourceWorkflow.php', 'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php', 'DrydockObjectAuthorizationView' => 'applications/drydock/view/DrydockObjectAuthorizationView.php', 'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php', 'DrydockRepositoryOperation' => 'applications/drydock/storage/DrydockRepositoryOperation.php', 'DrydockRepositoryOperationController' => 'applications/drydock/controller/DrydockRepositoryOperationController.php', 'DrydockRepositoryOperationDismissController' => 'applications/drydock/controller/DrydockRepositoryOperationDismissController.php', 'DrydockRepositoryOperationListController' => 'applications/drydock/controller/DrydockRepositoryOperationListController.php', 'DrydockRepositoryOperationPHIDType' => 'applications/drydock/phid/DrydockRepositoryOperationPHIDType.php', 'DrydockRepositoryOperationQuery' => 'applications/drydock/query/DrydockRepositoryOperationQuery.php', 'DrydockRepositoryOperationSearchEngine' => 'applications/drydock/query/DrydockRepositoryOperationSearchEngine.php', 'DrydockRepositoryOperationStatusController' => 'applications/drydock/controller/DrydockRepositoryOperationStatusController.php', 'DrydockRepositoryOperationStatusView' => 'applications/drydock/view/DrydockRepositoryOperationStatusView.php', 'DrydockRepositoryOperationType' => 'applications/drydock/operation/DrydockRepositoryOperationType.php', 'DrydockRepositoryOperationUpdateWorker' => 'applications/drydock/worker/DrydockRepositoryOperationUpdateWorker.php', 'DrydockRepositoryOperationViewController' => 'applications/drydock/controller/DrydockRepositoryOperationViewController.php', 'DrydockResource' => 'applications/drydock/storage/DrydockResource.php', 'DrydockResourceActivationFailureLogType' => 'applications/drydock/logtype/DrydockResourceActivationFailureLogType.php', 'DrydockResourceActivationYieldLogType' => 'applications/drydock/logtype/DrydockResourceActivationYieldLogType.php', 'DrydockResourceController' => 'applications/drydock/controller/DrydockResourceController.php', 'DrydockResourceDatasource' => 'applications/drydock/typeahead/DrydockResourceDatasource.php', 'DrydockResourceListController' => 'applications/drydock/controller/DrydockResourceListController.php', 'DrydockResourceListView' => 'applications/drydock/view/DrydockResourceListView.php', 'DrydockResourcePHIDType' => 'applications/drydock/phid/DrydockResourcePHIDType.php', 'DrydockResourceQuery' => 'applications/drydock/query/DrydockResourceQuery.php', 'DrydockResourceReclaimLogType' => 'applications/drydock/logtype/DrydockResourceReclaimLogType.php', 'DrydockResourceReleaseController' => 'applications/drydock/controller/DrydockResourceReleaseController.php', 'DrydockResourceSearchEngine' => 'applications/drydock/query/DrydockResourceSearchEngine.php', 'DrydockResourceStatus' => 'applications/drydock/constants/DrydockResourceStatus.php', 'DrydockResourceUpdateWorker' => 'applications/drydock/worker/DrydockResourceUpdateWorker.php', 'DrydockResourceViewController' => 'applications/drydock/controller/DrydockResourceViewController.php', 'DrydockSFTPFilesystemInterface' => 'applications/drydock/interface/filesystem/DrydockSFTPFilesystemInterface.php', 'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/DrydockSSHCommandInterface.php', 'DrydockSchemaSpec' => 'applications/drydock/storage/DrydockSchemaSpec.php', 'DrydockSlotLock' => 'applications/drydock/storage/DrydockSlotLock.php', 'DrydockSlotLockException' => 'applications/drydock/exception/DrydockSlotLockException.php', 'DrydockSlotLockFailureLogType' => 'applications/drydock/logtype/DrydockSlotLockFailureLogType.php', 'DrydockTestRepositoryOperation' => 'applications/drydock/operation/DrydockTestRepositoryOperation.php', 'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/DrydockWebrootInterface.php', 'DrydockWorker' => 'applications/drydock/worker/DrydockWorker.php', 'DrydockWorkingCopyBlueprintImplementation' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php', 'FeedConduitAPIMethod' => 'applications/feed/conduit/FeedConduitAPIMethod.php', 'FeedPublishConduitAPIMethod' => 'applications/feed/conduit/FeedPublishConduitAPIMethod.php', 'FeedPublisherHTTPWorker' => 'applications/feed/worker/FeedPublisherHTTPWorker.php', 'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php', 'FeedPushWorker' => 'applications/feed/worker/FeedPushWorker.php', 'FeedQueryConduitAPIMethod' => 'applications/feed/conduit/FeedQueryConduitAPIMethod.php', 'FeedStoryNotificationGarbageCollector' => 'applications/notification/garbagecollector/FeedStoryNotificationGarbageCollector.php', 'FileAllocateConduitAPIMethod' => 'applications/files/conduit/FileAllocateConduitAPIMethod.php', 'FileConduitAPIMethod' => 'applications/files/conduit/FileConduitAPIMethod.php', 'FileCreateMailReceiver' => 'applications/files/mail/FileCreateMailReceiver.php', 'FileDownloadConduitAPIMethod' => 'applications/files/conduit/FileDownloadConduitAPIMethod.php', 'FileInfoConduitAPIMethod' => 'applications/files/conduit/FileInfoConduitAPIMethod.php', 'FileMailReceiver' => 'applications/files/mail/FileMailReceiver.php', 'FileQueryChunksConduitAPIMethod' => 'applications/files/conduit/FileQueryChunksConduitAPIMethod.php', 'FileReplyHandler' => 'applications/files/mail/FileReplyHandler.php', 'FileUploadChunkConduitAPIMethod' => 'applications/files/conduit/FileUploadChunkConduitAPIMethod.php', 'FileUploadConduitAPIMethod' => 'applications/files/conduit/FileUploadConduitAPIMethod.php', 'FileUploadHashConduitAPIMethod' => 'applications/files/conduit/FileUploadHashConduitAPIMethod.php', 'FilesDefaultViewCapability' => 'applications/files/capability/FilesDefaultViewCapability.php', 'FlagConduitAPIMethod' => 'applications/flag/conduit/FlagConduitAPIMethod.php', 'FlagDeleteConduitAPIMethod' => 'applications/flag/conduit/FlagDeleteConduitAPIMethod.php', 'FlagEditConduitAPIMethod' => 'applications/flag/conduit/FlagEditConduitAPIMethod.php', 'FlagQueryConduitAPIMethod' => 'applications/flag/conduit/FlagQueryConduitAPIMethod.php', 'FundBacker' => 'applications/fund/storage/FundBacker.php', 'FundBackerCart' => 'applications/fund/phortune/FundBackerCart.php', 'FundBackerEditor' => 'applications/fund/editor/FundBackerEditor.php', 'FundBackerListController' => 'applications/fund/controller/FundBackerListController.php', 'FundBackerPHIDType' => 'applications/fund/phid/FundBackerPHIDType.php', 'FundBackerProduct' => 'applications/fund/phortune/FundBackerProduct.php', 'FundBackerQuery' => 'applications/fund/query/FundBackerQuery.php', 'FundBackerSearchEngine' => 'applications/fund/query/FundBackerSearchEngine.php', 'FundBackerTransaction' => 'applications/fund/storage/FundBackerTransaction.php', 'FundBackerTransactionQuery' => 'applications/fund/query/FundBackerTransactionQuery.php', 'FundController' => 'applications/fund/controller/FundController.php', 'FundCreateInitiativesCapability' => 'applications/fund/capability/FundCreateInitiativesCapability.php', 'FundDAO' => 'applications/fund/storage/FundDAO.php', 'FundDefaultViewCapability' => 'applications/fund/capability/FundDefaultViewCapability.php', 'FundInitiative' => 'applications/fund/storage/FundInitiative.php', 'FundInitiativeBackController' => 'applications/fund/controller/FundInitiativeBackController.php', 'FundInitiativeCloseController' => 'applications/fund/controller/FundInitiativeCloseController.php', 'FundInitiativeCommentController' => 'applications/fund/controller/FundInitiativeCommentController.php', 'FundInitiativeEditController' => 'applications/fund/controller/FundInitiativeEditController.php', 'FundInitiativeEditor' => 'applications/fund/editor/FundInitiativeEditor.php', 'FundInitiativeFulltextEngine' => 'applications/fund/search/FundInitiativeFulltextEngine.php', 'FundInitiativeListController' => 'applications/fund/controller/FundInitiativeListController.php', 'FundInitiativePHIDType' => 'applications/fund/phid/FundInitiativePHIDType.php', 'FundInitiativeQuery' => 'applications/fund/query/FundInitiativeQuery.php', 'FundInitiativeRemarkupRule' => 'applications/fund/remarkup/FundInitiativeRemarkupRule.php', 'FundInitiativeReplyHandler' => 'applications/fund/mail/FundInitiativeReplyHandler.php', 'FundInitiativeSearchEngine' => 'applications/fund/query/FundInitiativeSearchEngine.php', 'FundInitiativeTransaction' => 'applications/fund/storage/FundInitiativeTransaction.php', 'FundInitiativeTransactionComment' => 'applications/fund/storage/FundInitiativeTransactionComment.php', 'FundInitiativeTransactionQuery' => 'applications/fund/query/FundInitiativeTransactionQuery.php', 'FundInitiativeViewController' => 'applications/fund/controller/FundInitiativeViewController.php', 'FundSchemaSpec' => 'applications/fund/storage/FundSchemaSpec.php', 'HarbormasterArcLintBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcLintBuildStepImplementation.php', 'HarbormasterArcUnitBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcUnitBuildStepImplementation.php', 'HarbormasterArtifact' => 'applications/harbormaster/artifact/HarbormasterArtifact.php', 'HarbormasterAutotargetsTestCase' => 'applications/harbormaster/__tests__/HarbormasterAutotargetsTestCase.php', 'HarbormasterBuild' => 'applications/harbormaster/storage/build/HarbormasterBuild.php', 'HarbormasterBuildAbortedException' => 'applications/harbormaster/exception/HarbormasterBuildAbortedException.php', 'HarbormasterBuildActionController' => 'applications/harbormaster/controller/HarbormasterBuildActionController.php', 'HarbormasterBuildArcanistAutoplan' => 'applications/harbormaster/autoplan/HarbormasterBuildArcanistAutoplan.php', 'HarbormasterBuildArtifact' => 'applications/harbormaster/storage/build/HarbormasterBuildArtifact.php', 'HarbormasterBuildArtifactPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildArtifactPHIDType.php', 'HarbormasterBuildArtifactQuery' => 'applications/harbormaster/query/HarbormasterBuildArtifactQuery.php', 'HarbormasterBuildAutoplan' => 'applications/harbormaster/autoplan/HarbormasterBuildAutoplan.php', 'HarbormasterBuildCommand' => 'applications/harbormaster/storage/HarbormasterBuildCommand.php', 'HarbormasterBuildDependencyDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildDependencyDatasource.php', 'HarbormasterBuildEngine' => 'applications/harbormaster/engine/HarbormasterBuildEngine.php', 'HarbormasterBuildFailureException' => 'applications/harbormaster/exception/HarbormasterBuildFailureException.php', 'HarbormasterBuildGraph' => 'applications/harbormaster/engine/HarbormasterBuildGraph.php', 'HarbormasterBuildInitiatorDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildInitiatorDatasource.php', 'HarbormasterBuildLintMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildLintMessage.php', 'HarbormasterBuildListController' => 'applications/harbormaster/controller/HarbormasterBuildListController.php', 'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php', 'HarbormasterBuildLogChunk' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunk.php', 'HarbormasterBuildLogChunkIterator' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunkIterator.php', 'HarbormasterBuildLogPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php', 'HarbormasterBuildLogQuery' => 'applications/harbormaster/query/HarbormasterBuildLogQuery.php', 'HarbormasterBuildMessage' => 'applications/harbormaster/storage/HarbormasterBuildMessage.php', 'HarbormasterBuildMessageQuery' => 'applications/harbormaster/query/HarbormasterBuildMessageQuery.php', 'HarbormasterBuildPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildPHIDType.php', 'HarbormasterBuildPlan' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php', 'HarbormasterBuildPlanDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildPlanDatasource.php', 'HarbormasterBuildPlanDefaultEditCapability' => 'applications/harbormaster/capability/HarbormasterBuildPlanDefaultEditCapability.php', 'HarbormasterBuildPlanDefaultViewCapability' => 'applications/harbormaster/capability/HarbormasterBuildPlanDefaultViewCapability.php', 'HarbormasterBuildPlanEditEngine' => 'applications/harbormaster/editor/HarbormasterBuildPlanEditEngine.php', 'HarbormasterBuildPlanEditor' => 'applications/harbormaster/editor/HarbormasterBuildPlanEditor.php', 'HarbormasterBuildPlanNameNgrams' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlanNameNgrams.php', 'HarbormasterBuildPlanPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildPlanPHIDType.php', 'HarbormasterBuildPlanQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanQuery.php', 'HarbormasterBuildPlanSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildPlanSearchEngine.php', 'HarbormasterBuildPlanTransaction' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlanTransaction.php', 'HarbormasterBuildPlanTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanTransactionQuery.php', 'HarbormasterBuildQuery' => 'applications/harbormaster/query/HarbormasterBuildQuery.php', 'HarbormasterBuildRequest' => 'applications/harbormaster/engine/HarbormasterBuildRequest.php', 'HarbormasterBuildSearchConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildSearchConduitAPIMethod.php', 'HarbormasterBuildSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildSearchEngine.php', 'HarbormasterBuildStatus' => 'applications/harbormaster/constants/HarbormasterBuildStatus.php', 'HarbormasterBuildStatusDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildStatusDatasource.php', 'HarbormasterBuildStep' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStep.php', 'HarbormasterBuildStepCoreCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php', 'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php', 'HarbormasterBuildStepEditor' => 'applications/harbormaster/editor/HarbormasterBuildStepEditor.php', 'HarbormasterBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterBuildStepGroup.php', 'HarbormasterBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterBuildStepImplementation.php', 'HarbormasterBuildStepImplementationTestCase' => 'applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php', 'HarbormasterBuildStepPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php', 'HarbormasterBuildStepQuery' => 'applications/harbormaster/query/HarbormasterBuildStepQuery.php', 'HarbormasterBuildStepTransaction' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php', 'HarbormasterBuildStepTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildStepTransactionQuery.php', 'HarbormasterBuildTarget' => 'applications/harbormaster/storage/build/HarbormasterBuildTarget.php', 'HarbormasterBuildTargetPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildTargetPHIDType.php', 'HarbormasterBuildTargetQuery' => 'applications/harbormaster/query/HarbormasterBuildTargetQuery.php', 'HarbormasterBuildTransaction' => 'applications/harbormaster/storage/HarbormasterBuildTransaction.php', 'HarbormasterBuildTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php', 'HarbormasterBuildTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildTransactionQuery.php', 'HarbormasterBuildUnitMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildUnitMessage.php', 'HarbormasterBuildViewController' => 'applications/harbormaster/controller/HarbormasterBuildViewController.php', 'HarbormasterBuildWorker' => 'applications/harbormaster/worker/HarbormasterBuildWorker.php', 'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php', 'HarbormasterBuildableActionController' => 'applications/harbormaster/controller/HarbormasterBuildableActionController.php', 'HarbormasterBuildableAdapterInterface' => 'applications/harbormaster/herald/HarbormasterBuildableAdapterInterface.php', 'HarbormasterBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildableInterface.php', 'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php', 'HarbormasterBuildablePHIDType' => 'applications/harbormaster/phid/HarbormasterBuildablePHIDType.php', 'HarbormasterBuildableQuery' => 'applications/harbormaster/query/HarbormasterBuildableQuery.php', 'HarbormasterBuildableSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildableSearchEngine.php', 'HarbormasterBuildableTransaction' => 'applications/harbormaster/storage/HarbormasterBuildableTransaction.php', 'HarbormasterBuildableTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php', 'HarbormasterBuildableTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildableTransactionQuery.php', 'HarbormasterBuildableViewController' => 'applications/harbormaster/controller/HarbormasterBuildableViewController.php', 'HarbormasterBuiltinBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterBuiltinBuildStepGroup.php', 'HarbormasterCircleCIBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterCircleCIBuildStepImplementation.php', 'HarbormasterCircleCIBuildableInterface' => 'applications/harbormaster/interface/HarbormasterCircleCIBuildableInterface.php', 'HarbormasterCircleCIHookController' => 'applications/harbormaster/controller/HarbormasterCircleCIHookController.php', 'HarbormasterConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterConduitAPIMethod.php', 'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', 'HarbormasterCreateArtifactConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterCreateArtifactConduitAPIMethod.php', 'HarbormasterCreatePlansCapability' => 'applications/harbormaster/capability/HarbormasterCreatePlansCapability.php', 'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', 'HarbormasterDrydockBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterDrydockBuildStepGroup.php', 'HarbormasterDrydockCommandBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterDrydockCommandBuildStepImplementation.php', 'HarbormasterDrydockLeaseArtifact' => 'applications/harbormaster/artifact/HarbormasterDrydockLeaseArtifact.php', 'HarbormasterExecFuture' => 'applications/harbormaster/future/HarbormasterExecFuture.php', 'HarbormasterExternalBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterExternalBuildStepGroup.php', 'HarbormasterFileArtifact' => 'applications/harbormaster/artifact/HarbormasterFileArtifact.php', 'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php', 'HarbormasterHostArtifact' => 'applications/harbormaster/artifact/HarbormasterHostArtifact.php', 'HarbormasterLeaseWorkingCopyBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php', 'HarbormasterLintMessagesController' => 'applications/harbormaster/controller/HarbormasterLintMessagesController.php', 'HarbormasterLintPropertyView' => 'applications/harbormaster/view/HarbormasterLintPropertyView.php', 'HarbormasterManagementArchiveLogsWorkflow' => 'applications/harbormaster/management/HarbormasterManagementArchiveLogsWorkflow.php', 'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php', 'HarbormasterManagementRestartWorkflow' => 'applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php', 'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php', 'HarbormasterManagementWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWorkflow.php', 'HarbormasterMessageType' => 'applications/harbormaster/engine/HarbormasterMessageType.php', 'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', 'HarbormasterOtherBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterOtherBuildStepGroup.php', 'HarbormasterPlanController' => 'applications/harbormaster/controller/HarbormasterPlanController.php', 'HarbormasterPlanDisableController' => 'applications/harbormaster/controller/HarbormasterPlanDisableController.php', 'HarbormasterPlanEditController' => 'applications/harbormaster/controller/HarbormasterPlanEditController.php', 'HarbormasterPlanListController' => 'applications/harbormaster/controller/HarbormasterPlanListController.php', 'HarbormasterPlanRunController' => 'applications/harbormaster/controller/HarbormasterPlanRunController.php', 'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php', 'HarbormasterPrototypeBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterPrototypeBuildStepGroup.php', 'HarbormasterPublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php', 'HarbormasterQueryAutotargetsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryAutotargetsConduitAPIMethod.php', 'HarbormasterQueryBuildablesConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php', 'HarbormasterQueryBuildsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php', 'HarbormasterQueryBuildsSearchEngineAttachment' => 'applications/harbormaster/engineextension/HarbormasterQueryBuildsSearchEngineAttachment.php', 'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php', 'HarbormasterRunBuildPlansHeraldAction' => 'applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php', 'HarbormasterSchemaSpec' => 'applications/harbormaster/storage/HarbormasterSchemaSpec.php', 'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php', 'HarbormasterSendMessageConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php', 'HarbormasterSleepBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterSleepBuildStepImplementation.php', 'HarbormasterStepAddController' => 'applications/harbormaster/controller/HarbormasterStepAddController.php', 'HarbormasterStepDeleteController' => 'applications/harbormaster/controller/HarbormasterStepDeleteController.php', 'HarbormasterStepEditController' => 'applications/harbormaster/controller/HarbormasterStepEditController.php', 'HarbormasterStepViewController' => 'applications/harbormaster/controller/HarbormasterStepViewController.php', 'HarbormasterTargetEngine' => 'applications/harbormaster/engine/HarbormasterTargetEngine.php', 'HarbormasterTargetWorker' => 'applications/harbormaster/worker/HarbormasterTargetWorker.php', 'HarbormasterTestBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterTestBuildStepGroup.php', 'HarbormasterThrowExceptionBuildStep' => 'applications/harbormaster/step/HarbormasterThrowExceptionBuildStep.php', 'HarbormasterUIEventListener' => 'applications/harbormaster/event/HarbormasterUIEventListener.php', 'HarbormasterURIArtifact' => 'applications/harbormaster/artifact/HarbormasterURIArtifact.php', 'HarbormasterUnitMessageListController' => 'applications/harbormaster/controller/HarbormasterUnitMessageListController.php', 'HarbormasterUnitMessageViewController' => 'applications/harbormaster/controller/HarbormasterUnitMessageViewController.php', 'HarbormasterUnitPropertyView' => 'applications/harbormaster/view/HarbormasterUnitPropertyView.php', 'HarbormasterUnitStatus' => 'applications/harbormaster/constants/HarbormasterUnitStatus.php', 'HarbormasterUnitSummaryView' => 'applications/harbormaster/view/HarbormasterUnitSummaryView.php', 'HarbormasterUploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php', 'HarbormasterWaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php', 'HarbormasterWorker' => 'applications/harbormaster/worker/HarbormasterWorker.php', 'HarbormasterWorkingCopyArtifact' => 'applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php', 'HeraldAction' => 'applications/herald/action/HeraldAction.php', 'HeraldActionGroup' => 'applications/herald/action/HeraldActionGroup.php', 'HeraldActionRecord' => 'applications/herald/storage/HeraldActionRecord.php', 'HeraldAdapter' => 'applications/herald/adapter/HeraldAdapter.php', 'HeraldAlwaysField' => 'applications/herald/field/HeraldAlwaysField.php', 'HeraldAnotherRuleField' => 'applications/herald/field/HeraldAnotherRuleField.php', 'HeraldApplicationActionGroup' => 'applications/herald/action/HeraldApplicationActionGroup.php', 'HeraldApplyTranscript' => 'applications/herald/storage/transcript/HeraldApplyTranscript.php', 'HeraldBasicFieldGroup' => 'applications/herald/field/HeraldBasicFieldGroup.php', 'HeraldCommitAdapter' => 'applications/diffusion/herald/HeraldCommitAdapter.php', 'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php', 'HeraldConditionTranscript' => 'applications/herald/storage/transcript/HeraldConditionTranscript.php', 'HeraldContentSourceField' => 'applications/herald/field/HeraldContentSourceField.php', 'HeraldController' => 'applications/herald/controller/HeraldController.php', 'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php', 'HeraldDifferentialAdapter' => 'applications/differential/herald/HeraldDifferentialAdapter.php', 'HeraldDifferentialDiffAdapter' => 'applications/differential/herald/HeraldDifferentialDiffAdapter.php', 'HeraldDifferentialRevisionAdapter' => 'applications/differential/herald/HeraldDifferentialRevisionAdapter.php', 'HeraldDisableController' => 'applications/herald/controller/HeraldDisableController.php', 'HeraldDoNothingAction' => 'applications/herald/action/HeraldDoNothingAction.php', 'HeraldEditFieldGroup' => 'applications/herald/field/HeraldEditFieldGroup.php', 'HeraldEffect' => 'applications/herald/engine/HeraldEffect.php', 'HeraldEmptyFieldValue' => 'applications/herald/value/HeraldEmptyFieldValue.php', 'HeraldEngine' => 'applications/herald/engine/HeraldEngine.php', 'HeraldExactProjectsField' => 'applications/project/herald/HeraldExactProjectsField.php', 'HeraldField' => 'applications/herald/field/HeraldField.php', 'HeraldFieldGroup' => 'applications/herald/field/HeraldFieldGroup.php', 'HeraldFieldTestCase' => 'applications/herald/field/__tests__/HeraldFieldTestCase.php', 'HeraldFieldValue' => 'applications/herald/value/HeraldFieldValue.php', 'HeraldGroup' => 'applications/herald/group/HeraldGroup.php', 'HeraldInvalidActionException' => 'applications/herald/engine/exception/HeraldInvalidActionException.php', 'HeraldInvalidConditionException' => 'applications/herald/engine/exception/HeraldInvalidConditionException.php', 'HeraldManageGlobalRulesCapability' => 'applications/herald/capability/HeraldManageGlobalRulesCapability.php', 'HeraldManiphestTaskAdapter' => 'applications/maniphest/herald/HeraldManiphestTaskAdapter.php', 'HeraldNewController' => 'applications/herald/controller/HeraldNewController.php', 'HeraldNewObjectField' => 'applications/herald/field/HeraldNewObjectField.php', 'HeraldNotifyActionGroup' => 'applications/herald/action/HeraldNotifyActionGroup.php', 'HeraldObjectTranscript' => 'applications/herald/storage/transcript/HeraldObjectTranscript.php', 'HeraldPhameBlogAdapter' => 'applications/phame/herald/HeraldPhameBlogAdapter.php', 'HeraldPhamePostAdapter' => 'applications/phame/herald/HeraldPhamePostAdapter.php', 'HeraldPholioMockAdapter' => 'applications/pholio/herald/HeraldPholioMockAdapter.php', 'HeraldPonderQuestionAdapter' => 'applications/ponder/herald/HeraldPonderQuestionAdapter.php', 'HeraldPreCommitAdapter' => 'applications/diffusion/herald/HeraldPreCommitAdapter.php', 'HeraldPreCommitContentAdapter' => 'applications/diffusion/herald/HeraldPreCommitContentAdapter.php', 'HeraldPreCommitRefAdapter' => 'applications/diffusion/herald/HeraldPreCommitRefAdapter.php', 'HeraldPreventActionGroup' => 'applications/herald/action/HeraldPreventActionGroup.php', 'HeraldProjectsField' => 'applications/project/herald/HeraldProjectsField.php', 'HeraldRecursiveConditionsException' => 'applications/herald/engine/exception/HeraldRecursiveConditionsException.php', 'HeraldRelatedFieldGroup' => 'applications/herald/field/HeraldRelatedFieldGroup.php', 'HeraldRemarkupRule' => 'applications/herald/remarkup/HeraldRemarkupRule.php', 'HeraldRepetitionPolicyConfig' => 'applications/herald/config/HeraldRepetitionPolicyConfig.php', 'HeraldRule' => 'applications/herald/storage/HeraldRule.php', 'HeraldRuleController' => 'applications/herald/controller/HeraldRuleController.php', 'HeraldRuleDatasource' => 'applications/herald/typeahead/HeraldRuleDatasource.php', 'HeraldRuleEditor' => 'applications/herald/editor/HeraldRuleEditor.php', 'HeraldRuleListController' => 'applications/herald/controller/HeraldRuleListController.php', 'HeraldRulePHIDType' => 'applications/herald/phid/HeraldRulePHIDType.php', 'HeraldRuleQuery' => 'applications/herald/query/HeraldRuleQuery.php', 'HeraldRuleSearchEngine' => 'applications/herald/query/HeraldRuleSearchEngine.php', 'HeraldRuleSerializer' => 'applications/herald/editor/HeraldRuleSerializer.php', 'HeraldRuleTestCase' => 'applications/herald/storage/__tests__/HeraldRuleTestCase.php', 'HeraldRuleTransaction' => 'applications/herald/storage/HeraldRuleTransaction.php', 'HeraldRuleTransactionComment' => 'applications/herald/storage/HeraldRuleTransactionComment.php', 'HeraldRuleTranscript' => 'applications/herald/storage/transcript/HeraldRuleTranscript.php', 'HeraldRuleTypeConfig' => 'applications/herald/config/HeraldRuleTypeConfig.php', 'HeraldRuleViewController' => 'applications/herald/controller/HeraldRuleViewController.php', 'HeraldSchemaSpec' => 'applications/herald/storage/HeraldSchemaSpec.php', 'HeraldSelectFieldValue' => 'applications/herald/value/HeraldSelectFieldValue.php', 'HeraldSpaceField' => 'applications/spaces/herald/HeraldSpaceField.php', 'HeraldSubscribersField' => 'applications/subscriptions/herald/HeraldSubscribersField.php', 'HeraldSupportActionGroup' => 'applications/herald/action/HeraldSupportActionGroup.php', 'HeraldSupportFieldGroup' => 'applications/herald/field/HeraldSupportFieldGroup.php', 'HeraldTestConsoleController' => 'applications/herald/controller/HeraldTestConsoleController.php', 'HeraldTextFieldValue' => 'applications/herald/value/HeraldTextFieldValue.php', 'HeraldTokenizerFieldValue' => 'applications/herald/value/HeraldTokenizerFieldValue.php', 'HeraldTransactionQuery' => 'applications/herald/query/HeraldTransactionQuery.php', 'HeraldTranscript' => 'applications/herald/storage/transcript/HeraldTranscript.php', 'HeraldTranscriptController' => 'applications/herald/controller/HeraldTranscriptController.php', 'HeraldTranscriptDestructionEngineExtension' => 'applications/herald/engineextension/HeraldTranscriptDestructionEngineExtension.php', 'HeraldTranscriptGarbageCollector' => 'applications/herald/garbagecollector/HeraldTranscriptGarbageCollector.php', 'HeraldTranscriptListController' => 'applications/herald/controller/HeraldTranscriptListController.php', 'HeraldTranscriptPHIDType' => 'applications/herald/phid/HeraldTranscriptPHIDType.php', 'HeraldTranscriptQuery' => 'applications/herald/query/HeraldTranscriptQuery.php', 'HeraldTranscriptSearchEngine' => 'applications/herald/query/HeraldTranscriptSearchEngine.php', 'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php', 'HeraldUtilityActionGroup' => 'applications/herald/action/HeraldUtilityActionGroup.php', 'Javelin' => 'infrastructure/javelin/Javelin.php', 'JavelinReactorUIExample' => 'applications/uiexample/examples/JavelinReactorUIExample.php', 'JavelinUIExample' => 'applications/uiexample/examples/JavelinUIExample.php', 'JavelinViewExampleServerView' => 'applications/uiexample/examples/JavelinViewExampleServerView.php', 'JavelinViewUIExample' => 'applications/uiexample/examples/JavelinViewUIExample.php', 'LegalpadController' => 'applications/legalpad/controller/LegalpadController.php', 'LegalpadCreateDocumentsCapability' => 'applications/legalpad/capability/LegalpadCreateDocumentsCapability.php', 'LegalpadDAO' => 'applications/legalpad/storage/LegalpadDAO.php', 'LegalpadDefaultEditCapability' => 'applications/legalpad/capability/LegalpadDefaultEditCapability.php', 'LegalpadDefaultViewCapability' => 'applications/legalpad/capability/LegalpadDefaultViewCapability.php', 'LegalpadDocument' => 'applications/legalpad/storage/LegalpadDocument.php', 'LegalpadDocumentBody' => 'applications/legalpad/storage/LegalpadDocumentBody.php', 'LegalpadDocumentCommentController' => 'applications/legalpad/controller/LegalpadDocumentCommentController.php', 'LegalpadDocumentDatasource' => 'applications/legalpad/typeahead/LegalpadDocumentDatasource.php', 'LegalpadDocumentDoneController' => 'applications/legalpad/controller/LegalpadDocumentDoneController.php', 'LegalpadDocumentEditController' => 'applications/legalpad/controller/LegalpadDocumentEditController.php', 'LegalpadDocumentEditor' => 'applications/legalpad/editor/LegalpadDocumentEditor.php', 'LegalpadDocumentListController' => 'applications/legalpad/controller/LegalpadDocumentListController.php', 'LegalpadDocumentManageController' => 'applications/legalpad/controller/LegalpadDocumentManageController.php', 'LegalpadDocumentQuery' => 'applications/legalpad/query/LegalpadDocumentQuery.php', 'LegalpadDocumentRemarkupRule' => 'applications/legalpad/remarkup/LegalpadDocumentRemarkupRule.php', 'LegalpadDocumentSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSearchEngine.php', 'LegalpadDocumentSignController' => 'applications/legalpad/controller/LegalpadDocumentSignController.php', 'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php', 'LegalpadDocumentSignatureAddController' => 'applications/legalpad/controller/LegalpadDocumentSignatureAddController.php', 'LegalpadDocumentSignatureListController' => 'applications/legalpad/controller/LegalpadDocumentSignatureListController.php', 'LegalpadDocumentSignatureQuery' => 'applications/legalpad/query/LegalpadDocumentSignatureQuery.php', 'LegalpadDocumentSignatureSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php', 'LegalpadDocumentSignatureVerificationController' => 'applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php', 'LegalpadDocumentSignatureViewController' => 'applications/legalpad/controller/LegalpadDocumentSignatureViewController.php', 'LegalpadMailReceiver' => 'applications/legalpad/mail/LegalpadMailReceiver.php', 'LegalpadObjectNeedsSignatureEdgeType' => 'applications/legalpad/edge/LegalpadObjectNeedsSignatureEdgeType.php', 'LegalpadReplyHandler' => 'applications/legalpad/mail/LegalpadReplyHandler.php', 'LegalpadRequireSignatureHeraldAction' => 'applications/legalpad/herald/LegalpadRequireSignatureHeraldAction.php', 'LegalpadSchemaSpec' => 'applications/legalpad/storage/LegalpadSchemaSpec.php', 'LegalpadSignatureNeededByObjectEdgeType' => 'applications/legalpad/edge/LegalpadSignatureNeededByObjectEdgeType.php', 'LegalpadTransaction' => 'applications/legalpad/storage/LegalpadTransaction.php', 'LegalpadTransactionComment' => 'applications/legalpad/storage/LegalpadTransactionComment.php', 'LegalpadTransactionQuery' => 'applications/legalpad/query/LegalpadTransactionQuery.php', 'LegalpadTransactionView' => 'applications/legalpad/view/LegalpadTransactionView.php', 'LiskChunkTestCase' => 'infrastructure/storage/lisk/__tests__/LiskChunkTestCase.php', 'LiskDAO' => 'infrastructure/storage/lisk/LiskDAO.php', 'LiskDAOSet' => 'infrastructure/storage/lisk/LiskDAOSet.php', 'LiskDAOTestCase' => 'infrastructure/storage/lisk/__tests__/LiskDAOTestCase.php', 'LiskEphemeralObjectException' => 'infrastructure/storage/lisk/LiskEphemeralObjectException.php', 'LiskFixtureTestCase' => 'infrastructure/storage/lisk/__tests__/LiskFixtureTestCase.php', 'LiskIsolationTestCase' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestCase.php', 'LiskIsolationTestDAO' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestDAO.php', 'LiskIsolationTestDAOException' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestDAOException.php', 'LiskMigrationIterator' => 'infrastructure/storage/lisk/LiskMigrationIterator.php', 'LiskRawMigrationIterator' => 'infrastructure/storage/lisk/LiskRawMigrationIterator.php', 'MacroConduitAPIMethod' => 'applications/macro/conduit/MacroConduitAPIMethod.php', 'MacroCreateMemeConduitAPIMethod' => 'applications/macro/conduit/MacroCreateMemeConduitAPIMethod.php', 'MacroQueryConduitAPIMethod' => 'applications/macro/conduit/MacroQueryConduitAPIMethod.php', 'ManiphestAssignEmailCommand' => 'applications/maniphest/command/ManiphestAssignEmailCommand.php', 'ManiphestAssigneeDatasource' => 'applications/maniphest/typeahead/ManiphestAssigneeDatasource.php', 'ManiphestBatchEditController' => 'applications/maniphest/controller/ManiphestBatchEditController.php', 'ManiphestBulkEditCapability' => 'applications/maniphest/capability/ManiphestBulkEditCapability.php', 'ManiphestClaimEmailCommand' => 'applications/maniphest/command/ManiphestClaimEmailCommand.php', 'ManiphestCloseEmailCommand' => 'applications/maniphest/command/ManiphestCloseEmailCommand.php', 'ManiphestConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestConduitAPIMethod.php', 'ManiphestConfiguredCustomField' => 'applications/maniphest/field/ManiphestConfiguredCustomField.php', 'ManiphestConstants' => 'applications/maniphest/constants/ManiphestConstants.php', 'ManiphestController' => 'applications/maniphest/controller/ManiphestController.php', 'ManiphestCreateMailReceiver' => 'applications/maniphest/mail/ManiphestCreateMailReceiver.php', 'ManiphestCreateTaskConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestCreateTaskConduitAPIMethod.php', 'ManiphestCustomField' => 'applications/maniphest/field/ManiphestCustomField.php', 'ManiphestCustomFieldNumericIndex' => 'applications/maniphest/storage/ManiphestCustomFieldNumericIndex.php', 'ManiphestCustomFieldStatusParser' => 'applications/maniphest/field/parser/ManiphestCustomFieldStatusParser.php', 'ManiphestCustomFieldStatusParserTestCase' => 'applications/maniphest/field/parser/__tests__/ManiphestCustomFieldStatusParserTestCase.php', 'ManiphestCustomFieldStorage' => 'applications/maniphest/storage/ManiphestCustomFieldStorage.php', 'ManiphestCustomFieldStringIndex' => 'applications/maniphest/storage/ManiphestCustomFieldStringIndex.php', 'ManiphestDAO' => 'applications/maniphest/storage/ManiphestDAO.php', 'ManiphestDefaultEditCapability' => 'applications/maniphest/capability/ManiphestDefaultEditCapability.php', 'ManiphestDefaultViewCapability' => 'applications/maniphest/capability/ManiphestDefaultViewCapability.php', 'ManiphestEditAssignCapability' => 'applications/maniphest/capability/ManiphestEditAssignCapability.php', 'ManiphestEditConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestEditConduitAPIMethod.php', 'ManiphestEditEngine' => 'applications/maniphest/editor/ManiphestEditEngine.php', 'ManiphestEditPoliciesCapability' => 'applications/maniphest/capability/ManiphestEditPoliciesCapability.php', 'ManiphestEditPriorityCapability' => 'applications/maniphest/capability/ManiphestEditPriorityCapability.php', 'ManiphestEditProjectsCapability' => 'applications/maniphest/capability/ManiphestEditProjectsCapability.php', 'ManiphestEditStatusCapability' => 'applications/maniphest/capability/ManiphestEditStatusCapability.php', 'ManiphestEmailCommand' => 'applications/maniphest/command/ManiphestEmailCommand.php', 'ManiphestExcelDefaultFormat' => 'applications/maniphest/export/ManiphestExcelDefaultFormat.php', 'ManiphestExcelFormat' => 'applications/maniphest/export/ManiphestExcelFormat.php', 'ManiphestExcelFormatTestCase' => 'applications/maniphest/export/__tests__/ManiphestExcelFormatTestCase.php', 'ManiphestExportController' => 'applications/maniphest/controller/ManiphestExportController.php', 'ManiphestGetTaskTransactionsConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php', 'ManiphestHovercardEngineExtension' => 'applications/maniphest/engineextension/ManiphestHovercardEngineExtension.php', 'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php', 'ManiphestNameIndex' => 'applications/maniphest/storage/ManiphestNameIndex.php', 'ManiphestPointsConfigOptionType' => 'applications/maniphest/config/ManiphestPointsConfigOptionType.php', 'ManiphestPriorityConfigOptionType' => 'applications/maniphest/config/ManiphestPriorityConfigOptionType.php', 'ManiphestPriorityEmailCommand' => 'applications/maniphest/command/ManiphestPriorityEmailCommand.php', 'ManiphestProjectNameFulltextEngineExtension' => 'applications/maniphest/engineextension/ManiphestProjectNameFulltextEngineExtension.php', 'ManiphestQueryConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php', 'ManiphestQueryStatusesConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php', 'ManiphestRemarkupRule' => 'applications/maniphest/remarkup/ManiphestRemarkupRule.php', 'ManiphestReplyHandler' => 'applications/maniphest/mail/ManiphestReplyHandler.php', 'ManiphestReportController' => 'applications/maniphest/controller/ManiphestReportController.php', 'ManiphestSchemaSpec' => 'applications/maniphest/storage/ManiphestSchemaSpec.php', 'ManiphestSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestSearchConduitAPIMethod.php', 'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php', 'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', 'ManiphestTaskAssignHeraldAction' => 'applications/maniphest/herald/ManiphestTaskAssignHeraldAction.php', 'ManiphestTaskAssignOtherHeraldAction' => 'applications/maniphest/herald/ManiphestTaskAssignOtherHeraldAction.php', 'ManiphestTaskAssignSelfHeraldAction' => 'applications/maniphest/herald/ManiphestTaskAssignSelfHeraldAction.php', 'ManiphestTaskAssigneeHeraldField' => 'applications/maniphest/herald/ManiphestTaskAssigneeHeraldField.php', 'ManiphestTaskAuthorHeraldField' => 'applications/maniphest/herald/ManiphestTaskAuthorHeraldField.php', 'ManiphestTaskAuthorPolicyRule' => 'applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php', 'ManiphestTaskCloseAsDuplicateRelationship' => 'applications/maniphest/relationship/ManiphestTaskCloseAsDuplicateRelationship.php', 'ManiphestTaskClosedStatusDatasource' => 'applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php', 'ManiphestTaskDependedOnByTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskDependedOnByTaskEdgeType.php', 'ManiphestTaskDependsOnTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskDependsOnTaskEdgeType.php', 'ManiphestTaskDescriptionHeraldField' => 'applications/maniphest/herald/ManiphestTaskDescriptionHeraldField.php', 'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php', 'ManiphestTaskEditBulkJobType' => 'applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php', 'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php', 'ManiphestTaskFulltextEngine' => 'applications/maniphest/search/ManiphestTaskFulltextEngine.php', 'ManiphestTaskGraph' => 'infrastructure/graph/ManiphestTaskGraph.php', 'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php', 'ManiphestTaskHasCommitRelationship' => 'applications/maniphest/relationship/ManiphestTaskHasCommitRelationship.php', 'ManiphestTaskHasDuplicateTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasDuplicateTaskEdgeType.php', 'ManiphestTaskHasMockEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasMockEdgeType.php', 'ManiphestTaskHasMockRelationship' => 'applications/maniphest/relationship/ManiphestTaskHasMockRelationship.php', 'ManiphestTaskHasParentRelationship' => 'applications/maniphest/relationship/ManiphestTaskHasParentRelationship.php', 'ManiphestTaskHasRevisionEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasRevisionEdgeType.php', 'ManiphestTaskHasRevisionRelationship' => 'applications/maniphest/relationship/ManiphestTaskHasRevisionRelationship.php', 'ManiphestTaskHasSubtaskRelationship' => 'applications/maniphest/relationship/ManiphestTaskHasSubtaskRelationship.php', 'ManiphestTaskHeraldField' => 'applications/maniphest/herald/ManiphestTaskHeraldField.php', 'ManiphestTaskHeraldFieldGroup' => 'applications/maniphest/herald/ManiphestTaskHeraldFieldGroup.php', 'ManiphestTaskIsDuplicateOfTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskIsDuplicateOfTaskEdgeType.php', 'ManiphestTaskListController' => 'applications/maniphest/controller/ManiphestTaskListController.php', 'ManiphestTaskListHTTPParameterType' => 'applications/maniphest/httpparametertype/ManiphestTaskListHTTPParameterType.php', 'ManiphestTaskListView' => 'applications/maniphest/view/ManiphestTaskListView.php', 'ManiphestTaskMailReceiver' => 'applications/maniphest/mail/ManiphestTaskMailReceiver.php', 'ManiphestTaskMergeInRelationship' => 'applications/maniphest/relationship/ManiphestTaskMergeInRelationship.php', 'ManiphestTaskOpenStatusDatasource' => 'applications/maniphest/typeahead/ManiphestTaskOpenStatusDatasource.php', 'ManiphestTaskPHIDResolver' => 'applications/maniphest/httpparametertype/ManiphestTaskPHIDResolver.php', 'ManiphestTaskPHIDType' => 'applications/maniphest/phid/ManiphestTaskPHIDType.php', 'ManiphestTaskPoints' => 'applications/maniphest/constants/ManiphestTaskPoints.php', 'ManiphestTaskPriority' => 'applications/maniphest/constants/ManiphestTaskPriority.php', 'ManiphestTaskPriorityDatasource' => 'applications/maniphest/typeahead/ManiphestTaskPriorityDatasource.php', 'ManiphestTaskPriorityHeraldAction' => 'applications/maniphest/herald/ManiphestTaskPriorityHeraldAction.php', 'ManiphestTaskPriorityHeraldField' => 'applications/maniphest/herald/ManiphestTaskPriorityHeraldField.php', 'ManiphestTaskQuery' => 'applications/maniphest/query/ManiphestTaskQuery.php', 'ManiphestTaskRelationship' => 'applications/maniphest/relationship/ManiphestTaskRelationship.php', 'ManiphestTaskRelationshipSource' => 'applications/search/relationship/ManiphestTaskRelationshipSource.php', 'ManiphestTaskResultListView' => 'applications/maniphest/view/ManiphestTaskResultListView.php', 'ManiphestTaskSearchEngine' => 'applications/maniphest/query/ManiphestTaskSearchEngine.php', 'ManiphestTaskStatus' => 'applications/maniphest/constants/ManiphestTaskStatus.php', 'ManiphestTaskStatusDatasource' => 'applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php', 'ManiphestTaskStatusFunctionDatasource' => 'applications/maniphest/typeahead/ManiphestTaskStatusFunctionDatasource.php', 'ManiphestTaskStatusHeraldAction' => 'applications/maniphest/herald/ManiphestTaskStatusHeraldAction.php', 'ManiphestTaskStatusHeraldField' => 'applications/maniphest/herald/ManiphestTaskStatusHeraldField.php', 'ManiphestTaskStatusTestCase' => 'applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php', 'ManiphestTaskTestCase' => 'applications/maniphest/__tests__/ManiphestTaskTestCase.php', 'ManiphestTaskTitleHeraldField' => 'applications/maniphest/herald/ManiphestTaskTitleHeraldField.php', 'ManiphestTransaction' => 'applications/maniphest/storage/ManiphestTransaction.php', 'ManiphestTransactionComment' => 'applications/maniphest/storage/ManiphestTransactionComment.php', 'ManiphestTransactionEditor' => 'applications/maniphest/editor/ManiphestTransactionEditor.php', 'ManiphestTransactionQuery' => 'applications/maniphest/query/ManiphestTransactionQuery.php', 'ManiphestUpdateConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestUpdateConduitAPIMethod.php', 'ManiphestView' => 'applications/maniphest/view/ManiphestView.php', 'MetaMTAEmailTransactionCommand' => 'applications/metamta/command/MetaMTAEmailTransactionCommand.php', 'MetaMTAEmailTransactionCommandTestCase' => 'applications/metamta/command/__tests__/MetaMTAEmailTransactionCommandTestCase.php', 'MetaMTAMailReceivedGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailReceivedGarbageCollector.php', 'MetaMTAMailSentGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailSentGarbageCollector.php', 'MetaMTAReceivedMailStatus' => 'applications/metamta/constants/MetaMTAReceivedMailStatus.php', 'MultimeterContext' => 'applications/multimeter/storage/MultimeterContext.php', 'MultimeterControl' => 'applications/multimeter/data/MultimeterControl.php', 'MultimeterController' => 'applications/multimeter/controller/MultimeterController.php', 'MultimeterDAO' => 'applications/multimeter/storage/MultimeterDAO.php', 'MultimeterDimension' => 'applications/multimeter/storage/MultimeterDimension.php', 'MultimeterEvent' => 'applications/multimeter/storage/MultimeterEvent.php', 'MultimeterEventGarbageCollector' => 'applications/multimeter/garbagecollector/MultimeterEventGarbageCollector.php', 'MultimeterHost' => 'applications/multimeter/storage/MultimeterHost.php', 'MultimeterLabel' => 'applications/multimeter/storage/MultimeterLabel.php', 'MultimeterSampleController' => 'applications/multimeter/controller/MultimeterSampleController.php', 'MultimeterViewer' => 'applications/multimeter/storage/MultimeterViewer.php', 'NuanceConduitAPIMethod' => 'applications/nuance/conduit/NuanceConduitAPIMethod.php', 'NuanceConsoleController' => 'applications/nuance/controller/NuanceConsoleController.php', 'NuanceContentSource' => 'applications/nuance/contentsource/NuanceContentSource.php', 'NuanceController' => 'applications/nuance/controller/NuanceController.php', 'NuanceDAO' => 'applications/nuance/storage/NuanceDAO.php', 'NuanceGitHubEventItemType' => 'applications/nuance/item/NuanceGitHubEventItemType.php', 'NuanceGitHubImportCursor' => 'applications/nuance/cursor/NuanceGitHubImportCursor.php', 'NuanceGitHubIssuesImportCursor' => 'applications/nuance/cursor/NuanceGitHubIssuesImportCursor.php', 'NuanceGitHubRawEvent' => 'applications/nuance/github/NuanceGitHubRawEvent.php', 'NuanceGitHubRawEventTestCase' => 'applications/nuance/github/__tests__/NuanceGitHubRawEventTestCase.php', 'NuanceGitHubRepositoryImportCursor' => 'applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php', 'NuanceGitHubRepositorySourceDefinition' => 'applications/nuance/source/NuanceGitHubRepositorySourceDefinition.php', 'NuanceImportCursor' => 'applications/nuance/cursor/NuanceImportCursor.php', 'NuanceImportCursorData' => 'applications/nuance/storage/NuanceImportCursorData.php', 'NuanceImportCursorDataQuery' => 'applications/nuance/query/NuanceImportCursorDataQuery.php', 'NuanceImportCursorPHIDType' => 'applications/nuance/phid/NuanceImportCursorPHIDType.php', 'NuanceItem' => 'applications/nuance/storage/NuanceItem.php', 'NuanceItemActionController' => 'applications/nuance/controller/NuanceItemActionController.php', 'NuanceItemCommand' => 'applications/nuance/storage/NuanceItemCommand.php', 'NuanceItemCommandQuery' => 'applications/nuance/query/NuanceItemCommandQuery.php', 'NuanceItemController' => 'applications/nuance/controller/NuanceItemController.php', 'NuanceItemEditor' => 'applications/nuance/editor/NuanceItemEditor.php', 'NuanceItemListController' => 'applications/nuance/controller/NuanceItemListController.php', 'NuanceItemManageController' => 'applications/nuance/controller/NuanceItemManageController.php', 'NuanceItemPHIDType' => 'applications/nuance/phid/NuanceItemPHIDType.php', 'NuanceItemQuery' => 'applications/nuance/query/NuanceItemQuery.php', 'NuanceItemSearchEngine' => 'applications/nuance/query/NuanceItemSearchEngine.php', 'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php', 'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php', 'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php', 'NuanceItemType' => 'applications/nuance/item/NuanceItemType.php', 'NuanceItemUpdateWorker' => 'applications/nuance/worker/NuanceItemUpdateWorker.php', 'NuanceItemViewController' => 'applications/nuance/controller/NuanceItemViewController.php', 'NuanceManagementImportWorkflow' => 'applications/nuance/management/NuanceManagementImportWorkflow.php', 'NuanceManagementUpdateWorkflow' => 'applications/nuance/management/NuanceManagementUpdateWorkflow.php', 'NuanceManagementWorkflow' => 'applications/nuance/management/NuanceManagementWorkflow.php', 'NuancePhabricatorFormSourceDefinition' => 'applications/nuance/source/NuancePhabricatorFormSourceDefinition.php', 'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php', 'NuanceQueue' => 'applications/nuance/storage/NuanceQueue.php', 'NuanceQueueController' => 'applications/nuance/controller/NuanceQueueController.php', 'NuanceQueueDatasource' => 'applications/nuance/typeahead/NuanceQueueDatasource.php', 'NuanceQueueEditController' => 'applications/nuance/controller/NuanceQueueEditController.php', 'NuanceQueueEditEngine' => 'applications/nuance/editor/NuanceQueueEditEngine.php', 'NuanceQueueEditor' => 'applications/nuance/editor/NuanceQueueEditor.php', 'NuanceQueueListController' => 'applications/nuance/controller/NuanceQueueListController.php', 'NuanceQueuePHIDType' => 'applications/nuance/phid/NuanceQueuePHIDType.php', 'NuanceQueueQuery' => 'applications/nuance/query/NuanceQueueQuery.php', 'NuanceQueueSearchEngine' => 'applications/nuance/query/NuanceQueueSearchEngine.php', 'NuanceQueueTransaction' => 'applications/nuance/storage/NuanceQueueTransaction.php', 'NuanceQueueTransactionComment' => 'applications/nuance/storage/NuanceQueueTransactionComment.php', 'NuanceQueueTransactionQuery' => 'applications/nuance/query/NuanceQueueTransactionQuery.php', 'NuanceQueueViewController' => 'applications/nuance/controller/NuanceQueueViewController.php', 'NuanceSchemaSpec' => 'applications/nuance/storage/NuanceSchemaSpec.php', 'NuanceSource' => 'applications/nuance/storage/NuanceSource.php', 'NuanceSourceActionController' => 'applications/nuance/controller/NuanceSourceActionController.php', 'NuanceSourceController' => 'applications/nuance/controller/NuanceSourceController.php', 'NuanceSourceDefaultEditCapability' => 'applications/nuance/capability/NuanceSourceDefaultEditCapability.php', 'NuanceSourceDefaultViewCapability' => 'applications/nuance/capability/NuanceSourceDefaultViewCapability.php', 'NuanceSourceDefinition' => 'applications/nuance/source/NuanceSourceDefinition.php', 'NuanceSourceDefinitionTestCase' => 'applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php', 'NuanceSourceEditController' => 'applications/nuance/controller/NuanceSourceEditController.php', 'NuanceSourceEditEngine' => 'applications/nuance/editor/NuanceSourceEditEngine.php', 'NuanceSourceEditor' => 'applications/nuance/editor/NuanceSourceEditor.php', 'NuanceSourceListController' => 'applications/nuance/controller/NuanceSourceListController.php', 'NuanceSourceManageCapability' => 'applications/nuance/capability/NuanceSourceManageCapability.php', 'NuanceSourceNameNgrams' => 'applications/nuance/storage/NuanceSourceNameNgrams.php', 'NuanceSourcePHIDType' => 'applications/nuance/phid/NuanceSourcePHIDType.php', 'NuanceSourceQuery' => 'applications/nuance/query/NuanceSourceQuery.php', 'NuanceSourceSearchEngine' => 'applications/nuance/query/NuanceSourceSearchEngine.php', 'NuanceSourceTransaction' => 'applications/nuance/storage/NuanceSourceTransaction.php', 'NuanceSourceTransactionComment' => 'applications/nuance/storage/NuanceSourceTransactionComment.php', 'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php', 'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php', 'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php', 'NuanceWorker' => 'applications/nuance/worker/NuanceWorker.php', 'OwnersConduitAPIMethod' => 'applications/owners/conduit/OwnersConduitAPIMethod.php', 'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php', 'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php', 'OwnersQueryConduitAPIMethod' => 'applications/owners/conduit/OwnersQueryConduitAPIMethod.php', 'OwnersSearchConduitAPIMethod' => 'applications/owners/conduit/OwnersSearchConduitAPIMethod.php', 'PHIDConduitAPIMethod' => 'applications/phid/conduit/PHIDConduitAPIMethod.php', 'PHIDInfoConduitAPIMethod' => 'applications/phid/conduit/PHIDInfoConduitAPIMethod.php', 'PHIDLookupConduitAPIMethod' => 'applications/phid/conduit/PHIDLookupConduitAPIMethod.php', 'PHIDQueryConduitAPIMethod' => 'applications/phid/conduit/PHIDQueryConduitAPIMethod.php', 'PHUI' => 'view/phui/PHUI.php', 'PHUIActionPanelExample' => 'applications/uiexample/examples/PHUIActionPanelExample.php', 'PHUIActionPanelView' => 'view/phui/PHUIActionPanelView.php', 'PHUIApplicationMenuView' => 'view/layout/PHUIApplicationMenuView.php', 'PHUIBadgeBoxView' => 'view/phui/PHUIBadgeBoxView.php', 'PHUIBadgeExample' => 'applications/uiexample/examples/PHUIBadgeExample.php', 'PHUIBadgeMiniView' => 'view/phui/PHUIBadgeMiniView.php', 'PHUIBadgeView' => 'view/phui/PHUIBadgeView.php', 'PHUIBigInfoView' => 'view/phui/PHUIBigInfoView.php', 'PHUIBoxExample' => 'applications/uiexample/examples/PHUIBoxExample.php', 'PHUIBoxView' => 'view/phui/PHUIBoxView.php', 'PHUIButtonBarExample' => 'applications/uiexample/examples/PHUIButtonBarExample.php', 'PHUIButtonBarView' => 'view/phui/PHUIButtonBarView.php', 'PHUIButtonExample' => 'applications/uiexample/examples/PHUIButtonExample.php', 'PHUIButtonView' => 'view/phui/PHUIButtonView.php', 'PHUICMSView' => 'view/phui/PHUICMSView.php', 'PHUICalendarDayView' => 'view/phui/calendar/PHUICalendarDayView.php', 'PHUICalendarListView' => 'view/phui/calendar/PHUICalendarListView.php', 'PHUICalendarMonthView' => 'view/phui/calendar/PHUICalendarMonthView.php', 'PHUICalendarWeekView' => 'view/phui/calendar/PHUICalendarWeekView.php', 'PHUICalendarWidgetView' => 'view/phui/calendar/PHUICalendarWidgetView.php', 'PHUIColorPalletteExample' => 'applications/uiexample/examples/PHUIColorPalletteExample.php', 'PHUICrumbView' => 'view/phui/PHUICrumbView.php', 'PHUICrumbsView' => 'view/phui/PHUICrumbsView.php', 'PHUICurtainExtension' => 'view/extension/PHUICurtainExtension.php', 'PHUICurtainPanelView' => 'view/layout/PHUICurtainPanelView.php', 'PHUICurtainView' => 'view/layout/PHUICurtainView.php', 'PHUIDiffGraphView' => 'infrastructure/diff/view/PHUIDiffGraphView.php', 'PHUIDiffGraphViewTestCase' => 'infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php', 'PHUIDiffInlineCommentDetailView' => 'infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php', 'PHUIDiffInlineCommentEditView' => 'infrastructure/diff/view/PHUIDiffInlineCommentEditView.php', 'PHUIDiffInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffInlineCommentRowScaffold.php', 'PHUIDiffInlineCommentTableScaffold' => 'infrastructure/diff/view/PHUIDiffInlineCommentTableScaffold.php', 'PHUIDiffInlineCommentUndoView' => 'infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php', 'PHUIDiffInlineCommentView' => 'infrastructure/diff/view/PHUIDiffInlineCommentView.php', 'PHUIDiffOneUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffOneUpInlineCommentRowScaffold.php', 'PHUIDiffRevealIconView' => 'infrastructure/diff/view/PHUIDiffRevealIconView.php', 'PHUIDiffTableOfContentsItemView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php', 'PHUIDiffTableOfContentsListView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsListView.php', 'PHUIDiffTwoUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffTwoUpInlineCommentRowScaffold.php', 'PHUIDocumentSummaryView' => 'view/phui/PHUIDocumentSummaryView.php', 'PHUIDocumentViewPro' => 'view/phui/PHUIDocumentViewPro.php', 'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php', 'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php', 'PHUIFormDividerControl' => 'view/form/control/PHUIFormDividerControl.php', 'PHUIFormFileControl' => 'view/form/control/PHUIFormFileControl.php', 'PHUIFormFreeformDateControl' => 'view/form/control/PHUIFormFreeformDateControl.php', 'PHUIFormIconSetControl' => 'view/form/control/PHUIFormIconSetControl.php', 'PHUIFormInsetView' => 'view/form/PHUIFormInsetView.php', 'PHUIFormLayoutView' => 'view/form/PHUIFormLayoutView.php', 'PHUIFormNumberControl' => 'view/form/control/PHUIFormNumberControl.php', 'PHUIHandleListView' => 'applications/phid/view/PHUIHandleListView.php', 'PHUIHandleTagListView' => 'applications/phid/view/PHUIHandleTagListView.php', 'PHUIHandleView' => 'applications/phid/view/PHUIHandleView.php', 'PHUIHeadThingView' => 'view/phui/PHUIHeadThingView.php', 'PHUIHeaderView' => 'view/phui/PHUIHeaderView.php', 'PHUIHovercardUIExample' => 'applications/uiexample/examples/PHUIHovercardUIExample.php', 'PHUIHovercardView' => 'view/phui/PHUIHovercardView.php', 'PHUIIconCircleView' => 'view/phui/PHUIIconCircleView.php', 'PHUIIconExample' => 'applications/uiexample/examples/PHUIIconExample.php', 'PHUIIconView' => 'view/phui/PHUIIconView.php', 'PHUIImageMaskExample' => 'applications/uiexample/examples/PHUIImageMaskExample.php', 'PHUIImageMaskView' => 'view/phui/PHUIImageMaskView.php', 'PHUIInfoExample' => 'applications/uiexample/examples/PHUIInfoExample.php', 'PHUIInfoPanelExample' => 'applications/uiexample/examples/PHUIInfoPanelExample.php', 'PHUIInfoPanelView' => 'view/phui/PHUIInfoPanelView.php', 'PHUIInfoView' => 'view/form/PHUIInfoView.php', 'PHUIInvisibleCharacterTestCase' => 'view/phui/__tests__/PHUIInvisibleCharacterTestCase.php', 'PHUIInvisibleCharacterView' => 'view/phui/PHUIInvisibleCharacterView.php', 'PHUIListExample' => 'applications/uiexample/examples/PHUIListExample.php', 'PHUIListItemView' => 'view/phui/PHUIListItemView.php', 'PHUIListView' => 'view/phui/PHUIListView.php', 'PHUIListViewTestCase' => 'view/layout/__tests__/PHUIListViewTestCase.php', 'PHUIMainMenuView' => 'view/phui/PHUIMainMenuView.php', 'PHUIObjectBoxView' => 'view/phui/PHUIObjectBoxView.php', 'PHUIObjectItemListExample' => 'applications/uiexample/examples/PHUIObjectItemListExample.php', 'PHUIObjectItemListView' => 'view/phui/PHUIObjectItemListView.php', 'PHUIObjectItemView' => 'view/phui/PHUIObjectItemView.php', 'PHUIPagerView' => 'view/phui/PHUIPagerView.php', 'PHUIPinboardItemView' => 'view/phui/PHUIPinboardItemView.php', 'PHUIPinboardView' => 'view/phui/PHUIPinboardView.php', 'PHUIPropertyGroupView' => 'view/phui/PHUIPropertyGroupView.php', 'PHUIPropertyListExample' => 'applications/uiexample/examples/PHUIPropertyListExample.php', 'PHUIPropertyListView' => 'view/phui/PHUIPropertyListView.php', 'PHUIRemarkupPreviewPanel' => 'view/phui/PHUIRemarkupPreviewPanel.php', 'PHUIRemarkupView' => 'infrastructure/markup/view/PHUIRemarkupView.php', 'PHUISegmentBarSegmentView' => 'view/phui/PHUISegmentBarSegmentView.php', 'PHUISegmentBarView' => 'view/phui/PHUISegmentBarView.php', 'PHUISpacesNamespaceContextView' => 'applications/spaces/view/PHUISpacesNamespaceContextView.php', 'PHUIStatusItemView' => 'view/phui/PHUIStatusItemView.php', 'PHUIStatusListView' => 'view/phui/PHUIStatusListView.php', 'PHUITabGroupView' => 'view/phui/PHUITabGroupView.php', 'PHUITabView' => 'view/phui/PHUITabView.php', 'PHUITagExample' => 'applications/uiexample/examples/PHUITagExample.php', 'PHUITagView' => 'view/phui/PHUITagView.php', 'PHUITimelineEventView' => 'view/phui/PHUITimelineEventView.php', 'PHUITimelineExample' => 'applications/uiexample/examples/PHUITimelineExample.php', 'PHUITimelineView' => 'view/phui/PHUITimelineView.php', 'PHUITwoColumnView' => 'view/phui/PHUITwoColumnView.php', 'PHUITypeaheadExample' => 'applications/uiexample/examples/PHUITypeaheadExample.php', 'PHUIWorkboardView' => 'view/phui/PHUIWorkboardView.php', 'PHUIWorkpanelView' => 'view/phui/PHUIWorkpanelView.php', 'PassphraseAbstractKey' => 'applications/passphrase/keys/PassphraseAbstractKey.php', 'PassphraseConduitAPIMethod' => 'applications/passphrase/conduit/PassphraseConduitAPIMethod.php', 'PassphraseController' => 'applications/passphrase/controller/PassphraseController.php', 'PassphraseCredential' => 'applications/passphrase/storage/PassphraseCredential.php', 'PassphraseCredentialAuthorPolicyRule' => 'applications/passphrase/policyrule/PassphraseCredentialAuthorPolicyRule.php', 'PassphraseCredentialConduitController' => 'applications/passphrase/controller/PassphraseCredentialConduitController.php', 'PassphraseCredentialControl' => 'applications/passphrase/view/PassphraseCredentialControl.php', 'PassphraseCredentialCreateController' => 'applications/passphrase/controller/PassphraseCredentialCreateController.php', 'PassphraseCredentialDestroyController' => 'applications/passphrase/controller/PassphraseCredentialDestroyController.php', 'PassphraseCredentialEditController' => 'applications/passphrase/controller/PassphraseCredentialEditController.php', 'PassphraseCredentialFulltextEngine' => 'applications/passphrase/search/PassphraseCredentialFulltextEngine.php', 'PassphraseCredentialListController' => 'applications/passphrase/controller/PassphraseCredentialListController.php', 'PassphraseCredentialLockController' => 'applications/passphrase/controller/PassphraseCredentialLockController.php', 'PassphraseCredentialPHIDType' => 'applications/passphrase/phid/PassphraseCredentialPHIDType.php', 'PassphraseCredentialPublicController' => 'applications/passphrase/controller/PassphraseCredentialPublicController.php', 'PassphraseCredentialQuery' => 'applications/passphrase/query/PassphraseCredentialQuery.php', 'PassphraseCredentialRevealController' => 'applications/passphrase/controller/PassphraseCredentialRevealController.php', 'PassphraseCredentialSearchEngine' => 'applications/passphrase/query/PassphraseCredentialSearchEngine.php', 'PassphraseCredentialTransaction' => 'applications/passphrase/storage/PassphraseCredentialTransaction.php', 'PassphraseCredentialTransactionEditor' => 'applications/passphrase/editor/PassphraseCredentialTransactionEditor.php', 'PassphraseCredentialTransactionQuery' => 'applications/passphrase/query/PassphraseCredentialTransactionQuery.php', 'PassphraseCredentialType' => 'applications/passphrase/credentialtype/PassphraseCredentialType.php', 'PassphraseCredentialTypeTestCase' => 'applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php', 'PassphraseCredentialViewController' => 'applications/passphrase/controller/PassphraseCredentialViewController.php', 'PassphraseDAO' => 'applications/passphrase/storage/PassphraseDAO.php', 'PassphraseDefaultEditCapability' => 'applications/passphrase/capability/PassphraseDefaultEditCapability.php', 'PassphraseDefaultViewCapability' => 'applications/passphrase/capability/PassphraseDefaultViewCapability.php', 'PassphraseNoteCredentialType' => 'applications/passphrase/credentialtype/PassphraseNoteCredentialType.php', 'PassphrasePasswordCredentialType' => 'applications/passphrase/credentialtype/PassphrasePasswordCredentialType.php', 'PassphrasePasswordKey' => 'applications/passphrase/keys/PassphrasePasswordKey.php', 'PassphraseQueryConduitAPIMethod' => 'applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php', 'PassphraseRemarkupRule' => 'applications/passphrase/remarkup/PassphraseRemarkupRule.php', 'PassphraseSSHGeneratedKeyCredentialType' => 'applications/passphrase/credentialtype/PassphraseSSHGeneratedKeyCredentialType.php', 'PassphraseSSHKey' => 'applications/passphrase/keys/PassphraseSSHKey.php', 'PassphraseSSHPrivateKeyCredentialType' => 'applications/passphrase/credentialtype/PassphraseSSHPrivateKeyCredentialType.php', 'PassphraseSSHPrivateKeyFileCredentialType' => 'applications/passphrase/credentialtype/PassphraseSSHPrivateKeyFileCredentialType.php', 'PassphraseSSHPrivateKeyTextCredentialType' => 'applications/passphrase/credentialtype/PassphraseSSHPrivateKeyTextCredentialType.php', 'PassphraseSchemaSpec' => 'applications/passphrase/storage/PassphraseSchemaSpec.php', 'PassphraseSecret' => 'applications/passphrase/storage/PassphraseSecret.php', 'PassphraseTokenCredentialType' => 'applications/passphrase/credentialtype/PassphraseTokenCredentialType.php', 'PasteConduitAPIMethod' => 'applications/paste/conduit/PasteConduitAPIMethod.php', 'PasteCreateConduitAPIMethod' => 'applications/paste/conduit/PasteCreateConduitAPIMethod.php', 'PasteCreateMailReceiver' => 'applications/paste/mail/PasteCreateMailReceiver.php', 'PasteDefaultEditCapability' => 'applications/paste/capability/PasteDefaultEditCapability.php', 'PasteDefaultViewCapability' => 'applications/paste/capability/PasteDefaultViewCapability.php', 'PasteEditConduitAPIMethod' => 'applications/paste/conduit/PasteEditConduitAPIMethod.php', 'PasteEmbedView' => 'applications/paste/view/PasteEmbedView.php', 'PasteInfoConduitAPIMethod' => 'applications/paste/conduit/PasteInfoConduitAPIMethod.php', 'PasteLanguageSelectDatasource' => 'applications/paste/typeahead/PasteLanguageSelectDatasource.php', 'PasteMailReceiver' => 'applications/paste/mail/PasteMailReceiver.php', 'PasteQueryConduitAPIMethod' => 'applications/paste/conduit/PasteQueryConduitAPIMethod.php', 'PasteReplyHandler' => 'applications/paste/mail/PasteReplyHandler.php', 'PasteSearchConduitAPIMethod' => 'applications/paste/conduit/PasteSearchConduitAPIMethod.php', 'PeopleBrowseUserDirectoryCapability' => 'applications/people/capability/PeopleBrowseUserDirectoryCapability.php', 'PeopleCreateUsersCapability' => 'applications/people/capability/PeopleCreateUsersCapability.php', 'PeopleHovercardEngineExtension' => 'applications/people/engineextension/PeopleHovercardEngineExtension.php', 'PeopleUserLogGarbageCollector' => 'applications/people/garbagecollector/PeopleUserLogGarbageCollector.php', 'Phabricator404Controller' => 'applications/base/controller/Phabricator404Controller.php', 'PhabricatorAWSConfigOptions' => 'applications/config/option/PhabricatorAWSConfigOptions.php', 'PhabricatorAccessControlTestCase' => 'applications/base/controller/__tests__/PhabricatorAccessControlTestCase.php', 'PhabricatorAccessLog' => 'infrastructure/log/PhabricatorAccessLog.php', 'PhabricatorAccessLogConfigOptions' => 'applications/config/option/PhabricatorAccessLogConfigOptions.php', 'PhabricatorAccessibilitySetting' => 'applications/settings/setting/PhabricatorAccessibilitySetting.php', 'PhabricatorAccountSettingsPanel' => 'applications/settings/panel/PhabricatorAccountSettingsPanel.php', 'PhabricatorActionListView' => 'view/layout/PhabricatorActionListView.php', 'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php', 'PhabricatorActivitySettingsPanel' => 'applications/settings/panel/PhabricatorActivitySettingsPanel.php', 'PhabricatorAdministratorsPolicyRule' => 'applications/people/policyrule/PhabricatorAdministratorsPolicyRule.php', 'PhabricatorAjaxRequestExceptionHandler' => 'aphront/handler/PhabricatorAjaxRequestExceptionHandler.php', 'PhabricatorAlmanacApplication' => 'applications/almanac/application/PhabricatorAlmanacApplication.php', 'PhabricatorAmazonAuthProvider' => 'applications/auth/provider/PhabricatorAmazonAuthProvider.php', 'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php', 'PhabricatorAphlictManagementDebugWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php', 'PhabricatorAphlictManagementRestartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementRestartWorkflow.php', 'PhabricatorAphlictManagementStartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStartWorkflow.php', 'PhabricatorAphlictManagementStatusWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStatusWorkflow.php', 'PhabricatorAphlictManagementStopWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStopWorkflow.php', 'PhabricatorAphlictManagementWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php', 'PhabricatorAphlictSetupCheck' => 'applications/notification/setup/PhabricatorAphlictSetupCheck.php', 'PhabricatorAphrontBarUIExample' => 'applications/uiexample/examples/PhabricatorAphrontBarUIExample.php', 'PhabricatorAphrontViewTestCase' => 'view/__tests__/PhabricatorAphrontViewTestCase.php', 'PhabricatorAppSearchEngine' => 'applications/meta/query/PhabricatorAppSearchEngine.php', 'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php', 'PhabricatorApplicationApplicationPHIDType' => 'applications/meta/phid/PhabricatorApplicationApplicationPHIDType.php', 'PhabricatorApplicationConfigOptions' => 'applications/config/option/PhabricatorApplicationConfigOptions.php', 'PhabricatorApplicationConfigurationPanel' => 'applications/meta/panel/PhabricatorApplicationConfigurationPanel.php', 'PhabricatorApplicationConfigurationPanelTestCase' => 'applications/meta/panel/__tests__/PhabricatorApplicationConfigurationPanelTestCase.php', 'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php', 'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php', 'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php', 'PhabricatorApplicationEditHTTPParameterHelpView' => 'applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php', 'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php', 'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php', 'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php', 'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php', 'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php', 'PhabricatorApplicationSearchEngine' => 'applications/search/engine/PhabricatorApplicationSearchEngine.php', 'PhabricatorApplicationSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorApplicationSearchEngineTestCase.php', 'PhabricatorApplicationSearchResultView' => 'applications/search/view/PhabricatorApplicationSearchResultView.php', 'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php', 'PhabricatorApplicationTestCase' => 'applications/base/__tests__/PhabricatorApplicationTestCase.php', 'PhabricatorApplicationTransaction' => 'applications/transactions/storage/PhabricatorApplicationTransaction.php', 'PhabricatorApplicationTransactionComment' => 'applications/transactions/storage/PhabricatorApplicationTransactionComment.php', 'PhabricatorApplicationTransactionCommentEditController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentEditController.php', 'PhabricatorApplicationTransactionCommentEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php', 'PhabricatorApplicationTransactionCommentHistoryController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentHistoryController.php', 'PhabricatorApplicationTransactionCommentQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php', 'PhabricatorApplicationTransactionCommentQuoteController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentQuoteController.php', 'PhabricatorApplicationTransactionCommentRawController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentRawController.php', 'PhabricatorApplicationTransactionCommentRemoveController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentRemoveController.php', 'PhabricatorApplicationTransactionCommentView' => 'applications/transactions/view/PhabricatorApplicationTransactionCommentView.php', 'PhabricatorApplicationTransactionController' => 'applications/transactions/controller/PhabricatorApplicationTransactionController.php', 'PhabricatorApplicationTransactionDetailController' => 'applications/transactions/controller/PhabricatorApplicationTransactionDetailController.php', 'PhabricatorApplicationTransactionEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionEditor.php', 'PhabricatorApplicationTransactionFeedStory' => 'applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php', 'PhabricatorApplicationTransactionInterface' => 'applications/transactions/interface/PhabricatorApplicationTransactionInterface.php', 'PhabricatorApplicationTransactionNoEffectException' => 'applications/transactions/exception/PhabricatorApplicationTransactionNoEffectException.php', 'PhabricatorApplicationTransactionNoEffectResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionNoEffectResponse.php', 'PhabricatorApplicationTransactionPublishWorker' => 'applications/transactions/worker/PhabricatorApplicationTransactionPublishWorker.php', 'PhabricatorApplicationTransactionQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionQuery.php', 'PhabricatorApplicationTransactionRemarkupPreviewController' => 'applications/transactions/controller/PhabricatorApplicationTransactionRemarkupPreviewController.php', 'PhabricatorApplicationTransactionReplyHandler' => 'applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php', 'PhabricatorApplicationTransactionResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionResponse.php', 'PhabricatorApplicationTransactionShowOlderController' => 'applications/transactions/controller/PhabricatorApplicationTransactionShowOlderController.php', 'PhabricatorApplicationTransactionStructureException' => 'applications/transactions/exception/PhabricatorApplicationTransactionStructureException.php', 'PhabricatorApplicationTransactionTemplatedCommentQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionTemplatedCommentQuery.php', 'PhabricatorApplicationTransactionTextDiffDetailView' => 'applications/transactions/view/PhabricatorApplicationTransactionTextDiffDetailView.php', 'PhabricatorApplicationTransactionTransactionPHIDType' => 'applications/transactions/phid/PhabricatorApplicationTransactionTransactionPHIDType.php', 'PhabricatorApplicationTransactionValidationError' => 'applications/transactions/error/PhabricatorApplicationTransactionValidationError.php', 'PhabricatorApplicationTransactionValidationException' => 'applications/transactions/exception/PhabricatorApplicationTransactionValidationException.php', 'PhabricatorApplicationTransactionValidationResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionValidationResponse.php', 'PhabricatorApplicationTransactionValueController' => 'applications/transactions/controller/PhabricatorApplicationTransactionValueController.php', 'PhabricatorApplicationTransactionView' => 'applications/transactions/view/PhabricatorApplicationTransactionView.php', 'PhabricatorApplicationUninstallController' => 'applications/meta/controller/PhabricatorApplicationUninstallController.php', 'PhabricatorApplicationsApplication' => 'applications/meta/application/PhabricatorApplicationsApplication.php', 'PhabricatorApplicationsController' => 'applications/meta/controller/PhabricatorApplicationsController.php', 'PhabricatorApplicationsListController' => 'applications/meta/controller/PhabricatorApplicationsListController.php', 'PhabricatorAsanaAuthProvider' => 'applications/auth/provider/PhabricatorAsanaAuthProvider.php', 'PhabricatorAsanaConfigOptions' => 'applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php', 'PhabricatorAsanaSubtaskHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorAsanaSubtaskHasObjectEdgeType.php', 'PhabricatorAsanaTaskHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorAsanaTaskHasObjectEdgeType.php', 'PhabricatorAuditActionConstants' => 'applications/audit/constants/PhabricatorAuditActionConstants.php', 'PhabricatorAuditAddCommentController' => 'applications/audit/controller/PhabricatorAuditAddCommentController.php', 'PhabricatorAuditApplication' => 'applications/audit/application/PhabricatorAuditApplication.php', 'PhabricatorAuditCommentEditor' => 'applications/audit/editor/PhabricatorAuditCommentEditor.php', 'PhabricatorAuditCommitStatusConstants' => 'applications/audit/constants/PhabricatorAuditCommitStatusConstants.php', 'PhabricatorAuditController' => 'applications/audit/controller/PhabricatorAuditController.php', 'PhabricatorAuditEditor' => 'applications/audit/editor/PhabricatorAuditEditor.php', 'PhabricatorAuditInlineComment' => 'applications/audit/storage/PhabricatorAuditInlineComment.php', 'PhabricatorAuditListController' => 'applications/audit/controller/PhabricatorAuditListController.php', 'PhabricatorAuditListView' => 'applications/audit/view/PhabricatorAuditListView.php', 'PhabricatorAuditMailReceiver' => 'applications/audit/mail/PhabricatorAuditMailReceiver.php', 'PhabricatorAuditManagementDeleteWorkflow' => 'applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php', 'PhabricatorAuditManagementWorkflow' => 'applications/audit/management/PhabricatorAuditManagementWorkflow.php', 'PhabricatorAuditPreviewController' => 'applications/audit/controller/PhabricatorAuditPreviewController.php', 'PhabricatorAuditReplyHandler' => 'applications/audit/mail/PhabricatorAuditReplyHandler.php', 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', 'PhabricatorAuditTransaction' => 'applications/audit/storage/PhabricatorAuditTransaction.php', 'PhabricatorAuditTransactionComment' => 'applications/audit/storage/PhabricatorAuditTransactionComment.php', 'PhabricatorAuditTransactionQuery' => 'applications/audit/query/PhabricatorAuditTransactionQuery.php', 'PhabricatorAuditTransactionView' => 'applications/audit/view/PhabricatorAuditTransactionView.php', 'PhabricatorAuthAccountView' => 'applications/auth/view/PhabricatorAuthAccountView.php', 'PhabricatorAuthApplication' => 'applications/auth/application/PhabricatorAuthApplication.php', 'PhabricatorAuthAuthFactorPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php', 'PhabricatorAuthAuthProviderPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthProviderPHIDType.php', 'PhabricatorAuthConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthConduitAPIMethod.php', 'PhabricatorAuthConfirmLinkController' => 'applications/auth/controller/PhabricatorAuthConfirmLinkController.php', 'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php', 'PhabricatorAuthDAO' => 'applications/auth/storage/PhabricatorAuthDAO.php', 'PhabricatorAuthDisableController' => 'applications/auth/controller/config/PhabricatorAuthDisableController.php', 'PhabricatorAuthDowngradeSessionController' => 'applications/auth/controller/PhabricatorAuthDowngradeSessionController.php', 'PhabricatorAuthEditController' => 'applications/auth/controller/config/PhabricatorAuthEditController.php', 'PhabricatorAuthFactor' => 'applications/auth/factor/PhabricatorAuthFactor.php', 'PhabricatorAuthFactorConfig' => 'applications/auth/storage/PhabricatorAuthFactorConfig.php', 'PhabricatorAuthFactorTestCase' => 'applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php', 'PhabricatorAuthFinishController' => 'applications/auth/controller/PhabricatorAuthFinishController.php', 'PhabricatorAuthHighSecurityRequiredException' => 'applications/auth/exception/PhabricatorAuthHighSecurityRequiredException.php', 'PhabricatorAuthHighSecurityToken' => 'applications/auth/data/PhabricatorAuthHighSecurityToken.php', 'PhabricatorAuthInvite' => 'applications/auth/storage/PhabricatorAuthInvite.php', 'PhabricatorAuthInviteAccountException' => 'applications/auth/exception/PhabricatorAuthInviteAccountException.php', 'PhabricatorAuthInviteAction' => 'applications/auth/data/PhabricatorAuthInviteAction.php', 'PhabricatorAuthInviteActionTableView' => 'applications/auth/view/PhabricatorAuthInviteActionTableView.php', 'PhabricatorAuthInviteController' => 'applications/auth/controller/PhabricatorAuthInviteController.php', 'PhabricatorAuthInviteDialogException' => 'applications/auth/exception/PhabricatorAuthInviteDialogException.php', 'PhabricatorAuthInviteEngine' => 'applications/auth/engine/PhabricatorAuthInviteEngine.php', 'PhabricatorAuthInviteException' => 'applications/auth/exception/PhabricatorAuthInviteException.php', 'PhabricatorAuthInviteInvalidException' => 'applications/auth/exception/PhabricatorAuthInviteInvalidException.php', 'PhabricatorAuthInviteLoginException' => 'applications/auth/exception/PhabricatorAuthInviteLoginException.php', 'PhabricatorAuthInvitePHIDType' => 'applications/auth/phid/PhabricatorAuthInvitePHIDType.php', 'PhabricatorAuthInviteQuery' => 'applications/auth/query/PhabricatorAuthInviteQuery.php', 'PhabricatorAuthInviteRegisteredException' => 'applications/auth/exception/PhabricatorAuthInviteRegisteredException.php', 'PhabricatorAuthInviteSearchEngine' => 'applications/auth/query/PhabricatorAuthInviteSearchEngine.php', 'PhabricatorAuthInviteTestCase' => 'applications/auth/factor/__tests__/PhabricatorAuthInviteTestCase.php', 'PhabricatorAuthInviteVerifyException' => 'applications/auth/exception/PhabricatorAuthInviteVerifyException.php', 'PhabricatorAuthInviteWorker' => 'applications/auth/worker/PhabricatorAuthInviteWorker.php', 'PhabricatorAuthLinkController' => 'applications/auth/controller/PhabricatorAuthLinkController.php', 'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php', 'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php', 'PhabricatorAuthLoginHandler' => 'applications/auth/handler/PhabricatorAuthLoginHandler.php', 'PhabricatorAuthLogoutConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthLogoutConduitAPIMethod.php', 'PhabricatorAuthMainMenuBarExtension' => 'applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php', 'PhabricatorAuthManagementCachePKCS8Workflow' => 'applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php', 'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php', 'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php', 'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php', 'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php', 'PhabricatorAuthManagementStripWorkflow' => 'applications/auth/management/PhabricatorAuthManagementStripWorkflow.php', 'PhabricatorAuthManagementTrustOAuthClientWorkflow' => 'applications/auth/management/PhabricatorAuthManagementTrustOAuthClientWorkflow.php', 'PhabricatorAuthManagementUnlimitWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUnlimitWorkflow.php', 'PhabricatorAuthManagementUntrustOAuthClientWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUntrustOAuthClientWorkflow.php', 'PhabricatorAuthManagementVerifyWorkflow' => 'applications/auth/management/PhabricatorAuthManagementVerifyWorkflow.php', 'PhabricatorAuthManagementWorkflow' => 'applications/auth/management/PhabricatorAuthManagementWorkflow.php', 'PhabricatorAuthNeedsApprovalController' => 'applications/auth/controller/PhabricatorAuthNeedsApprovalController.php', 'PhabricatorAuthNeedsMultiFactorController' => 'applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php', 'PhabricatorAuthNewController' => 'applications/auth/controller/config/PhabricatorAuthNewController.php', 'PhabricatorAuthOldOAuthRedirectController' => 'applications/auth/controller/PhabricatorAuthOldOAuthRedirectController.php', 'PhabricatorAuthOneTimeLoginController' => 'applications/auth/controller/PhabricatorAuthOneTimeLoginController.php', 'PhabricatorAuthOneTimeLoginTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthOneTimeLoginTemporaryTokenType.php', 'PhabricatorAuthPasswordResetTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthPasswordResetTemporaryTokenType.php', 'PhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorAuthProvider.php', 'PhabricatorAuthProviderConfig' => 'applications/auth/storage/PhabricatorAuthProviderConfig.php', 'PhabricatorAuthProviderConfigController' => 'applications/auth/controller/config/PhabricatorAuthProviderConfigController.php', 'PhabricatorAuthProviderConfigEditor' => 'applications/auth/editor/PhabricatorAuthProviderConfigEditor.php', 'PhabricatorAuthProviderConfigQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigQuery.php', 'PhabricatorAuthProviderConfigTransaction' => 'applications/auth/storage/PhabricatorAuthProviderConfigTransaction.php', 'PhabricatorAuthProviderConfigTransactionQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigTransactionQuery.php', 'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php', 'PhabricatorAuthRegisterController' => 'applications/auth/controller/PhabricatorAuthRegisterController.php', 'PhabricatorAuthRevokeTokenController' => 'applications/auth/controller/PhabricatorAuthRevokeTokenController.php', 'PhabricatorAuthSSHKey' => 'applications/auth/storage/PhabricatorAuthSSHKey.php', 'PhabricatorAuthSSHKeyController' => 'applications/auth/controller/PhabricatorAuthSSHKeyController.php', 'PhabricatorAuthSSHKeyDeactivateController' => 'applications/auth/controller/PhabricatorAuthSSHKeyDeactivateController.php', 'PhabricatorAuthSSHKeyEditController' => 'applications/auth/controller/PhabricatorAuthSSHKeyEditController.php', 'PhabricatorAuthSSHKeyEditor' => 'applications/auth/editor/PhabricatorAuthSSHKeyEditor.php', 'PhabricatorAuthSSHKeyGenerateController' => 'applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php', 'PhabricatorAuthSSHKeyListController' => 'applications/auth/controller/PhabricatorAuthSSHKeyListController.php', 'PhabricatorAuthSSHKeyPHIDType' => 'applications/auth/phid/PhabricatorAuthSSHKeyPHIDType.php', 'PhabricatorAuthSSHKeyQuery' => 'applications/auth/query/PhabricatorAuthSSHKeyQuery.php', 'PhabricatorAuthSSHKeyReplyHandler' => 'applications/auth/mail/PhabricatorAuthSSHKeyReplyHandler.php', 'PhabricatorAuthSSHKeySearchEngine' => 'applications/auth/query/PhabricatorAuthSSHKeySearchEngine.php', 'PhabricatorAuthSSHKeyTableView' => 'applications/auth/view/PhabricatorAuthSSHKeyTableView.php', 'PhabricatorAuthSSHKeyTransaction' => 'applications/auth/storage/PhabricatorAuthSSHKeyTransaction.php', 'PhabricatorAuthSSHKeyTransactionQuery' => 'applications/auth/query/PhabricatorAuthSSHKeyTransactionQuery.php', 'PhabricatorAuthSSHKeyViewController' => 'applications/auth/controller/PhabricatorAuthSSHKeyViewController.php', 'PhabricatorAuthSSHPublicKey' => 'applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php', 'PhabricatorAuthSession' => 'applications/auth/storage/PhabricatorAuthSession.php', 'PhabricatorAuthSessionEngine' => 'applications/auth/engine/PhabricatorAuthSessionEngine.php', 'PhabricatorAuthSessionEngineExtension' => 'applications/auth/engine/PhabricatorAuthSessionEngineExtension.php', 'PhabricatorAuthSessionEngineExtensionModule' => 'applications/auth/engine/PhabricatorAuthSessionEngineExtensionModule.php', 'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php', 'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php', 'PhabricatorAuthSetupCheck' => 'applications/config/check/PhabricatorAuthSetupCheck.php', 'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php', 'PhabricatorAuthTOTPKeyTemporaryTokenType' => 'applications/auth/factor/PhabricatorAuthTOTPKeyTemporaryTokenType.php', 'PhabricatorAuthTemporaryToken' => 'applications/auth/storage/PhabricatorAuthTemporaryToken.php', 'PhabricatorAuthTemporaryTokenGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthTemporaryTokenGarbageCollector.php', 'PhabricatorAuthTemporaryTokenQuery' => 'applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php', 'PhabricatorAuthTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthTemporaryTokenType.php', 'PhabricatorAuthTemporaryTokenTypeModule' => 'applications/auth/tokentype/PhabricatorAuthTemporaryTokenTypeModule.php', 'PhabricatorAuthTerminateSessionController' => 'applications/auth/controller/PhabricatorAuthTerminateSessionController.php', 'PhabricatorAuthTryFactorAction' => 'applications/auth/action/PhabricatorAuthTryFactorAction.php', 'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php', 'PhabricatorAuthValidateController' => 'applications/auth/controller/PhabricatorAuthValidateController.php', 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', 'PhabricatorAutoEventListener' => 'infrastructure/events/PhabricatorAutoEventListener.php', 'PhabricatorBadgeHasRecipientEdgeType' => 'applications/badges/edge/PhabricatorBadgeHasRecipientEdgeType.php', 'PhabricatorBadgesApplication' => 'applications/badges/application/PhabricatorBadgesApplication.php', 'PhabricatorBadgesArchiveController' => 'applications/badges/controller/PhabricatorBadgesArchiveController.php', 'PhabricatorBadgesAward' => 'applications/badges/storage/PhabricatorBadgesAward.php', 'PhabricatorBadgesAwardController' => 'applications/badges/controller/PhabricatorBadgesAwardController.php', 'PhabricatorBadgesAwardQuery' => 'applications/badges/query/PhabricatorBadgesAwardQuery.php', 'PhabricatorBadgesBadge' => 'applications/badges/storage/PhabricatorBadgesBadge.php', 'PhabricatorBadgesBadgeNameNgrams' => 'applications/badges/storage/PhabricatorBadgesBadgeNameNgrams.php', 'PhabricatorBadgesCommentController' => 'applications/badges/controller/PhabricatorBadgesCommentController.php', 'PhabricatorBadgesController' => 'applications/badges/controller/PhabricatorBadgesController.php', 'PhabricatorBadgesCreateCapability' => 'applications/badges/capability/PhabricatorBadgesCreateCapability.php', 'PhabricatorBadgesDAO' => 'applications/badges/storage/PhabricatorBadgesDAO.php', 'PhabricatorBadgesDatasource' => 'applications/badges/typeahead/PhabricatorBadgesDatasource.php', 'PhabricatorBadgesDefaultEditCapability' => 'applications/badges/capability/PhabricatorBadgesDefaultEditCapability.php', 'PhabricatorBadgesEditConduitAPIMethod' => 'applications/badges/conduit/PhabricatorBadgesEditConduitAPIMethod.php', 'PhabricatorBadgesEditController' => 'applications/badges/controller/PhabricatorBadgesEditController.php', 'PhabricatorBadgesEditEngine' => 'applications/badges/editor/PhabricatorBadgesEditEngine.php', 'PhabricatorBadgesEditRecipientsController' => 'applications/badges/controller/PhabricatorBadgesEditRecipientsController.php', 'PhabricatorBadgesEditor' => 'applications/badges/editor/PhabricatorBadgesEditor.php', 'PhabricatorBadgesIconSet' => 'applications/badges/icon/PhabricatorBadgesIconSet.php', 'PhabricatorBadgesListController' => 'applications/badges/controller/PhabricatorBadgesListController.php', 'PhabricatorBadgesMailReceiver' => 'applications/badges/mail/PhabricatorBadgesMailReceiver.php', 'PhabricatorBadgesPHIDType' => 'applications/badges/phid/PhabricatorBadgesPHIDType.php', 'PhabricatorBadgesQuality' => 'applications/badges/constants/PhabricatorBadgesQuality.php', 'PhabricatorBadgesQuery' => 'applications/badges/query/PhabricatorBadgesQuery.php', 'PhabricatorBadgesRecipientsListView' => 'applications/badges/view/PhabricatorBadgesRecipientsListView.php', 'PhabricatorBadgesRemoveRecipientsController' => 'applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php', 'PhabricatorBadgesReplyHandler' => 'applications/badges/mail/PhabricatorBadgesReplyHandler.php', 'PhabricatorBadgesSchemaSpec' => 'applications/badges/storage/PhabricatorBadgesSchemaSpec.php', 'PhabricatorBadgesSearchConduitAPIMethod' => 'applications/badges/conduit/PhabricatorBadgesSearchConduitAPIMethod.php', 'PhabricatorBadgesSearchEngine' => 'applications/badges/query/PhabricatorBadgesSearchEngine.php', 'PhabricatorBadgesTransaction' => 'applications/badges/storage/PhabricatorBadgesTransaction.php', 'PhabricatorBadgesTransactionComment' => 'applications/badges/storage/PhabricatorBadgesTransactionComment.php', 'PhabricatorBadgesTransactionQuery' => 'applications/badges/query/PhabricatorBadgesTransactionQuery.php', 'PhabricatorBadgesViewController' => 'applications/badges/controller/PhabricatorBadgesViewController.php', 'PhabricatorBarePageUIExample' => 'applications/uiexample/examples/PhabricatorBarePageUIExample.php', 'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php', 'PhabricatorBaseURISetupCheck' => 'applications/config/check/PhabricatorBaseURISetupCheck.php', 'PhabricatorBcryptPasswordHasher' => 'infrastructure/util/password/PhabricatorBcryptPasswordHasher.php', 'PhabricatorBinariesSetupCheck' => 'applications/config/check/PhabricatorBinariesSetupCheck.php', 'PhabricatorBitbucketAuthProvider' => 'applications/auth/provider/PhabricatorBitbucketAuthProvider.php', 'PhabricatorBoardLayoutEngine' => 'applications/project/engine/PhabricatorBoardLayoutEngine.php', 'PhabricatorBoardRenderingEngine' => 'applications/project/engine/PhabricatorBoardRenderingEngine.php', 'PhabricatorBoardResponseEngine' => 'applications/project/engine/PhabricatorBoardResponseEngine.php', 'PhabricatorBoolEditField' => 'applications/transactions/editfield/PhabricatorBoolEditField.php', 'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php', 'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php', 'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php', 'PhabricatorBotFeedNotificationHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotFeedNotificationHandler.php', 'PhabricatorBotFlowdockProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBotFlowdockProtocolAdapter.php', 'PhabricatorBotHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotHandler.php', 'PhabricatorBotLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotLogHandler.php', 'PhabricatorBotMacroHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php', 'PhabricatorBotMessage' => 'infrastructure/daemon/bot/PhabricatorBotMessage.php', 'PhabricatorBotObjectNameHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php', 'PhabricatorBotSymbolHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotSymbolHandler.php', 'PhabricatorBotTarget' => 'infrastructure/daemon/bot/target/PhabricatorBotTarget.php', 'PhabricatorBotUser' => 'infrastructure/daemon/bot/target/PhabricatorBotUser.php', 'PhabricatorBotWhatsNewHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php', 'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php', 'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php', 'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php', 'PhabricatorBusyUIExample' => 'applications/uiexample/examples/PhabricatorBusyUIExample.php', 'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php', 'PhabricatorCacheGeneralGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheGeneralGarbageCollector.php', 'PhabricatorCacheManagementPurgeWorkflow' => 'applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php', 'PhabricatorCacheManagementWorkflow' => 'applications/cache/management/PhabricatorCacheManagementWorkflow.php', 'PhabricatorCacheMarkupGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheMarkupGarbageCollector.php', 'PhabricatorCacheSchemaSpec' => 'applications/cache/storage/PhabricatorCacheSchemaSpec.php', 'PhabricatorCacheSetupCheck' => 'applications/config/check/PhabricatorCacheSetupCheck.php', 'PhabricatorCacheSpec' => 'applications/cache/spec/PhabricatorCacheSpec.php', 'PhabricatorCacheTTLGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheTTLGarbageCollector.php', 'PhabricatorCaches' => 'applications/cache/PhabricatorCaches.php', 'PhabricatorCachesTestCase' => 'applications/cache/__tests__/PhabricatorCachesTestCase.php', 'PhabricatorCalendarApplication' => 'applications/calendar/application/PhabricatorCalendarApplication.php', 'PhabricatorCalendarController' => 'applications/calendar/controller/PhabricatorCalendarController.php', 'PhabricatorCalendarDAO' => 'applications/calendar/storage/PhabricatorCalendarDAO.php', 'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php', 'PhabricatorCalendarEventAcceptTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventAcceptTransaction.php', 'PhabricatorCalendarEventAllDayTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventAllDayTransaction.php', 'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php', 'PhabricatorCalendarEventCancelTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventCancelTransaction.php', 'PhabricatorCalendarEventDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDateTransaction.php', 'PhabricatorCalendarEventDeclineTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDeclineTransaction.php', 'PhabricatorCalendarEventDefaultEditCapability' => 'applications/calendar/capability/PhabricatorCalendarEventDefaultEditCapability.php', 'PhabricatorCalendarEventDefaultViewCapability' => 'applications/calendar/capability/PhabricatorCalendarEventDefaultViewCapability.php', 'PhabricatorCalendarEventDescriptionTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDescriptionTransaction.php', 'PhabricatorCalendarEventDragController' => 'applications/calendar/controller/PhabricatorCalendarEventDragController.php', 'PhabricatorCalendarEventEditConduitAPIMethod' => 'applications/calendar/conduit/PhabricatorCalendarEventEditConduitAPIMethod.php', 'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php', 'PhabricatorCalendarEventEditEngine' => 'applications/calendar/editor/PhabricatorCalendarEventEditEngine.php', 'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php', 'PhabricatorCalendarEventEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventEmailCommand.php', 'PhabricatorCalendarEventEndDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php', 'PhabricatorCalendarEventExportController' => 'applications/calendar/controller/PhabricatorCalendarEventExportController.php', 'PhabricatorCalendarEventFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php', 'PhabricatorCalendarEventFulltextEngine' => 'applications/calendar/search/PhabricatorCalendarEventFulltextEngine.php', 'PhabricatorCalendarEventHeraldAdapter' => 'applications/calendar/herald/PhabricatorCalendarEventHeraldAdapter.php', 'PhabricatorCalendarEventHeraldField' => 'applications/calendar/herald/PhabricatorCalendarEventHeraldField.php', 'PhabricatorCalendarEventHeraldFieldGroup' => 'applications/calendar/herald/PhabricatorCalendarEventHeraldFieldGroup.php', 'PhabricatorCalendarEventHostPolicyRule' => 'applications/calendar/policyrule/PhabricatorCalendarEventHostPolicyRule.php', 'PhabricatorCalendarEventHostTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventHostTransaction.php', 'PhabricatorCalendarEventIconTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventIconTransaction.php', 'PhabricatorCalendarEventInviteTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventInviteTransaction.php', 'PhabricatorCalendarEventInvitee' => 'applications/calendar/storage/PhabricatorCalendarEventInvitee.php', 'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php', 'PhabricatorCalendarEventInviteesPolicyRule' => 'applications/calendar/policyrule/PhabricatorCalendarEventInviteesPolicyRule.php', 'PhabricatorCalendarEventJoinController' => 'applications/calendar/controller/PhabricatorCalendarEventJoinController.php', 'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php', 'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php', 'PhabricatorCalendarEventNameHeraldField' => 'applications/calendar/herald/PhabricatorCalendarEventNameHeraldField.php', 'PhabricatorCalendarEventNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventNameTransaction.php', 'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php', 'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php', 'PhabricatorCalendarEventRSVPEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php', 'PhabricatorCalendarEventRecurringTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventRecurringTransaction.php', 'PhabricatorCalendarEventReplyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventReplyTransaction.php', 'PhabricatorCalendarEventSearchConduitAPIMethod' => 'applications/calendar/conduit/PhabricatorCalendarEventSearchConduitAPIMethod.php', 'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php', 'PhabricatorCalendarEventStartDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventStartDateTransaction.php', 'PhabricatorCalendarEventTransaction' => 'applications/calendar/storage/PhabricatorCalendarEventTransaction.php', 'PhabricatorCalendarEventTransactionComment' => 'applications/calendar/storage/PhabricatorCalendarEventTransactionComment.php', 'PhabricatorCalendarEventTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarEventTransactionQuery.php', 'PhabricatorCalendarEventTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarEventTransactionType.php', 'PhabricatorCalendarEventUntilDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventUntilDateTransaction.php', 'PhabricatorCalendarEventViewController' => 'applications/calendar/controller/PhabricatorCalendarEventViewController.php', 'PhabricatorCalendarExport' => 'applications/calendar/storage/PhabricatorCalendarExport.php', 'PhabricatorCalendarExportDisableController' => 'applications/calendar/controller/PhabricatorCalendarExportDisableController.php', 'PhabricatorCalendarExportDisableTransaction' => 'applications/calendar/xaction/PhabricatorCalendarExportDisableTransaction.php', 'PhabricatorCalendarExportEditController' => 'applications/calendar/controller/PhabricatorCalendarExportEditController.php', 'PhabricatorCalendarExportEditEngine' => 'applications/calendar/editor/PhabricatorCalendarExportEditEngine.php', 'PhabricatorCalendarExportEditor' => 'applications/calendar/editor/PhabricatorCalendarExportEditor.php', 'PhabricatorCalendarExportICSController' => 'applications/calendar/controller/PhabricatorCalendarExportICSController.php', 'PhabricatorCalendarExportListController' => 'applications/calendar/controller/PhabricatorCalendarExportListController.php', 'PhabricatorCalendarExportModeTransaction' => 'applications/calendar/xaction/PhabricatorCalendarExportModeTransaction.php', 'PhabricatorCalendarExportNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarExportNameTransaction.php', 'PhabricatorCalendarExportPHIDType' => 'applications/calendar/phid/PhabricatorCalendarExportPHIDType.php', 'PhabricatorCalendarExportQuery' => 'applications/calendar/query/PhabricatorCalendarExportQuery.php', 'PhabricatorCalendarExportQueryKeyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarExportQueryKeyTransaction.php', 'PhabricatorCalendarExportSearchEngine' => 'applications/calendar/query/PhabricatorCalendarExportSearchEngine.php', 'PhabricatorCalendarExportTransaction' => 'applications/calendar/storage/PhabricatorCalendarExportTransaction.php', 'PhabricatorCalendarExportTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarExportTransactionQuery.php', 'PhabricatorCalendarExportTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarExportTransactionType.php', 'PhabricatorCalendarExportViewController' => 'applications/calendar/controller/PhabricatorCalendarExportViewController.php', 'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php', 'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php', + 'PhabricatorCalendarICSFileImportEngine' => 'applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php', + 'PhabricatorCalendarICSImportEngine' => 'applications/calendar/import/PhabricatorCalendarICSImportEngine.php', + 'PhabricatorCalendarICSURIImportEngine' => 'applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php', 'PhabricatorCalendarICSWriter' => 'applications/calendar/util/PhabricatorCalendarICSWriter.php', 'PhabricatorCalendarIconSet' => 'applications/calendar/icon/PhabricatorCalendarIconSet.php', + 'PhabricatorCalendarImport' => 'applications/calendar/storage/PhabricatorCalendarImport.php', + 'PhabricatorCalendarImportDefaultLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportDefaultLogType.php', + 'PhabricatorCalendarImportDeleteController' => 'applications/calendar/controller/PhabricatorCalendarImportDeleteController.php', + 'PhabricatorCalendarImportDeleteTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportDeleteTransaction.php', + 'PhabricatorCalendarImportDisableController' => 'applications/calendar/controller/PhabricatorCalendarImportDisableController.php', + 'PhabricatorCalendarImportDisableTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportDisableTransaction.php', + 'PhabricatorCalendarImportDropController' => 'applications/calendar/controller/PhabricatorCalendarImportDropController.php', + 'PhabricatorCalendarImportDuplicateLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportDuplicateLogType.php', + 'PhabricatorCalendarImportEditController' => 'applications/calendar/controller/PhabricatorCalendarImportEditController.php', + 'PhabricatorCalendarImportEditEngine' => 'applications/calendar/editor/PhabricatorCalendarImportEditEngine.php', + 'PhabricatorCalendarImportEditor' => 'applications/calendar/editor/PhabricatorCalendarImportEditor.php', + 'PhabricatorCalendarImportEmptyLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportEmptyLogType.php', + 'PhabricatorCalendarImportEngine' => 'applications/calendar/import/PhabricatorCalendarImportEngine.php', + 'PhabricatorCalendarImportEpochLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportEpochLogType.php', + 'PhabricatorCalendarImportFetchLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportFetchLogType.php', + 'PhabricatorCalendarImportFrequencyLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportFrequencyLogType.php', + 'PhabricatorCalendarImportICSFileTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php', + 'PhabricatorCalendarImportICSLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportICSLogType.php', + 'PhabricatorCalendarImportICSURITransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSURITransaction.php', + 'PhabricatorCalendarImportIgnoredNodeLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportIgnoredNodeLogType.php', + 'PhabricatorCalendarImportListController' => 'applications/calendar/controller/PhabricatorCalendarImportListController.php', + 'PhabricatorCalendarImportLog' => 'applications/calendar/storage/PhabricatorCalendarImportLog.php', + 'PhabricatorCalendarImportLogListController' => 'applications/calendar/controller/PhabricatorCalendarImportLogListController.php', + 'PhabricatorCalendarImportLogQuery' => 'applications/calendar/query/PhabricatorCalendarImportLogQuery.php', + 'PhabricatorCalendarImportLogSearchEngine' => 'applications/calendar/query/PhabricatorCalendarImportLogSearchEngine.php', + 'PhabricatorCalendarImportLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportLogType.php', + 'PhabricatorCalendarImportLogView' => 'applications/calendar/view/PhabricatorCalendarImportLogView.php', + 'PhabricatorCalendarImportNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportNameTransaction.php', + 'PhabricatorCalendarImportOriginalLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportOriginalLogType.php', + 'PhabricatorCalendarImportOrphanLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportOrphanLogType.php', + 'PhabricatorCalendarImportPHIDType' => 'applications/calendar/phid/PhabricatorCalendarImportPHIDType.php', + 'PhabricatorCalendarImportQuery' => 'applications/calendar/query/PhabricatorCalendarImportQuery.php', + 'PhabricatorCalendarImportSearchEngine' => 'applications/calendar/query/PhabricatorCalendarImportSearchEngine.php', + 'PhabricatorCalendarImportTransaction' => 'applications/calendar/storage/PhabricatorCalendarImportTransaction.php', + 'PhabricatorCalendarImportTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarImportTransactionQuery.php', + 'PhabricatorCalendarImportTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarImportTransactionType.php', + 'PhabricatorCalendarImportUpdateLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportUpdateLogType.php', + 'PhabricatorCalendarImportViewController' => 'applications/calendar/controller/PhabricatorCalendarImportViewController.php', 'PhabricatorCalendarRemarkupRule' => 'applications/calendar/remarkup/PhabricatorCalendarRemarkupRule.php', 'PhabricatorCalendarReplyHandler' => 'applications/calendar/mail/PhabricatorCalendarReplyHandler.php', 'PhabricatorCalendarSchemaSpec' => 'applications/calendar/storage/PhabricatorCalendarSchemaSpec.php', 'PhabricatorCampfireProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php', 'PhabricatorCelerityApplication' => 'applications/celerity/application/PhabricatorCelerityApplication.php', 'PhabricatorCelerityTestCase' => '__tests__/PhabricatorCelerityTestCase.php', 'PhabricatorChangeParserTestCase' => 'applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php', 'PhabricatorChangesetResponse' => 'infrastructure/diff/PhabricatorChangesetResponse.php', 'PhabricatorChatLogApplication' => 'applications/chatlog/application/PhabricatorChatLogApplication.php', 'PhabricatorChatLogChannel' => 'applications/chatlog/storage/PhabricatorChatLogChannel.php', 'PhabricatorChatLogChannelListController' => 'applications/chatlog/controller/PhabricatorChatLogChannelListController.php', 'PhabricatorChatLogChannelLogController' => 'applications/chatlog/controller/PhabricatorChatLogChannelLogController.php', 'PhabricatorChatLogChannelQuery' => 'applications/chatlog/query/PhabricatorChatLogChannelQuery.php', 'PhabricatorChatLogController' => 'applications/chatlog/controller/PhabricatorChatLogController.php', 'PhabricatorChatLogDAO' => 'applications/chatlog/storage/PhabricatorChatLogDAO.php', 'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php', 'PhabricatorChatLogQuery' => 'applications/chatlog/query/PhabricatorChatLogQuery.php', 'PhabricatorChunkedFileStorageEngine' => 'applications/files/engine/PhabricatorChunkedFileStorageEngine.php', 'PhabricatorClusterConfigOptions' => 'applications/config/option/PhabricatorClusterConfigOptions.php', 'PhabricatorClusterDatabasesConfigOptionType' => 'infrastructure/cluster/PhabricatorClusterDatabasesConfigOptionType.php', 'PhabricatorClusterException' => 'infrastructure/cluster/PhabricatorClusterException.php', 'PhabricatorClusterExceptionHandler' => 'infrastructure/cluster/PhabricatorClusterExceptionHandler.php', 'PhabricatorClusterImpossibleWriteException' => 'infrastructure/cluster/PhabricatorClusterImpossibleWriteException.php', 'PhabricatorClusterImproperWriteException' => 'infrastructure/cluster/PhabricatorClusterImproperWriteException.php', 'PhabricatorClusterStrandedException' => 'infrastructure/cluster/PhabricatorClusterStrandedException.php', 'PhabricatorColumnProxyInterface' => 'applications/project/interface/PhabricatorColumnProxyInterface.php', 'PhabricatorColumnsEditField' => 'applications/transactions/editfield/PhabricatorColumnsEditField.php', 'PhabricatorCommentEditEngineExtension' => 'applications/transactions/engineextension/PhabricatorCommentEditEngineExtension.php', 'PhabricatorCommentEditField' => 'applications/transactions/editfield/PhabricatorCommentEditField.php', 'PhabricatorCommentEditType' => 'applications/transactions/edittype/PhabricatorCommentEditType.php', 'PhabricatorCommitBranchesField' => 'applications/repository/customfield/PhabricatorCommitBranchesField.php', 'PhabricatorCommitCustomField' => 'applications/repository/customfield/PhabricatorCommitCustomField.php', 'PhabricatorCommitMergedCommitsField' => 'applications/repository/customfield/PhabricatorCommitMergedCommitsField.php', 'PhabricatorCommitRepositoryField' => 'applications/repository/customfield/PhabricatorCommitRepositoryField.php', 'PhabricatorCommitSearchEngine' => 'applications/audit/query/PhabricatorCommitSearchEngine.php', 'PhabricatorCommitTagsField' => 'applications/repository/customfield/PhabricatorCommitTagsField.php', 'PhabricatorCommonPasswords' => 'applications/auth/constants/PhabricatorCommonPasswords.php', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php', 'PhabricatorConduitApplication' => 'applications/conduit/application/PhabricatorConduitApplication.php', 'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/PhabricatorConduitConsoleController.php', 'PhabricatorConduitContentSource' => 'infrastructure/contentsource/PhabricatorConduitContentSource.php', 'PhabricatorConduitController' => 'applications/conduit/controller/PhabricatorConduitController.php', 'PhabricatorConduitDAO' => 'applications/conduit/storage/PhabricatorConduitDAO.php', 'PhabricatorConduitEditField' => 'applications/transactions/editfield/PhabricatorConduitEditField.php', 'PhabricatorConduitListController' => 'applications/conduit/controller/PhabricatorConduitListController.php', 'PhabricatorConduitLogController' => 'applications/conduit/controller/PhabricatorConduitLogController.php', 'PhabricatorConduitLogQuery' => 'applications/conduit/query/PhabricatorConduitLogQuery.php', 'PhabricatorConduitLogSearchEngine' => 'applications/conduit/query/PhabricatorConduitLogSearchEngine.php', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php', 'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php', 'PhabricatorConduitRequestExceptionHandler' => 'aphront/handler/PhabricatorConduitRequestExceptionHandler.php', 'PhabricatorConduitResultInterface' => 'applications/conduit/interface/PhabricatorConduitResultInterface.php', 'PhabricatorConduitSearchEngine' => 'applications/conduit/query/PhabricatorConduitSearchEngine.php', 'PhabricatorConduitSearchFieldSpecification' => 'applications/conduit/interface/PhabricatorConduitSearchFieldSpecification.php', 'PhabricatorConduitTestCase' => '__tests__/PhabricatorConduitTestCase.php', 'PhabricatorConduitToken' => 'applications/conduit/storage/PhabricatorConduitToken.php', 'PhabricatorConduitTokenController' => 'applications/conduit/controller/PhabricatorConduitTokenController.php', 'PhabricatorConduitTokenEditController' => 'applications/conduit/controller/PhabricatorConduitTokenEditController.php', 'PhabricatorConduitTokenHandshakeController' => 'applications/conduit/controller/PhabricatorConduitTokenHandshakeController.php', 'PhabricatorConduitTokenQuery' => 'applications/conduit/query/PhabricatorConduitTokenQuery.php', 'PhabricatorConduitTokenTerminateController' => 'applications/conduit/controller/PhabricatorConduitTokenTerminateController.php', 'PhabricatorConduitTokensSettingsPanel' => 'applications/conduit/settings/PhabricatorConduitTokensSettingsPanel.php', 'PhabricatorConfigAllController' => 'applications/config/controller/PhabricatorConfigAllController.php', 'PhabricatorConfigApplication' => 'applications/config/application/PhabricatorConfigApplication.php', 'PhabricatorConfigApplicationController' => 'applications/config/controller/PhabricatorConfigApplicationController.php', 'PhabricatorConfigCacheController' => 'applications/config/controller/PhabricatorConfigCacheController.php', 'PhabricatorConfigClusterDatabasesController' => 'applications/config/controller/PhabricatorConfigClusterDatabasesController.php', 'PhabricatorConfigClusterNotificationsController' => 'applications/config/controller/PhabricatorConfigClusterNotificationsController.php', 'PhabricatorConfigClusterRepositoriesController' => 'applications/config/controller/PhabricatorConfigClusterRepositoriesController.php', 'PhabricatorConfigCollectorsModule' => 'applications/config/module/PhabricatorConfigCollectorsModule.php', 'PhabricatorConfigColumnSchema' => 'applications/config/schema/PhabricatorConfigColumnSchema.php', 'PhabricatorConfigConfigPHIDType' => 'applications/config/phid/PhabricatorConfigConfigPHIDType.php', 'PhabricatorConfigConstants' => 'applications/config/constants/PhabricatorConfigConstants.php', 'PhabricatorConfigController' => 'applications/config/controller/PhabricatorConfigController.php', 'PhabricatorConfigCoreSchemaSpec' => 'applications/config/schema/PhabricatorConfigCoreSchemaSpec.php', 'PhabricatorConfigDatabaseController' => 'applications/config/controller/PhabricatorConfigDatabaseController.php', 'PhabricatorConfigDatabaseIssueController' => 'applications/config/controller/PhabricatorConfigDatabaseIssueController.php', 'PhabricatorConfigDatabaseSchema' => 'applications/config/schema/PhabricatorConfigDatabaseSchema.php', 'PhabricatorConfigDatabaseSource' => 'infrastructure/env/PhabricatorConfigDatabaseSource.php', 'PhabricatorConfigDatabaseStatusController' => 'applications/config/controller/PhabricatorConfigDatabaseStatusController.php', 'PhabricatorConfigDefaultSource' => 'infrastructure/env/PhabricatorConfigDefaultSource.php', 'PhabricatorConfigDictionarySource' => 'infrastructure/env/PhabricatorConfigDictionarySource.php', 'PhabricatorConfigEdgeModule' => 'applications/config/module/PhabricatorConfigEdgeModule.php', 'PhabricatorConfigEditController' => 'applications/config/controller/PhabricatorConfigEditController.php', 'PhabricatorConfigEditor' => 'applications/config/editor/PhabricatorConfigEditor.php', 'PhabricatorConfigEntry' => 'applications/config/storage/PhabricatorConfigEntry.php', 'PhabricatorConfigEntryDAO' => 'applications/config/storage/PhabricatorConfigEntryDAO.php', 'PhabricatorConfigEntryQuery' => 'applications/config/query/PhabricatorConfigEntryQuery.php', 'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php', 'PhabricatorConfigGroupConstants' => 'applications/config/constants/PhabricatorConfigGroupConstants.php', 'PhabricatorConfigGroupController' => 'applications/config/controller/PhabricatorConfigGroupController.php', 'PhabricatorConfigHTTPParameterTypesModule' => 'applications/config/module/PhabricatorConfigHTTPParameterTypesModule.php', 'PhabricatorConfigHistoryController' => 'applications/config/controller/PhabricatorConfigHistoryController.php', 'PhabricatorConfigIgnoreController' => 'applications/config/controller/PhabricatorConfigIgnoreController.php', 'PhabricatorConfigIssueListController' => 'applications/config/controller/PhabricatorConfigIssueListController.php', 'PhabricatorConfigIssuePanelController' => 'applications/config/controller/PhabricatorConfigIssuePanelController.php', 'PhabricatorConfigIssueViewController' => 'applications/config/controller/PhabricatorConfigIssueViewController.php', 'PhabricatorConfigJSON' => 'applications/config/json/PhabricatorConfigJSON.php', 'PhabricatorConfigJSONOptionType' => 'applications/config/custom/PhabricatorConfigJSONOptionType.php', 'PhabricatorConfigKeySchema' => 'applications/config/schema/PhabricatorConfigKeySchema.php', 'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php', 'PhabricatorConfigLocalSource' => 'infrastructure/env/PhabricatorConfigLocalSource.php', 'PhabricatorConfigManagementDeleteWorkflow' => 'applications/config/management/PhabricatorConfigManagementDeleteWorkflow.php', 'PhabricatorConfigManagementGetWorkflow' => 'applications/config/management/PhabricatorConfigManagementGetWorkflow.php', 'PhabricatorConfigManagementListWorkflow' => 'applications/config/management/PhabricatorConfigManagementListWorkflow.php', 'PhabricatorConfigManagementMigrateWorkflow' => 'applications/config/management/PhabricatorConfigManagementMigrateWorkflow.php', 'PhabricatorConfigManagementSetWorkflow' => 'applications/config/management/PhabricatorConfigManagementSetWorkflow.php', 'PhabricatorConfigManagementWorkflow' => 'applications/config/management/PhabricatorConfigManagementWorkflow.php', 'PhabricatorConfigModule' => 'applications/config/module/PhabricatorConfigModule.php', 'PhabricatorConfigModuleController' => 'applications/config/controller/PhabricatorConfigModuleController.php', 'PhabricatorConfigOption' => 'applications/config/option/PhabricatorConfigOption.php', 'PhabricatorConfigOptionType' => 'applications/config/custom/PhabricatorConfigOptionType.php', 'PhabricatorConfigPHIDModule' => 'applications/config/module/PhabricatorConfigPHIDModule.php', 'PhabricatorConfigPageView' => 'applications/config/view/PhabricatorConfigPageView.php', 'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php', 'PhabricatorConfigPurgeCacheController' => 'applications/config/controller/PhabricatorConfigPurgeCacheController.php', 'PhabricatorConfigRequestExceptionHandlerModule' => 'applications/config/module/PhabricatorConfigRequestExceptionHandlerModule.php', 'PhabricatorConfigResponse' => 'applications/config/response/PhabricatorConfigResponse.php', 'PhabricatorConfigSchemaQuery' => 'applications/config/schema/PhabricatorConfigSchemaQuery.php', 'PhabricatorConfigSchemaSpec' => 'applications/config/schema/PhabricatorConfigSchemaSpec.php', 'PhabricatorConfigServerSchema' => 'applications/config/schema/PhabricatorConfigServerSchema.php', 'PhabricatorConfigSetupCheckModule' => 'applications/config/module/PhabricatorConfigSetupCheckModule.php', 'PhabricatorConfigSiteModule' => 'applications/config/module/PhabricatorConfigSiteModule.php', 'PhabricatorConfigSiteSource' => 'infrastructure/env/PhabricatorConfigSiteSource.php', 'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php', 'PhabricatorConfigStackSource' => 'infrastructure/env/PhabricatorConfigStackSource.php', 'PhabricatorConfigStorageSchema' => 'applications/config/schema/PhabricatorConfigStorageSchema.php', 'PhabricatorConfigTableSchema' => 'applications/config/schema/PhabricatorConfigTableSchema.php', 'PhabricatorConfigTransaction' => 'applications/config/storage/PhabricatorConfigTransaction.php', 'PhabricatorConfigTransactionQuery' => 'applications/config/query/PhabricatorConfigTransactionQuery.php', 'PhabricatorConfigValidationException' => 'applications/config/exception/PhabricatorConfigValidationException.php', 'PhabricatorConfigVersionController' => 'applications/config/controller/PhabricatorConfigVersionController.php', 'PhabricatorConpherenceApplication' => 'applications/conpherence/application/PhabricatorConpherenceApplication.php', 'PhabricatorConpherenceColumnMinimizeSetting' => 'applications/settings/setting/PhabricatorConpherenceColumnMinimizeSetting.php', 'PhabricatorConpherenceColumnVisibleSetting' => 'applications/settings/setting/PhabricatorConpherenceColumnVisibleSetting.php', 'PhabricatorConpherenceNotificationsSetting' => 'applications/settings/setting/PhabricatorConpherenceNotificationsSetting.php', 'PhabricatorConpherencePreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php', 'PhabricatorConpherenceThreadPHIDType' => 'applications/conpherence/phid/PhabricatorConpherenceThreadPHIDType.php', 'PhabricatorConpherenceWidgetVisibleSetting' => 'applications/settings/setting/PhabricatorConpherenceWidgetVisibleSetting.php', 'PhabricatorConsoleApplication' => 'applications/console/application/PhabricatorConsoleApplication.php', 'PhabricatorConsoleContentSource' => 'infrastructure/contentsource/PhabricatorConsoleContentSource.php', 'PhabricatorContentSource' => 'infrastructure/contentsource/PhabricatorContentSource.php', 'PhabricatorContentSourceModule' => 'infrastructure/contentsource/PhabricatorContentSourceModule.php', 'PhabricatorContentSourceView' => 'infrastructure/contentsource/PhabricatorContentSourceView.php', 'PhabricatorContributedToObjectEdgeType' => 'applications/transactions/edges/PhabricatorContributedToObjectEdgeType.php', 'PhabricatorController' => 'applications/base/controller/PhabricatorController.php', 'PhabricatorCookies' => 'applications/auth/constants/PhabricatorCookies.php', 'PhabricatorCoreConfigOptions' => 'applications/config/option/PhabricatorCoreConfigOptions.php', 'PhabricatorCoreCreateTransaction' => 'applications/transactions/xaction/PhabricatorCoreCreateTransaction.php', 'PhabricatorCoreTransactionType' => 'applications/transactions/xaction/PhabricatorCoreTransactionType.php', 'PhabricatorCoreVoidTransaction' => 'applications/transactions/xaction/PhabricatorCoreVoidTransaction.php', 'PhabricatorCountdown' => 'applications/countdown/storage/PhabricatorCountdown.php', 'PhabricatorCountdownApplication' => 'applications/countdown/application/PhabricatorCountdownApplication.php', 'PhabricatorCountdownController' => 'applications/countdown/controller/PhabricatorCountdownController.php', 'PhabricatorCountdownCountdownPHIDType' => 'applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php', 'PhabricatorCountdownDAO' => 'applications/countdown/storage/PhabricatorCountdownDAO.php', 'PhabricatorCountdownDefaultEditCapability' => 'applications/countdown/capability/PhabricatorCountdownDefaultEditCapability.php', 'PhabricatorCountdownDefaultViewCapability' => 'applications/countdown/capability/PhabricatorCountdownDefaultViewCapability.php', 'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/PhabricatorCountdownDeleteController.php', 'PhabricatorCountdownEditController' => 'applications/countdown/controller/PhabricatorCountdownEditController.php', 'PhabricatorCountdownEditEngine' => 'applications/countdown/editor/PhabricatorCountdownEditEngine.php', 'PhabricatorCountdownEditor' => 'applications/countdown/editor/PhabricatorCountdownEditor.php', 'PhabricatorCountdownListController' => 'applications/countdown/controller/PhabricatorCountdownListController.php', 'PhabricatorCountdownMailReceiver' => 'applications/countdown/mail/PhabricatorCountdownMailReceiver.php', 'PhabricatorCountdownQuery' => 'applications/countdown/query/PhabricatorCountdownQuery.php', 'PhabricatorCountdownRemarkupRule' => 'applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php', 'PhabricatorCountdownReplyHandler' => 'applications/countdown/mail/PhabricatorCountdownReplyHandler.php', 'PhabricatorCountdownSchemaSpec' => 'applications/countdown/storage/PhabricatorCountdownSchemaSpec.php', 'PhabricatorCountdownSearchEngine' => 'applications/countdown/query/PhabricatorCountdownSearchEngine.php', 'PhabricatorCountdownTransaction' => 'applications/countdown/storage/PhabricatorCountdownTransaction.php', 'PhabricatorCountdownTransactionComment' => 'applications/countdown/storage/PhabricatorCountdownTransactionComment.php', 'PhabricatorCountdownTransactionQuery' => 'applications/countdown/query/PhabricatorCountdownTransactionQuery.php', 'PhabricatorCountdownView' => 'applications/countdown/view/PhabricatorCountdownView.php', 'PhabricatorCountdownViewController' => 'applications/countdown/controller/PhabricatorCountdownViewController.php', 'PhabricatorCursorPagedPolicyAwareQuery' => 'infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php', 'PhabricatorCustomField' => 'infrastructure/customfield/field/PhabricatorCustomField.php', 'PhabricatorCustomFieldAttachment' => 'infrastructure/customfield/field/PhabricatorCustomFieldAttachment.php', 'PhabricatorCustomFieldConfigOptionType' => 'infrastructure/customfield/config/PhabricatorCustomFieldConfigOptionType.php', 'PhabricatorCustomFieldDataNotAvailableException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldDataNotAvailableException.php', 'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php', 'PhabricatorCustomFieldEditField' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php', 'PhabricatorCustomFieldEditType' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditType.php', 'PhabricatorCustomFieldFulltextEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldFulltextEngineExtension.php', 'PhabricatorCustomFieldHeraldField' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldField.php', 'PhabricatorCustomFieldHeraldFieldGroup' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldFieldGroup.php', 'PhabricatorCustomFieldImplementationIncompleteException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldImplementationIncompleteException.php', 'PhabricatorCustomFieldIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldIndexStorage.php', 'PhabricatorCustomFieldInterface' => 'infrastructure/customfield/interface/PhabricatorCustomFieldInterface.php', 'PhabricatorCustomFieldList' => 'infrastructure/customfield/field/PhabricatorCustomFieldList.php', 'PhabricatorCustomFieldMonogramParser' => 'infrastructure/customfield/parser/PhabricatorCustomFieldMonogramParser.php', 'PhabricatorCustomFieldNotAttachedException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotAttachedException.php', 'PhabricatorCustomFieldNotProxyException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotProxyException.php', 'PhabricatorCustomFieldNumericIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldNumericIndexStorage.php', 'PhabricatorCustomFieldSearchEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldSearchEngineExtension.php', 'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php', 'PhabricatorCustomFieldStorageQuery' => 'infrastructure/customfield/query/PhabricatorCustomFieldStorageQuery.php', 'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php', 'PhabricatorCustomLogoConfigType' => 'applications/config/custom/PhabricatorCustomLogoConfigType.php', 'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php', 'PhabricatorDaemonBulkJobController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobController.php', 'PhabricatorDaemonBulkJobListController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobListController.php', 'PhabricatorDaemonBulkJobMonitorController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobMonitorController.php', 'PhabricatorDaemonBulkJobViewController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobViewController.php', 'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/PhabricatorDaemonConsoleController.php', 'PhabricatorDaemonContentSource' => 'infrastructure/daemon/contentsource/PhabricatorDaemonContentSource.php', 'PhabricatorDaemonController' => 'applications/daemon/controller/PhabricatorDaemonController.php', 'PhabricatorDaemonDAO' => 'applications/daemon/storage/PhabricatorDaemonDAO.php', 'PhabricatorDaemonEventListener' => 'applications/daemon/event/PhabricatorDaemonEventListener.php', 'PhabricatorDaemonLog' => 'applications/daemon/storage/PhabricatorDaemonLog.php', 'PhabricatorDaemonLogEvent' => 'applications/daemon/storage/PhabricatorDaemonLogEvent.php', 'PhabricatorDaemonLogEventGarbageCollector' => 'applications/daemon/garbagecollector/PhabricatorDaemonLogEventGarbageCollector.php', 'PhabricatorDaemonLogEventViewController' => 'applications/daemon/controller/PhabricatorDaemonLogEventViewController.php', 'PhabricatorDaemonLogEventsView' => 'applications/daemon/view/PhabricatorDaemonLogEventsView.php', 'PhabricatorDaemonLogGarbageCollector' => 'applications/daemon/garbagecollector/PhabricatorDaemonLogGarbageCollector.php', 'PhabricatorDaemonLogListController' => 'applications/daemon/controller/PhabricatorDaemonLogListController.php', 'PhabricatorDaemonLogListView' => 'applications/daemon/view/PhabricatorDaemonLogListView.php', 'PhabricatorDaemonLogQuery' => 'applications/daemon/query/PhabricatorDaemonLogQuery.php', 'PhabricatorDaemonLogViewController' => 'applications/daemon/controller/PhabricatorDaemonLogViewController.php', 'PhabricatorDaemonManagementDebugWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementDebugWorkflow.php', 'PhabricatorDaemonManagementLaunchWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementLaunchWorkflow.php', 'PhabricatorDaemonManagementListWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementListWorkflow.php', 'PhabricatorDaemonManagementLogWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementLogWorkflow.php', 'PhabricatorDaemonManagementReloadWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementReloadWorkflow.php', 'PhabricatorDaemonManagementRestartWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementRestartWorkflow.php', 'PhabricatorDaemonManagementStartWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementStartWorkflow.php', 'PhabricatorDaemonManagementStatusWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementStatusWorkflow.php', 'PhabricatorDaemonManagementStopWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementStopWorkflow.php', 'PhabricatorDaemonManagementWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementWorkflow.php', 'PhabricatorDaemonOverseerModule' => 'infrastructure/daemon/overseer/PhabricatorDaemonOverseerModule.php', 'PhabricatorDaemonReference' => 'infrastructure/daemon/control/PhabricatorDaemonReference.php', 'PhabricatorDaemonTaskGarbageCollector' => 'applications/daemon/garbagecollector/PhabricatorDaemonTaskGarbageCollector.php', 'PhabricatorDaemonTasksTableView' => 'applications/daemon/view/PhabricatorDaemonTasksTableView.php', 'PhabricatorDaemonsApplication' => 'applications/daemon/application/PhabricatorDaemonsApplication.php', 'PhabricatorDaemonsSetupCheck' => 'applications/config/check/PhabricatorDaemonsSetupCheck.php', 'PhabricatorDailyRoutineTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorDailyRoutineTriggerClock.php', 'PhabricatorDarkConsoleSetting' => 'applications/settings/setting/PhabricatorDarkConsoleSetting.php', 'PhabricatorDarkConsoleTabSetting' => 'applications/settings/setting/PhabricatorDarkConsoleTabSetting.php', 'PhabricatorDarkConsoleVisibleSetting' => 'applications/settings/setting/PhabricatorDarkConsoleVisibleSetting.php', 'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php', 'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php', 'PhabricatorDashboardApplication' => 'applications/dashboard/application/PhabricatorDashboardApplication.php', 'PhabricatorDashboardArchiveController' => 'applications/dashboard/controller/PhabricatorDashboardArchiveController.php', 'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php', 'PhabricatorDashboardCopyController' => 'applications/dashboard/controller/PhabricatorDashboardCopyController.php', 'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php', 'PhabricatorDashboardDashboardHasPanelEdgeType' => 'applications/dashboard/edge/PhabricatorDashboardDashboardHasPanelEdgeType.php', 'PhabricatorDashboardDashboardPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php', 'PhabricatorDashboardEditController' => 'applications/dashboard/controller/PhabricatorDashboardEditController.php', 'PhabricatorDashboardInstall' => 'applications/dashboard/storage/PhabricatorDashboardInstall.php', 'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/PhabricatorDashboardInstallController.php', 'PhabricatorDashboardLayoutConfig' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php', 'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php', 'PhabricatorDashboardManageController' => 'applications/dashboard/controller/PhabricatorDashboardManageController.php', 'PhabricatorDashboardMovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardMovePanelController.php', 'PhabricatorDashboardPanel' => 'applications/dashboard/storage/PhabricatorDashboardPanel.php', 'PhabricatorDashboardPanelArchiveController' => 'applications/dashboard/controller/PhabricatorDashboardPanelArchiveController.php', 'PhabricatorDashboardPanelCoreCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelCoreCustomField.php', 'PhabricatorDashboardPanelCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelCustomField.php', 'PhabricatorDashboardPanelEditConduitAPIMethod' => 'applications/dashboard/conduit/PhabricatorDashboardPanelEditConduitAPIMethod.php', 'PhabricatorDashboardPanelEditController' => 'applications/dashboard/controller/PhabricatorDashboardPanelEditController.php', 'PhabricatorDashboardPanelEditEngine' => 'applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php', 'PhabricatorDashboardPanelEditproController' => 'applications/dashboard/controller/PhabricatorDashboardPanelEditproController.php', 'PhabricatorDashboardPanelHasDashboardEdgeType' => 'applications/dashboard/edge/PhabricatorDashboardPanelHasDashboardEdgeType.php', 'PhabricatorDashboardPanelListController' => 'applications/dashboard/controller/PhabricatorDashboardPanelListController.php', 'PhabricatorDashboardPanelPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php', 'PhabricatorDashboardPanelQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelQuery.php', 'PhabricatorDashboardPanelRenderController' => 'applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php', 'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php', 'PhabricatorDashboardPanelSearchApplicationCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php', 'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php', 'PhabricatorDashboardPanelSearchQueryCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php', 'PhabricatorDashboardPanelTabsCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php', 'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php', 'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php', 'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php', 'PhabricatorDashboardPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelType.php', 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php', 'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php', 'PhabricatorDashboardQueryPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php', 'PhabricatorDashboardRemarkupRule' => 'applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php', 'PhabricatorDashboardRemovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php', 'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php', 'PhabricatorDashboardSchemaSpec' => 'applications/dashboard/storage/PhabricatorDashboardSchemaSpec.php', 'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php', 'PhabricatorDashboardTabsPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php', 'PhabricatorDashboardTextPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php', 'PhabricatorDashboardTransaction' => 'applications/dashboard/storage/PhabricatorDashboardTransaction.php', 'PhabricatorDashboardTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php', 'PhabricatorDashboardTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardTransactionQuery.php', 'PhabricatorDashboardUninstallController' => 'applications/dashboard/controller/PhabricatorDashboardUninstallController.php', 'PhabricatorDashboardViewController' => 'applications/dashboard/controller/PhabricatorDashboardViewController.php', 'PhabricatorDataCacheSpec' => 'applications/cache/spec/PhabricatorDataCacheSpec.php', 'PhabricatorDataNotAttachedException' => 'infrastructure/storage/lisk/PhabricatorDataNotAttachedException.php', 'PhabricatorDatabaseHealthRecord' => 'infrastructure/cluster/PhabricatorDatabaseHealthRecord.php', 'PhabricatorDatabaseRef' => 'infrastructure/cluster/PhabricatorDatabaseRef.php', 'PhabricatorDatabaseSetupCheck' => 'applications/config/check/PhabricatorDatabaseSetupCheck.php', 'PhabricatorDatasourceEditField' => 'applications/transactions/editfield/PhabricatorDatasourceEditField.php', 'PhabricatorDatasourceEditType' => 'applications/transactions/edittype/PhabricatorDatasourceEditType.php', 'PhabricatorDateFormatSetting' => 'applications/settings/setting/PhabricatorDateFormatSetting.php', 'PhabricatorDateTimeSettingsPanel' => 'applications/settings/panel/PhabricatorDateTimeSettingsPanel.php', 'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php', 'PhabricatorDefaultRequestExceptionHandler' => 'aphront/handler/PhabricatorDefaultRequestExceptionHandler.php', 'PhabricatorDefaultSyntaxStyle' => 'infrastructure/syntax/PhabricatorDefaultSyntaxStyle.php', 'PhabricatorDesktopNotificationsSetting' => 'applications/settings/setting/PhabricatorDesktopNotificationsSetting.php', 'PhabricatorDesktopNotificationsSettingsPanel' => 'applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php', 'PhabricatorDestructibleInterface' => 'applications/system/interface/PhabricatorDestructibleInterface.php', 'PhabricatorDestructionEngine' => 'applications/system/engine/PhabricatorDestructionEngine.php', 'PhabricatorDestructionEngineExtension' => 'applications/system/engine/PhabricatorDestructionEngineExtension.php', 'PhabricatorDestructionEngineExtensionModule' => 'applications/system/engine/PhabricatorDestructionEngineExtensionModule.php', 'PhabricatorDeveloperConfigOptions' => 'applications/config/option/PhabricatorDeveloperConfigOptions.php', 'PhabricatorDeveloperPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorDeveloperPreferencesSettingsPanel.php', 'PhabricatorDiffInlineCommentQuery' => 'infrastructure/diff/query/PhabricatorDiffInlineCommentQuery.php', 'PhabricatorDiffPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorDiffPreferencesSettingsPanel.php', 'PhabricatorDifferenceEngine' => 'infrastructure/diff/PhabricatorDifferenceEngine.php', 'PhabricatorDifferentialApplication' => 'applications/differential/application/PhabricatorDifferentialApplication.php', 'PhabricatorDifferentialAttachCommitWorkflow' => 'applications/differential/management/PhabricatorDifferentialAttachCommitWorkflow.php', 'PhabricatorDifferentialConfigOptions' => 'applications/differential/config/PhabricatorDifferentialConfigOptions.php', 'PhabricatorDifferentialExtractWorkflow' => 'applications/differential/management/PhabricatorDifferentialExtractWorkflow.php', 'PhabricatorDifferentialManagementWorkflow' => 'applications/differential/management/PhabricatorDifferentialManagementWorkflow.php', 'PhabricatorDifferentialRevisionTestDataGenerator' => 'applications/differential/lipsum/PhabricatorDifferentialRevisionTestDataGenerator.php', 'PhabricatorDiffusionApplication' => 'applications/diffusion/application/PhabricatorDiffusionApplication.php', 'PhabricatorDiffusionBlameSetting' => 'applications/settings/setting/PhabricatorDiffusionBlameSetting.php', 'PhabricatorDiffusionColorSetting' => 'applications/settings/setting/PhabricatorDiffusionColorSetting.php', 'PhabricatorDiffusionConfigOptions' => 'applications/diffusion/config/PhabricatorDiffusionConfigOptions.php', 'PhabricatorDisabledUserController' => 'applications/auth/controller/PhabricatorDisabledUserController.php', 'PhabricatorDisplayPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorDisplayPreferencesSettingsPanel.php', 'PhabricatorDisqusAuthProvider' => 'applications/auth/provider/PhabricatorDisqusAuthProvider.php', 'PhabricatorDividerProfilePanel' => 'applications/search/profilepanel/PhabricatorDividerProfilePanel.php', 'PhabricatorDivinerApplication' => 'applications/diviner/application/PhabricatorDivinerApplication.php', 'PhabricatorDoorkeeperApplication' => 'applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php', 'PhabricatorDraft' => 'applications/draft/storage/PhabricatorDraft.php', 'PhabricatorDraftDAO' => 'applications/draft/storage/PhabricatorDraftDAO.php', 'PhabricatorDrydockApplication' => 'applications/drydock/application/PhabricatorDrydockApplication.php', 'PhabricatorEdgeConfig' => 'infrastructure/edges/constants/PhabricatorEdgeConfig.php', 'PhabricatorEdgeConstants' => 'infrastructure/edges/constants/PhabricatorEdgeConstants.php', 'PhabricatorEdgeCycleException' => 'infrastructure/edges/exception/PhabricatorEdgeCycleException.php', 'PhabricatorEdgeEditType' => 'applications/transactions/edittype/PhabricatorEdgeEditType.php', 'PhabricatorEdgeEditor' => 'infrastructure/edges/editor/PhabricatorEdgeEditor.php', 'PhabricatorEdgeGraph' => 'infrastructure/edges/util/PhabricatorEdgeGraph.php', 'PhabricatorEdgeQuery' => 'infrastructure/edges/query/PhabricatorEdgeQuery.php', 'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php', 'PhabricatorEdgeType' => 'infrastructure/edges/type/PhabricatorEdgeType.php', 'PhabricatorEdgeTypeTestCase' => 'infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php', 'PhabricatorEdgesDestructionEngineExtension' => 'infrastructure/edges/engineextension/PhabricatorEdgesDestructionEngineExtension.php', 'PhabricatorEditEngine' => 'applications/transactions/editengine/PhabricatorEditEngine.php', 'PhabricatorEditEngineAPIMethod' => 'applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php', 'PhabricatorEditEngineColumnsCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineColumnsCommentAction.php', 'PhabricatorEditEngineCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineCommentAction.php', 'PhabricatorEditEngineConfiguration' => 'applications/transactions/storage/PhabricatorEditEngineConfiguration.php', 'PhabricatorEditEngineConfigurationDefaultCreateController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultCreateController.php', 'PhabricatorEditEngineConfigurationDefaultsController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultsController.php', 'PhabricatorEditEngineConfigurationDisableController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationDisableController.php', 'PhabricatorEditEngineConfigurationEditController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationEditController.php', 'PhabricatorEditEngineConfigurationEditEngine' => 'applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php', 'PhabricatorEditEngineConfigurationEditor' => 'applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php', 'PhabricatorEditEngineConfigurationIsEditController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationIsEditController.php', 'PhabricatorEditEngineConfigurationListController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php', 'PhabricatorEditEngineConfigurationLockController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationLockController.php', 'PhabricatorEditEngineConfigurationPHIDType' => 'applications/transactions/phid/PhabricatorEditEngineConfigurationPHIDType.php', 'PhabricatorEditEngineConfigurationQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php', 'PhabricatorEditEngineConfigurationReorderController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationReorderController.php', 'PhabricatorEditEngineConfigurationSaveController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSaveController.php', 'PhabricatorEditEngineConfigurationSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php', 'PhabricatorEditEngineConfigurationSortController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSortController.php', 'PhabricatorEditEngineConfigurationTransaction' => 'applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php', 'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php', 'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php', 'PhabricatorEditEngineController' => 'applications/transactions/controller/PhabricatorEditEngineController.php', 'PhabricatorEditEngineCreateQuickActions' => 'applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php', 'PhabricatorEditEngineExtension' => 'applications/transactions/engineextension/PhabricatorEditEngineExtension.php', 'PhabricatorEditEngineExtensionModule' => 'applications/transactions/engineextension/PhabricatorEditEngineExtensionModule.php', 'PhabricatorEditEngineListController' => 'applications/transactions/controller/PhabricatorEditEngineListController.php', 'PhabricatorEditEnginePointsCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEnginePointsCommentAction.php', 'PhabricatorEditEngineQuery' => 'applications/transactions/query/PhabricatorEditEngineQuery.php', 'PhabricatorEditEngineSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineSearchEngine.php', 'PhabricatorEditEngineSelectCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineSelectCommentAction.php', 'PhabricatorEditEngineSettingsPanel' => 'applications/settings/panel/PhabricatorEditEngineSettingsPanel.php', 'PhabricatorEditEngineTokenizerCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineTokenizerCommentAction.php', 'PhabricatorEditField' => 'applications/transactions/editfield/PhabricatorEditField.php', 'PhabricatorEditPage' => 'applications/transactions/editengine/PhabricatorEditPage.php', 'PhabricatorEditType' => 'applications/transactions/edittype/PhabricatorEditType.php', 'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php', 'PhabricatorEditorMultipleSetting' => 'applications/settings/setting/PhabricatorEditorMultipleSetting.php', 'PhabricatorEditorSetting' => 'applications/settings/setting/PhabricatorEditorSetting.php', 'PhabricatorElasticFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php', 'PhabricatorElasticSearchSetupCheck' => 'applications/config/check/PhabricatorElasticSearchSetupCheck.php', 'PhabricatorEmailAddressesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php', 'PhabricatorEmailContentSource' => 'applications/metamta/contentsource/PhabricatorEmailContentSource.php', 'PhabricatorEmailDeliverySettingsPanel' => 'applications/settings/panel/PhabricatorEmailDeliverySettingsPanel.php', 'PhabricatorEmailFormatSetting' => 'applications/settings/setting/PhabricatorEmailFormatSetting.php', 'PhabricatorEmailFormatSettingsPanel' => 'applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php', 'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php', 'PhabricatorEmailNotificationsSetting' => 'applications/settings/setting/PhabricatorEmailNotificationsSetting.php', 'PhabricatorEmailPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php', 'PhabricatorEmailRePrefixSetting' => 'applications/settings/setting/PhabricatorEmailRePrefixSetting.php', 'PhabricatorEmailSelfActionsSetting' => 'applications/settings/setting/PhabricatorEmailSelfActionsSetting.php', 'PhabricatorEmailTagsSetting' => 'applications/settings/setting/PhabricatorEmailTagsSetting.php', 'PhabricatorEmailVarySubjectsSetting' => 'applications/settings/setting/PhabricatorEmailVarySubjectsSetting.php', 'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php', 'PhabricatorEmbedFileRemarkupRule' => 'applications/files/markup/PhabricatorEmbedFileRemarkupRule.php', 'PhabricatorEmojiRemarkupRule' => 'applications/macro/markup/PhabricatorEmojiRemarkupRule.php', 'PhabricatorEmojiTranslation' => 'infrastructure/internationalization/translation/PhabricatorEmojiTranslation.php', 'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php', 'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php', 'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php', 'PhabricatorEpochEditField' => 'applications/transactions/editfield/PhabricatorEpochEditField.php', 'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php', 'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php', 'PhabricatorEventListener' => 'infrastructure/events/PhabricatorEventListener.php', 'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php', 'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php', 'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php', 'PhabricatorExtendedPolicyInterface' => 'applications/policy/interface/PhabricatorExtendedPolicyInterface.php', 'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php', 'PhabricatorExtensionsSetupCheck' => 'applications/config/check/PhabricatorExtensionsSetupCheck.php', 'PhabricatorExternalAccount' => 'applications/people/storage/PhabricatorExternalAccount.php', 'PhabricatorExternalAccountQuery' => 'applications/auth/query/PhabricatorExternalAccountQuery.php', 'PhabricatorExternalAccountsSettingsPanel' => 'applications/settings/panel/PhabricatorExternalAccountsSettingsPanel.php', 'PhabricatorExtraConfigSetupCheck' => 'applications/config/check/PhabricatorExtraConfigSetupCheck.php', 'PhabricatorFacebookAuthProvider' => 'applications/auth/provider/PhabricatorFacebookAuthProvider.php', 'PhabricatorFactAggregate' => 'applications/fact/storage/PhabricatorFactAggregate.php', 'PhabricatorFactApplication' => 'applications/fact/application/PhabricatorFactApplication.php', 'PhabricatorFactChartController' => 'applications/fact/controller/PhabricatorFactChartController.php', 'PhabricatorFactController' => 'applications/fact/controller/PhabricatorFactController.php', 'PhabricatorFactCountEngine' => 'applications/fact/engine/PhabricatorFactCountEngine.php', 'PhabricatorFactCursor' => 'applications/fact/storage/PhabricatorFactCursor.php', 'PhabricatorFactDAO' => 'applications/fact/storage/PhabricatorFactDAO.php', 'PhabricatorFactDaemon' => 'applications/fact/daemon/PhabricatorFactDaemon.php', 'PhabricatorFactEngine' => 'applications/fact/engine/PhabricatorFactEngine.php', 'PhabricatorFactEngineTestCase' => 'applications/fact/engine/__tests__/PhabricatorFactEngineTestCase.php', 'PhabricatorFactHomeController' => 'applications/fact/controller/PhabricatorFactHomeController.php', 'PhabricatorFactLastUpdatedEngine' => 'applications/fact/engine/PhabricatorFactLastUpdatedEngine.php', 'PhabricatorFactManagementAnalyzeWorkflow' => 'applications/fact/management/PhabricatorFactManagementAnalyzeWorkflow.php', 'PhabricatorFactManagementCursorsWorkflow' => 'applications/fact/management/PhabricatorFactManagementCursorsWorkflow.php', 'PhabricatorFactManagementDestroyWorkflow' => 'applications/fact/management/PhabricatorFactManagementDestroyWorkflow.php', 'PhabricatorFactManagementListWorkflow' => 'applications/fact/management/PhabricatorFactManagementListWorkflow.php', 'PhabricatorFactManagementStatusWorkflow' => 'applications/fact/management/PhabricatorFactManagementStatusWorkflow.php', 'PhabricatorFactManagementWorkflow' => 'applications/fact/management/PhabricatorFactManagementWorkflow.php', 'PhabricatorFactRaw' => 'applications/fact/storage/PhabricatorFactRaw.php', 'PhabricatorFactSimpleSpec' => 'applications/fact/spec/PhabricatorFactSimpleSpec.php', 'PhabricatorFactSpec' => 'applications/fact/spec/PhabricatorFactSpec.php', 'PhabricatorFactUpdateIterator' => 'applications/fact/extract/PhabricatorFactUpdateIterator.php', 'PhabricatorFaxContentSource' => 'infrastructure/contentsource/PhabricatorFaxContentSource.php', 'PhabricatorFeedApplication' => 'applications/feed/application/PhabricatorFeedApplication.php', 'PhabricatorFeedBuilder' => 'applications/feed/builder/PhabricatorFeedBuilder.php', 'PhabricatorFeedConfigOptions' => 'applications/feed/config/PhabricatorFeedConfigOptions.php', 'PhabricatorFeedController' => 'applications/feed/controller/PhabricatorFeedController.php', 'PhabricatorFeedDAO' => 'applications/feed/storage/PhabricatorFeedDAO.php', 'PhabricatorFeedDetailController' => 'applications/feed/controller/PhabricatorFeedDetailController.php', 'PhabricatorFeedListController' => 'applications/feed/controller/PhabricatorFeedListController.php', 'PhabricatorFeedManagementRepublishWorkflow' => 'applications/feed/management/PhabricatorFeedManagementRepublishWorkflow.php', 'PhabricatorFeedManagementWorkflow' => 'applications/feed/management/PhabricatorFeedManagementWorkflow.php', 'PhabricatorFeedQuery' => 'applications/feed/query/PhabricatorFeedQuery.php', 'PhabricatorFeedSearchEngine' => 'applications/feed/query/PhabricatorFeedSearchEngine.php', 'PhabricatorFeedStory' => 'applications/feed/story/PhabricatorFeedStory.php', 'PhabricatorFeedStoryData' => 'applications/feed/storage/PhabricatorFeedStoryData.php', 'PhabricatorFeedStoryNotification' => 'applications/notification/storage/PhabricatorFeedStoryNotification.php', 'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php', 'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFileAES256StorageFormat' => 'applications/files/format/PhabricatorFileAES256StorageFormat.php', 'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php', 'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php', 'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php', 'PhabricatorFileChunkQuery' => 'applications/files/query/PhabricatorFileChunkQuery.php', 'PhabricatorFileCommentController' => 'applications/files/controller/PhabricatorFileCommentController.php', 'PhabricatorFileComposeController' => 'applications/files/controller/PhabricatorFileComposeController.php', 'PhabricatorFileController' => 'applications/files/controller/PhabricatorFileController.php', 'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php', 'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php', 'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php', 'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php', 'PhabricatorFileEditController' => 'applications/files/controller/PhabricatorFileEditController.php', + 'PhabricatorFileEditField' => 'applications/transactions/editfield/PhabricatorFileEditField.php', 'PhabricatorFileEditor' => 'applications/files/editor/PhabricatorFileEditor.php', 'PhabricatorFileExternalRequest' => 'applications/files/storage/PhabricatorFileExternalRequest.php', 'PhabricatorFileExternalRequestGarbageCollector' => 'applications/files/garbagecollector/PhabricatorFileExternalRequestGarbageCollector.php', 'PhabricatorFileFilePHIDType' => 'applications/files/phid/PhabricatorFileFilePHIDType.php', 'PhabricatorFileHasObjectEdgeType' => 'applications/files/edge/PhabricatorFileHasObjectEdgeType.php', 'PhabricatorFileIconSetSelectController' => 'applications/files/controller/PhabricatorFileIconSetSelectController.php', 'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php', 'PhabricatorFileImageProxyController' => 'applications/files/controller/PhabricatorFileImageProxyController.php', 'PhabricatorFileImageTransform' => 'applications/files/transform/PhabricatorFileImageTransform.php', 'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php', 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', 'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php', 'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php', 'PhabricatorFileROT13StorageFormat' => 'applications/files/format/PhabricatorFileROT13StorageFormat.php', 'PhabricatorFileRawStorageFormat' => 'applications/files/format/PhabricatorFileRawStorageFormat.php', 'PhabricatorFileSchemaSpec' => 'applications/files/storage/PhabricatorFileSchemaSpec.php', 'PhabricatorFileSearchEngine' => 'applications/files/query/PhabricatorFileSearchEngine.php', 'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php', 'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php', 'PhabricatorFileStorageEngine' => 'applications/files/engine/PhabricatorFileStorageEngine.php', 'PhabricatorFileStorageEngineTestCase' => 'applications/files/engine/__tests__/PhabricatorFileStorageEngineTestCase.php', 'PhabricatorFileStorageFormat' => 'applications/files/format/PhabricatorFileStorageFormat.php', 'PhabricatorFileStorageFormatTestCase' => 'applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php', 'PhabricatorFileTemporaryGarbageCollector' => 'applications/files/garbagecollector/PhabricatorFileTemporaryGarbageCollector.php', 'PhabricatorFileTestCase' => 'applications/files/storage/__tests__/PhabricatorFileTestCase.php', 'PhabricatorFileTestDataGenerator' => 'applications/files/lipsum/PhabricatorFileTestDataGenerator.php', 'PhabricatorFileThumbnailTransform' => 'applications/files/transform/PhabricatorFileThumbnailTransform.php', 'PhabricatorFileTransaction' => 'applications/files/storage/PhabricatorFileTransaction.php', 'PhabricatorFileTransactionComment' => 'applications/files/storage/PhabricatorFileTransactionComment.php', 'PhabricatorFileTransactionQuery' => 'applications/files/query/PhabricatorFileTransactionQuery.php', 'PhabricatorFileTransform' => 'applications/files/transform/PhabricatorFileTransform.php', 'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php', 'PhabricatorFileTransformListController' => 'applications/files/controller/PhabricatorFileTransformListController.php', 'PhabricatorFileTransformTestCase' => 'applications/files/transform/__tests__/PhabricatorFileTransformTestCase.php', 'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php', 'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php', 'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php', 'PhabricatorFileUploadSource' => 'applications/files/uploadsource/PhabricatorFileUploadSource.php', 'PhabricatorFileinfoSetupCheck' => 'applications/config/check/PhabricatorFileinfoSetupCheck.php', 'PhabricatorFilesApplication' => 'applications/files/application/PhabricatorFilesApplication.php', 'PhabricatorFilesApplicationStorageEnginePanel' => 'applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php', 'PhabricatorFilesBuiltinFile' => 'applications/files/builtin/PhabricatorFilesBuiltinFile.php', 'PhabricatorFilesComposeIconBuiltinFile' => 'applications/files/builtin/PhabricatorFilesComposeIconBuiltinFile.php', 'PhabricatorFilesConfigOptions' => 'applications/files/config/PhabricatorFilesConfigOptions.php', 'PhabricatorFilesManagementCatWorkflow' => 'applications/files/management/PhabricatorFilesManagementCatWorkflow.php', 'PhabricatorFilesManagementCompactWorkflow' => 'applications/files/management/PhabricatorFilesManagementCompactWorkflow.php', 'PhabricatorFilesManagementCycleWorkflow' => 'applications/files/management/PhabricatorFilesManagementCycleWorkflow.php', 'PhabricatorFilesManagementEncodeWorkflow' => 'applications/files/management/PhabricatorFilesManagementEncodeWorkflow.php', 'PhabricatorFilesManagementEnginesWorkflow' => 'applications/files/management/PhabricatorFilesManagementEnginesWorkflow.php', 'PhabricatorFilesManagementGenerateKeyWorkflow' => 'applications/files/management/PhabricatorFilesManagementGenerateKeyWorkflow.php', 'PhabricatorFilesManagementMigrateWorkflow' => 'applications/files/management/PhabricatorFilesManagementMigrateWorkflow.php', 'PhabricatorFilesManagementPurgeWorkflow' => 'applications/files/management/PhabricatorFilesManagementPurgeWorkflow.php', 'PhabricatorFilesManagementRebuildWorkflow' => 'applications/files/management/PhabricatorFilesManagementRebuildWorkflow.php', 'PhabricatorFilesManagementWorkflow' => 'applications/files/management/PhabricatorFilesManagementWorkflow.php', 'PhabricatorFilesOnDiskBuiltinFile' => 'applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php', 'PhabricatorFilesOutboundRequestAction' => 'applications/files/action/PhabricatorFilesOutboundRequestAction.php', 'PhabricatorFiletreeVisibleSetting' => 'applications/settings/setting/PhabricatorFiletreeVisibleSetting.php', 'PhabricatorFlag' => 'applications/flag/storage/PhabricatorFlag.php', 'PhabricatorFlagAddFlagHeraldAction' => 'applications/flag/herald/PhabricatorFlagAddFlagHeraldAction.php', 'PhabricatorFlagColor' => 'applications/flag/constants/PhabricatorFlagColor.php', 'PhabricatorFlagConstants' => 'applications/flag/constants/PhabricatorFlagConstants.php', 'PhabricatorFlagController' => 'applications/flag/controller/PhabricatorFlagController.php', 'PhabricatorFlagDAO' => 'applications/flag/storage/PhabricatorFlagDAO.php', 'PhabricatorFlagDeleteController' => 'applications/flag/controller/PhabricatorFlagDeleteController.php', 'PhabricatorFlagDestructionEngineExtension' => 'applications/flag/engineextension/PhabricatorFlagDestructionEngineExtension.php', 'PhabricatorFlagEditController' => 'applications/flag/controller/PhabricatorFlagEditController.php', 'PhabricatorFlagListController' => 'applications/flag/controller/PhabricatorFlagListController.php', 'PhabricatorFlagQuery' => 'applications/flag/query/PhabricatorFlagQuery.php', 'PhabricatorFlagSearchEngine' => 'applications/flag/query/PhabricatorFlagSearchEngine.php', 'PhabricatorFlagSelectControl' => 'applications/flag/view/PhabricatorFlagSelectControl.php', 'PhabricatorFlaggableInterface' => 'applications/flag/interface/PhabricatorFlaggableInterface.php', 'PhabricatorFlagsApplication' => 'applications/flag/application/PhabricatorFlagsApplication.php', 'PhabricatorFlagsUIEventListener' => 'applications/flag/events/PhabricatorFlagsUIEventListener.php', 'PhabricatorFulltextEngine' => 'applications/search/index/PhabricatorFulltextEngine.php', 'PhabricatorFulltextEngineExtension' => 'applications/search/index/PhabricatorFulltextEngineExtension.php', 'PhabricatorFulltextEngineExtensionModule' => 'applications/search/index/PhabricatorFulltextEngineExtensionModule.php', 'PhabricatorFulltextIndexEngineExtension' => 'applications/search/engineextension/PhabricatorFulltextIndexEngineExtension.php', 'PhabricatorFulltextInterface' => 'applications/search/interface/PhabricatorFulltextInterface.php', 'PhabricatorFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorFulltextStorageEngine.php', 'PhabricatorFundApplication' => 'applications/fund/application/PhabricatorFundApplication.php', 'PhabricatorGDSetupCheck' => 'applications/config/check/PhabricatorGDSetupCheck.php', 'PhabricatorGarbageCollector' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php', 'PhabricatorGarbageCollectorManagementCollectWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementCollectWorkflow.php', 'PhabricatorGarbageCollectorManagementSetPolicyWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementSetPolicyWorkflow.php', 'PhabricatorGarbageCollectorManagementWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementWorkflow.php', 'PhabricatorGestureUIExample' => 'applications/uiexample/examples/PhabricatorGestureUIExample.php', 'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php', 'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php', 'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php', 'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php', 'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php', 'PhabricatorGuideApplication' => 'applications/guides/application/PhabricatorGuideApplication.php', 'PhabricatorGuideController' => 'applications/guides/controller/PhabricatorGuideController.php', 'PhabricatorGuideInstallModule' => 'applications/guides/module/PhabricatorGuideInstallModule.php', 'PhabricatorGuideItemView' => 'applications/guides/view/PhabricatorGuideItemView.php', 'PhabricatorGuideListView' => 'applications/guides/view/PhabricatorGuideListView.php', 'PhabricatorGuideModule' => 'applications/guides/module/PhabricatorGuideModule.php', 'PhabricatorGuideModuleController' => 'applications/guides/controller/PhabricatorGuideModuleController.php', 'PhabricatorGuideQuickStartModule' => 'applications/guides/module/PhabricatorGuideQuickStartModule.php', 'PhabricatorHTTPParameterTypeTableView' => 'applications/config/view/PhabricatorHTTPParameterTypeTableView.php', 'PhabricatorHandleList' => 'applications/phid/handle/pool/PhabricatorHandleList.php', 'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php', 'PhabricatorHandlePool' => 'applications/phid/handle/pool/PhabricatorHandlePool.php', 'PhabricatorHandlePoolTestCase' => 'applications/phid/handle/pool/__tests__/PhabricatorHandlePoolTestCase.php', 'PhabricatorHandleQuery' => 'applications/phid/query/PhabricatorHandleQuery.php', 'PhabricatorHandleRemarkupRule' => 'applications/phid/remarkup/PhabricatorHandleRemarkupRule.php', 'PhabricatorHandlesEditField' => 'applications/transactions/editfield/PhabricatorHandlesEditField.php', 'PhabricatorHarbormasterApplication' => 'applications/harbormaster/application/PhabricatorHarbormasterApplication.php', 'PhabricatorHash' => 'infrastructure/util/PhabricatorHash.php', 'PhabricatorHashTestCase' => 'infrastructure/util/__tests__/PhabricatorHashTestCase.php', 'PhabricatorHelpApplication' => 'applications/help/application/PhabricatorHelpApplication.php', 'PhabricatorHelpController' => 'applications/help/controller/PhabricatorHelpController.php', 'PhabricatorHelpDocumentationController' => 'applications/help/controller/PhabricatorHelpDocumentationController.php', 'PhabricatorHelpEditorProtocolController' => 'applications/help/controller/PhabricatorHelpEditorProtocolController.php', 'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php', 'PhabricatorHelpMainMenuBarExtension' => 'applications/help/extension/PhabricatorHelpMainMenuBarExtension.php', 'PhabricatorHeraldApplication' => 'applications/herald/application/PhabricatorHeraldApplication.php', 'PhabricatorHeraldContentSource' => 'applications/herald/contentsource/PhabricatorHeraldContentSource.php', 'PhabricatorHighSecurityRequestExceptionHandler' => 'aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php', 'PhabricatorHomeApplication' => 'applications/home/application/PhabricatorHomeApplication.php', 'PhabricatorHomeController' => 'applications/home/controller/PhabricatorHomeController.php', 'PhabricatorHomeMainController' => 'applications/home/controller/PhabricatorHomeMainController.php', 'PhabricatorHomePreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php', 'PhabricatorHomeQuickCreateController' => 'applications/home/controller/PhabricatorHomeQuickCreateController.php', 'PhabricatorHovercardEngineExtension' => 'applications/search/engineextension/PhabricatorHovercardEngineExtension.php', 'PhabricatorHovercardEngineExtensionModule' => 'applications/search/engineextension/PhabricatorHovercardEngineExtensionModule.php', 'PhabricatorHunksManagementMigrateWorkflow' => 'applications/differential/management/PhabricatorHunksManagementMigrateWorkflow.php', 'PhabricatorHunksManagementWorkflow' => 'applications/differential/management/PhabricatorHunksManagementWorkflow.php', 'PhabricatorIDsSearchEngineExtension' => 'applications/search/engineextension/PhabricatorIDsSearchEngineExtension.php', 'PhabricatorIDsSearchField' => 'applications/search/field/PhabricatorIDsSearchField.php', 'PhabricatorIRCProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php', 'PhabricatorIconRemarkupRule' => 'applications/macro/markup/PhabricatorIconRemarkupRule.php', 'PhabricatorIconSet' => 'applications/files/iconset/PhabricatorIconSet.php', 'PhabricatorIconSetEditField' => 'applications/transactions/editfield/PhabricatorIconSetEditField.php', 'PhabricatorIconSetIcon' => 'applications/files/iconset/PhabricatorIconSetIcon.php', 'PhabricatorImageMacroRemarkupRule' => 'applications/macro/markup/PhabricatorImageMacroRemarkupRule.php', 'PhabricatorImageRemarkupRule' => 'applications/files/markup/PhabricatorImageRemarkupRule.php', 'PhabricatorImageTransformer' => 'applications/files/PhabricatorImageTransformer.php', 'PhabricatorImagemagickSetupCheck' => 'applications/config/check/PhabricatorImagemagickSetupCheck.php', 'PhabricatorInFlightErrorView' => 'applications/config/view/PhabricatorInFlightErrorView.php', 'PhabricatorIndexEngine' => 'applications/search/index/PhabricatorIndexEngine.php', 'PhabricatorIndexEngineExtension' => 'applications/search/index/PhabricatorIndexEngineExtension.php', 'PhabricatorIndexEngineExtensionModule' => 'applications/search/index/PhabricatorIndexEngineExtensionModule.php', 'PhabricatorInfrastructureTestCase' => '__tests__/PhabricatorInfrastructureTestCase.php', 'PhabricatorInlineCommentController' => 'infrastructure/diff/PhabricatorInlineCommentController.php', 'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/PhabricatorInlineCommentInterface.php', 'PhabricatorInlineCommentPreviewController' => 'infrastructure/diff/PhabricatorInlineCommentPreviewController.php', 'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php', 'PhabricatorInstructionsEditField' => 'applications/transactions/editfield/PhabricatorInstructionsEditField.php', 'PhabricatorInternalSetting' => 'applications/settings/setting/PhabricatorInternalSetting.php', 'PhabricatorInternationalizationManagementExtractWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php', 'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php', 'PhabricatorInvalidConfigSetupCheck' => 'applications/config/check/PhabricatorInvalidConfigSetupCheck.php', 'PhabricatorIteratedMD5PasswordHasher' => 'infrastructure/util/password/PhabricatorIteratedMD5PasswordHasher.php', 'PhabricatorIteratedMD5PasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php', 'PhabricatorIteratorFileUploadSource' => 'applications/files/uploadsource/PhabricatorIteratorFileUploadSource.php', 'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', 'PhabricatorKeyboardRemarkupRule' => 'infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php', 'PhabricatorKeyring' => 'applications/files/keyring/PhabricatorKeyring.php', 'PhabricatorKeyringConfigOptionType' => 'applications/files/keyring/PhabricatorKeyringConfigOptionType.php', 'PhabricatorLDAPAuthProvider' => 'applications/auth/provider/PhabricatorLDAPAuthProvider.php', 'PhabricatorLegalpadApplication' => 'applications/legalpad/application/PhabricatorLegalpadApplication.php', 'PhabricatorLegalpadConfigOptions' => 'applications/legalpad/config/PhabricatorLegalpadConfigOptions.php', 'PhabricatorLegalpadDocumentPHIDType' => 'applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php', 'PhabricatorLegalpadSignaturePolicyRule' => 'applications/legalpad/policyrule/PhabricatorLegalpadSignaturePolicyRule.php', 'PhabricatorLibraryTestCase' => '__tests__/PhabricatorLibraryTestCase.php', 'PhabricatorLinkProfilePanel' => 'applications/search/profilepanel/PhabricatorLinkProfilePanel.php', 'PhabricatorLipsumArtist' => 'applications/lipsum/image/PhabricatorLipsumArtist.php', 'PhabricatorLipsumContentSource' => 'infrastructure/contentsource/PhabricatorLipsumContentSource.php', 'PhabricatorLipsumGenerateWorkflow' => 'applications/lipsum/management/PhabricatorLipsumGenerateWorkflow.php', 'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php', 'PhabricatorLipsumMondrianArtist' => 'applications/lipsum/image/PhabricatorLipsumMondrianArtist.php', 'PhabricatorLiskDAO' => 'infrastructure/storage/lisk/PhabricatorLiskDAO.php', 'PhabricatorLiskFulltextEngineExtension' => 'applications/search/engineextension/PhabricatorLiskFulltextEngineExtension.php', 'PhabricatorLiskSearchEngineExtension' => 'applications/search/engineextension/PhabricatorLiskSearchEngineExtension.php', 'PhabricatorLiskSerializer' => 'infrastructure/storage/lisk/PhabricatorLiskSerializer.php', 'PhabricatorListFilterUIExample' => 'applications/uiexample/examples/PhabricatorListFilterUIExample.php', 'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php', 'PhabricatorLocalTimeTestCase' => 'view/__tests__/PhabricatorLocalTimeTestCase.php', 'PhabricatorLocaleScopeGuard' => 'infrastructure/internationalization/scope/PhabricatorLocaleScopeGuard.php', 'PhabricatorLocaleScopeGuardTestCase' => 'infrastructure/internationalization/scope/__tests__/PhabricatorLocaleScopeGuardTestCase.php', 'PhabricatorLogTriggerAction' => 'infrastructure/daemon/workers/action/PhabricatorLogTriggerAction.php', 'PhabricatorLogoutController' => 'applications/auth/controller/PhabricatorLogoutController.php', 'PhabricatorLunarPhasePolicyRule' => 'applications/policy/rule/PhabricatorLunarPhasePolicyRule.php', 'PhabricatorMacroApplication' => 'applications/macro/application/PhabricatorMacroApplication.php', 'PhabricatorMacroAudioController' => 'applications/macro/controller/PhabricatorMacroAudioController.php', 'PhabricatorMacroCommentController' => 'applications/macro/controller/PhabricatorMacroCommentController.php', 'PhabricatorMacroConfigOptions' => 'applications/macro/config/PhabricatorMacroConfigOptions.php', 'PhabricatorMacroController' => 'applications/macro/controller/PhabricatorMacroController.php', 'PhabricatorMacroDatasource' => 'applications/macro/typeahead/PhabricatorMacroDatasource.php', 'PhabricatorMacroDisableController' => 'applications/macro/controller/PhabricatorMacroDisableController.php', 'PhabricatorMacroEditController' => 'applications/macro/controller/PhabricatorMacroEditController.php', 'PhabricatorMacroEditor' => 'applications/macro/editor/PhabricatorMacroEditor.php', 'PhabricatorMacroListController' => 'applications/macro/controller/PhabricatorMacroListController.php', 'PhabricatorMacroMacroPHIDType' => 'applications/macro/phid/PhabricatorMacroMacroPHIDType.php', 'PhabricatorMacroMailReceiver' => 'applications/macro/mail/PhabricatorMacroMailReceiver.php', 'PhabricatorMacroManageCapability' => 'applications/macro/capability/PhabricatorMacroManageCapability.php', 'PhabricatorMacroMemeController' => 'applications/macro/controller/PhabricatorMacroMemeController.php', 'PhabricatorMacroMemeDialogController' => 'applications/macro/controller/PhabricatorMacroMemeDialogController.php', 'PhabricatorMacroQuery' => 'applications/macro/query/PhabricatorMacroQuery.php', 'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php', 'PhabricatorMacroSearchEngine' => 'applications/macro/query/PhabricatorMacroSearchEngine.php', 'PhabricatorMacroTransaction' => 'applications/macro/storage/PhabricatorMacroTransaction.php', 'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php', 'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php', 'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php', 'PhabricatorMailEmailHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailHeraldField.php', 'PhabricatorMailEmailHeraldFieldGroup' => 'applications/metamta/herald/PhabricatorMailEmailHeraldFieldGroup.php', 'PhabricatorMailEmailSubjectHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailSubjectHeraldField.php', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php', 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php', 'PhabricatorMailImplementationMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php', 'PhabricatorMailImplementationPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php', 'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php', 'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php', 'PhabricatorMailManagementListInboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php', 'PhabricatorMailManagementListOutboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementListOutboundWorkflow.php', 'PhabricatorMailManagementReceiveTestWorkflow' => 'applications/metamta/management/PhabricatorMailManagementReceiveTestWorkflow.php', 'PhabricatorMailManagementResendWorkflow' => 'applications/metamta/management/PhabricatorMailManagementResendWorkflow.php', 'PhabricatorMailManagementSendTestWorkflow' => 'applications/metamta/management/PhabricatorMailManagementSendTestWorkflow.php', 'PhabricatorMailManagementShowInboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementShowInboundWorkflow.php', 'PhabricatorMailManagementShowOutboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementShowOutboundWorkflow.php', 'PhabricatorMailManagementVolumeWorkflow' => 'applications/metamta/management/PhabricatorMailManagementVolumeWorkflow.php', 'PhabricatorMailManagementWorkflow' => 'applications/metamta/management/PhabricatorMailManagementWorkflow.php', 'PhabricatorMailOutboundMailHeraldAdapter' => 'applications/metamta/herald/PhabricatorMailOutboundMailHeraldAdapter.php', 'PhabricatorMailOutboundRoutingHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingHeraldAction.php', 'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfEmailHeraldAction.php', 'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfNotificationHeraldAction.php', 'PhabricatorMailOutboundStatus' => 'applications/metamta/constants/PhabricatorMailOutboundStatus.php', 'PhabricatorMailReceiver' => 'applications/metamta/receiver/PhabricatorMailReceiver.php', 'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php', 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php', 'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php', 'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php', 'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php', 'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php', 'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php', 'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php', 'PhabricatorMainMenuView' => 'view/page/menu/PhabricatorMainMenuView.php', 'PhabricatorManagementWorkflow' => 'infrastructure/management/PhabricatorManagementWorkflow.php', 'PhabricatorManiphestApplication' => 'applications/maniphest/application/PhabricatorManiphestApplication.php', 'PhabricatorManiphestConfigOptions' => 'applications/maniphest/config/PhabricatorManiphestConfigOptions.php', 'PhabricatorManiphestTaskTestDataGenerator' => 'applications/maniphest/lipsum/PhabricatorManiphestTaskTestDataGenerator.php', 'PhabricatorMarkupCache' => 'applications/cache/storage/PhabricatorMarkupCache.php', 'PhabricatorMarkupEngine' => 'infrastructure/markup/PhabricatorMarkupEngine.php', 'PhabricatorMarkupInterface' => 'infrastructure/markup/PhabricatorMarkupInterface.php', 'PhabricatorMarkupOneOff' => 'infrastructure/markup/PhabricatorMarkupOneOff.php', 'PhabricatorMarkupPreviewController' => 'infrastructure/markup/PhabricatorMarkupPreviewController.php', 'PhabricatorMemeRemarkupRule' => 'applications/macro/markup/PhabricatorMemeRemarkupRule.php', 'PhabricatorMentionRemarkupRule' => 'applications/people/markup/PhabricatorMentionRemarkupRule.php', 'PhabricatorMentionableInterface' => 'applications/transactions/interface/PhabricatorMentionableInterface.php', 'PhabricatorMercurialGraphStream' => 'applications/repository/daemon/PhabricatorMercurialGraphStream.php', 'PhabricatorMetaMTAActor' => 'applications/metamta/query/PhabricatorMetaMTAActor.php', 'PhabricatorMetaMTAActorQuery' => 'applications/metamta/query/PhabricatorMetaMTAActorQuery.php', 'PhabricatorMetaMTAApplication' => 'applications/metamta/application/PhabricatorMetaMTAApplication.php', 'PhabricatorMetaMTAApplicationEmail' => 'applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php', 'PhabricatorMetaMTAApplicationEmailDatasource' => 'applications/metamta/typeahead/PhabricatorMetaMTAApplicationEmailDatasource.php', 'PhabricatorMetaMTAApplicationEmailEditor' => 'applications/metamta/editor/PhabricatorMetaMTAApplicationEmailEditor.php', 'PhabricatorMetaMTAApplicationEmailHeraldField' => 'applications/metamta/herald/PhabricatorMetaMTAApplicationEmailHeraldField.php', 'PhabricatorMetaMTAApplicationEmailPHIDType' => 'applications/phid/PhabricatorMetaMTAApplicationEmailPHIDType.php', 'PhabricatorMetaMTAApplicationEmailPanel' => 'applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php', 'PhabricatorMetaMTAApplicationEmailQuery' => 'applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php', 'PhabricatorMetaMTAApplicationEmailTransaction' => 'applications/metamta/storage/PhabricatorMetaMTAApplicationEmailTransaction.php', 'PhabricatorMetaMTAApplicationEmailTransactionQuery' => 'applications/metamta/query/PhabricatorMetaMTAApplicationEmailTransactionQuery.php', 'PhabricatorMetaMTAAttachment' => 'applications/metamta/storage/PhabricatorMetaMTAAttachment.php', 'PhabricatorMetaMTAConfigOptions' => 'applications/config/option/PhabricatorMetaMTAConfigOptions.php', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/PhabricatorMetaMTAController.php', 'PhabricatorMetaMTADAO' => 'applications/metamta/storage/PhabricatorMetaMTADAO.php', 'PhabricatorMetaMTAEmailBodyParser' => 'applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'applications/metamta/parser/__tests__/PhabricatorMetaMTAEmailBodyParserTestCase.php', 'PhabricatorMetaMTAEmailHeraldAction' => 'applications/metamta/herald/PhabricatorMetaMTAEmailHeraldAction.php', 'PhabricatorMetaMTAEmailOthersHeraldAction' => 'applications/metamta/herald/PhabricatorMetaMTAEmailOthersHeraldAction.php', 'PhabricatorMetaMTAEmailSelfHeraldAction' => 'applications/metamta/herald/PhabricatorMetaMTAEmailSelfHeraldAction.php', 'PhabricatorMetaMTAErrorMailAction' => 'applications/metamta/action/PhabricatorMetaMTAErrorMailAction.php', 'PhabricatorMetaMTAMail' => 'applications/metamta/storage/PhabricatorMetaMTAMail.php', 'PhabricatorMetaMTAMailBody' => 'applications/metamta/view/PhabricatorMetaMTAMailBody.php', 'PhabricatorMetaMTAMailBodyTestCase' => 'applications/metamta/view/__tests__/PhabricatorMetaMTAMailBodyTestCase.php', 'PhabricatorMetaMTAMailHasRecipientEdgeType' => 'applications/metamta/edge/PhabricatorMetaMTAMailHasRecipientEdgeType.php', 'PhabricatorMetaMTAMailListController' => 'applications/metamta/controller/PhabricatorMetaMTAMailListController.php', 'PhabricatorMetaMTAMailPHIDType' => 'applications/metamta/phid/PhabricatorMetaMTAMailPHIDType.php', 'PhabricatorMetaMTAMailQuery' => 'applications/metamta/query/PhabricatorMetaMTAMailQuery.php', 'PhabricatorMetaMTAMailSearchEngine' => 'applications/metamta/query/PhabricatorMetaMTAMailSearchEngine.php', 'PhabricatorMetaMTAMailSection' => 'applications/metamta/view/PhabricatorMetaMTAMailSection.php', 'PhabricatorMetaMTAMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php', 'PhabricatorMetaMTAMailViewController' => 'applications/metamta/controller/PhabricatorMetaMTAMailViewController.php', 'PhabricatorMetaMTAMailableDatasource' => 'applications/metamta/typeahead/PhabricatorMetaMTAMailableDatasource.php', 'PhabricatorMetaMTAMailableFunctionDatasource' => 'applications/metamta/typeahead/PhabricatorMetaMTAMailableFunctionDatasource.php', 'PhabricatorMetaMTAMailgunReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php', 'PhabricatorMetaMTAMemberQuery' => 'applications/metamta/query/PhabricatorMetaMTAMemberQuery.php', 'PhabricatorMetaMTAPermanentFailureException' => 'applications/metamta/exception/PhabricatorMetaMTAPermanentFailureException.php', 'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php', 'PhabricatorMetaMTAReceivedMailProcessingException' => 'applications/metamta/exception/PhabricatorMetaMTAReceivedMailProcessingException.php', 'PhabricatorMetaMTAReceivedMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php', 'PhabricatorMetaMTASchemaSpec' => 'applications/metamta/storage/PhabricatorMetaMTASchemaSpec.php', 'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php', 'PhabricatorMetaMTAWorker' => 'applications/metamta/PhabricatorMetaMTAWorker.php', 'PhabricatorMetronomicTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorMetronomicTriggerClock.php', 'PhabricatorModularTransaction' => 'applications/transactions/storage/PhabricatorModularTransaction.php', 'PhabricatorModularTransactionType' => 'applications/transactions/storage/PhabricatorModularTransactionType.php', 'PhabricatorMonospacedFontSetting' => 'applications/settings/setting/PhabricatorMonospacedFontSetting.php', 'PhabricatorMonospacedTextareasSetting' => 'applications/settings/setting/PhabricatorMonospacedTextareasSetting.php', 'PhabricatorMotivatorProfilePanel' => 'applications/search/profilepanel/PhabricatorMotivatorProfilePanel.php', 'PhabricatorMultiColumnUIExample' => 'applications/uiexample/examples/PhabricatorMultiColumnUIExample.php', 'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php', 'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php', 'PhabricatorMustVerifyEmailController' => 'applications/auth/controller/PhabricatorMustVerifyEmailController.php', 'PhabricatorMySQLConfigOptions' => 'applications/config/option/PhabricatorMySQLConfigOptions.php', 'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php', 'PhabricatorMySQLFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorMySQLFulltextStorageEngine.php', 'PhabricatorMySQLSetupCheck' => 'applications/config/check/PhabricatorMySQLSetupCheck.php', 'PhabricatorNamedQuery' => 'applications/search/storage/PhabricatorNamedQuery.php', 'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php', 'PhabricatorNavigationRemarkupRule' => 'infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php', 'PhabricatorNeverTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorNeverTriggerClock.php', 'PhabricatorNgramsIndexEngineExtension' => 'applications/search/engineextension/PhabricatorNgramsIndexEngineExtension.php', 'PhabricatorNgramsInterface' => 'applications/search/interface/PhabricatorNgramsInterface.php', 'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php', 'PhabricatorNotificationClearController' => 'applications/notification/controller/PhabricatorNotificationClearController.php', 'PhabricatorNotificationClient' => 'applications/notification/client/PhabricatorNotificationClient.php', 'PhabricatorNotificationConfigOptions' => 'applications/config/option/PhabricatorNotificationConfigOptions.php', 'PhabricatorNotificationController' => 'applications/notification/controller/PhabricatorNotificationController.php', 'PhabricatorNotificationDestructionEngineExtension' => 'applications/notification/engineextension/PhabricatorNotificationDestructionEngineExtension.php', 'PhabricatorNotificationIndividualController' => 'applications/notification/controller/PhabricatorNotificationIndividualController.php', 'PhabricatorNotificationListController' => 'applications/notification/controller/PhabricatorNotificationListController.php', 'PhabricatorNotificationPanelController' => 'applications/notification/controller/PhabricatorNotificationPanelController.php', 'PhabricatorNotificationQuery' => 'applications/notification/query/PhabricatorNotificationQuery.php', 'PhabricatorNotificationSearchEngine' => 'applications/notification/query/PhabricatorNotificationSearchEngine.php', 'PhabricatorNotificationServerRef' => 'applications/notification/client/PhabricatorNotificationServerRef.php', 'PhabricatorNotificationServersConfigOptionType' => 'applications/notification/config/PhabricatorNotificationServersConfigOptionType.php', 'PhabricatorNotificationStatusView' => 'applications/notification/view/PhabricatorNotificationStatusView.php', 'PhabricatorNotificationTestController' => 'applications/notification/controller/PhabricatorNotificationTestController.php', 'PhabricatorNotificationTestFeedStory' => 'applications/notification/feed/PhabricatorNotificationTestFeedStory.php', 'PhabricatorNotificationUIExample' => 'applications/uiexample/examples/PhabricatorNotificationUIExample.php', 'PhabricatorNotificationsApplication' => 'applications/notification/application/PhabricatorNotificationsApplication.php', 'PhabricatorNuanceApplication' => 'applications/nuance/application/PhabricatorNuanceApplication.php', 'PhabricatorOAuth1AuthProvider' => 'applications/auth/provider/PhabricatorOAuth1AuthProvider.php', 'PhabricatorOAuth1SecretTemporaryTokenType' => 'applications/auth/provider/PhabricatorOAuth1SecretTemporaryTokenType.php', 'PhabricatorOAuth2AuthProvider' => 'applications/auth/provider/PhabricatorOAuth2AuthProvider.php', 'PhabricatorOAuthAuthProvider' => 'applications/auth/provider/PhabricatorOAuthAuthProvider.php', 'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php', 'PhabricatorOAuthClientAuthorizationQuery' => 'applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php', 'PhabricatorOAuthClientController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientController.php', 'PhabricatorOAuthClientDisableController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientDisableController.php', 'PhabricatorOAuthClientEditController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientEditController.php', 'PhabricatorOAuthClientListController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientListController.php', 'PhabricatorOAuthClientSecretController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientSecretController.php', 'PhabricatorOAuthClientTestController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientTestController.php', 'PhabricatorOAuthClientViewController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientViewController.php', 'PhabricatorOAuthResponse' => 'applications/oauthserver/PhabricatorOAuthResponse.php', 'PhabricatorOAuthServer' => 'applications/oauthserver/PhabricatorOAuthServer.php', 'PhabricatorOAuthServerAccessToken' => 'applications/oauthserver/storage/PhabricatorOAuthServerAccessToken.php', 'PhabricatorOAuthServerApplication' => 'applications/oauthserver/application/PhabricatorOAuthServerApplication.php', 'PhabricatorOAuthServerAuthController' => 'applications/oauthserver/controller/PhabricatorOAuthServerAuthController.php', 'PhabricatorOAuthServerAuthorizationCode' => 'applications/oauthserver/storage/PhabricatorOAuthServerAuthorizationCode.php', 'PhabricatorOAuthServerAuthorizationsSettingsPanel' => 'applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php', 'PhabricatorOAuthServerClient' => 'applications/oauthserver/storage/PhabricatorOAuthServerClient.php', 'PhabricatorOAuthServerClientAuthorizationPHIDType' => 'applications/oauthserver/phid/PhabricatorOAuthServerClientAuthorizationPHIDType.php', 'PhabricatorOAuthServerClientPHIDType' => 'applications/oauthserver/phid/PhabricatorOAuthServerClientPHIDType.php', 'PhabricatorOAuthServerClientQuery' => 'applications/oauthserver/query/PhabricatorOAuthServerClientQuery.php', 'PhabricatorOAuthServerClientSearchEngine' => 'applications/oauthserver/query/PhabricatorOAuthServerClientSearchEngine.php', 'PhabricatorOAuthServerController' => 'applications/oauthserver/controller/PhabricatorOAuthServerController.php', 'PhabricatorOAuthServerCreateClientsCapability' => 'applications/oauthserver/capability/PhabricatorOAuthServerCreateClientsCapability.php', 'PhabricatorOAuthServerDAO' => 'applications/oauthserver/storage/PhabricatorOAuthServerDAO.php', 'PhabricatorOAuthServerEditEngine' => 'applications/oauthserver/editor/PhabricatorOAuthServerEditEngine.php', 'PhabricatorOAuthServerEditor' => 'applications/oauthserver/editor/PhabricatorOAuthServerEditor.php', 'PhabricatorOAuthServerSchemaSpec' => 'applications/oauthserver/query/PhabricatorOAuthServerSchemaSpec.php', 'PhabricatorOAuthServerScope' => 'applications/oauthserver/PhabricatorOAuthServerScope.php', 'PhabricatorOAuthServerTestCase' => 'applications/oauthserver/__tests__/PhabricatorOAuthServerTestCase.php', 'PhabricatorOAuthServerTokenController' => 'applications/oauthserver/controller/PhabricatorOAuthServerTokenController.php', 'PhabricatorOAuthServerTransaction' => 'applications/oauthserver/storage/PhabricatorOAuthServerTransaction.php', 'PhabricatorOAuthServerTransactionQuery' => 'applications/oauthserver/query/PhabricatorOAuthServerTransactionQuery.php', 'PhabricatorObjectGraph' => 'infrastructure/graph/PhabricatorObjectGraph.php', 'PhabricatorObjectHandle' => 'applications/phid/PhabricatorObjectHandle.php', 'PhabricatorObjectHasAsanaSubtaskEdgeType' => 'applications/doorkeeper/edge/PhabricatorObjectHasAsanaSubtaskEdgeType.php', 'PhabricatorObjectHasAsanaTaskEdgeType' => 'applications/doorkeeper/edge/PhabricatorObjectHasAsanaTaskEdgeType.php', 'PhabricatorObjectHasContributorEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasContributorEdgeType.php', 'PhabricatorObjectHasFileEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasFileEdgeType.php', 'PhabricatorObjectHasJiraIssueEdgeType' => 'applications/doorkeeper/edge/PhabricatorObjectHasJiraIssueEdgeType.php', 'PhabricatorObjectHasSubscriberEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasSubscriberEdgeType.php', 'PhabricatorObjectHasUnsubscriberEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasUnsubscriberEdgeType.php', 'PhabricatorObjectHasWatcherEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasWatcherEdgeType.php', 'PhabricatorObjectListQuery' => 'applications/phid/query/PhabricatorObjectListQuery.php', 'PhabricatorObjectListQueryTestCase' => 'applications/phid/query/__tests__/PhabricatorObjectListQueryTestCase.php', 'PhabricatorObjectMailReceiver' => 'applications/metamta/receiver/PhabricatorObjectMailReceiver.php', 'PhabricatorObjectMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorObjectMailReceiverTestCase.php', 'PhabricatorObjectMentionedByObjectEdgeType' => 'applications/transactions/edges/PhabricatorObjectMentionedByObjectEdgeType.php', 'PhabricatorObjectMentionsObjectEdgeType' => 'applications/transactions/edges/PhabricatorObjectMentionsObjectEdgeType.php', 'PhabricatorObjectQuery' => 'applications/phid/query/PhabricatorObjectQuery.php', 'PhabricatorObjectRelationship' => 'applications/search/relationship/PhabricatorObjectRelationship.php', 'PhabricatorObjectRelationshipList' => 'applications/search/relationship/PhabricatorObjectRelationshipList.php', 'PhabricatorObjectRelationshipSource' => 'applications/search/relationship/PhabricatorObjectRelationshipSource.php', 'PhabricatorObjectRemarkupRule' => 'infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php', 'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php', 'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php', 'PhabricatorOldWorldContentSource' => 'infrastructure/contentsource/PhabricatorOldWorldContentSource.php', 'PhabricatorOlderInlinesSetting' => 'applications/settings/setting/PhabricatorOlderInlinesSetting.php', 'PhabricatorOneTimeTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorOneTimeTriggerClock.php', 'PhabricatorOpcodeCacheSpec' => 'applications/cache/spec/PhabricatorOpcodeCacheSpec.php', 'PhabricatorOptionGroupSetting' => 'applications/settings/setting/PhabricatorOptionGroupSetting.php', 'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php', 'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php', 'PhabricatorOwnersArchiveController' => 'applications/owners/controller/PhabricatorOwnersArchiveController.php', 'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php', 'PhabricatorOwnersConfiguredCustomField' => 'applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php', 'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php', 'PhabricatorOwnersCustomField' => 'applications/owners/customfield/PhabricatorOwnersCustomField.php', 'PhabricatorOwnersCustomFieldNumericIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldNumericIndex.php', 'PhabricatorOwnersCustomFieldStorage' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStorage.php', 'PhabricatorOwnersCustomFieldStringIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStringIndex.php', 'PhabricatorOwnersDAO' => 'applications/owners/storage/PhabricatorOwnersDAO.php', 'PhabricatorOwnersDefaultEditCapability' => 'applications/owners/capability/PhabricatorOwnersDefaultEditCapability.php', 'PhabricatorOwnersDefaultViewCapability' => 'applications/owners/capability/PhabricatorOwnersDefaultViewCapability.php', 'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php', 'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php', 'PhabricatorOwnersListController' => 'applications/owners/controller/PhabricatorOwnersListController.php', 'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php', 'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php', + 'PhabricatorOwnersPackageAuditingTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageAuditingTransaction.php', + 'PhabricatorOwnersPackageAutoreviewTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageAutoreviewTransaction.php', 'PhabricatorOwnersPackageDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php', + 'PhabricatorOwnersPackageDescriptionTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageDescriptionTransaction.php', + 'PhabricatorOwnersPackageDominionTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageDominionTransaction.php', 'PhabricatorOwnersPackageEditEngine' => 'applications/owners/editor/PhabricatorOwnersPackageEditEngine.php', 'PhabricatorOwnersPackageFulltextEngine' => 'applications/owners/query/PhabricatorOwnersPackageFulltextEngine.php', 'PhabricatorOwnersPackageFunctionDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageFunctionDatasource.php', 'PhabricatorOwnersPackageNameNgrams' => 'applications/owners/storage/PhabricatorOwnersPackageNameNgrams.php', + 'PhabricatorOwnersPackageNameTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageNameTransaction.php', 'PhabricatorOwnersPackageOwnerDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageOwnerDatasource.php', + 'PhabricatorOwnersPackageOwnersTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageOwnersTransaction.php', 'PhabricatorOwnersPackagePHIDType' => 'applications/owners/phid/PhabricatorOwnersPackagePHIDType.php', + 'PhabricatorOwnersPackagePathsTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackagePathsTransaction.php', + 'PhabricatorOwnersPackagePrimaryTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackagePrimaryTransaction.php', 'PhabricatorOwnersPackageQuery' => 'applications/owners/query/PhabricatorOwnersPackageQuery.php', 'PhabricatorOwnersPackageRemarkupRule' => 'applications/owners/remarkup/PhabricatorOwnersPackageRemarkupRule.php', 'PhabricatorOwnersPackageSearchEngine' => 'applications/owners/query/PhabricatorOwnersPackageSearchEngine.php', + 'PhabricatorOwnersPackageStatusTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageStatusTransaction.php', 'PhabricatorOwnersPackageTestCase' => 'applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php', 'PhabricatorOwnersPackageTransaction' => 'applications/owners/storage/PhabricatorOwnersPackageTransaction.php', 'PhabricatorOwnersPackageTransactionEditor' => 'applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php', 'PhabricatorOwnersPackageTransactionQuery' => 'applications/owners/query/PhabricatorOwnersPackageTransactionQuery.php', + 'PhabricatorOwnersPackageTransactionType' => 'applications/owners/xaction/PhabricatorOwnersPackageTransactionType.php', 'PhabricatorOwnersPath' => 'applications/owners/storage/PhabricatorOwnersPath.php', 'PhabricatorOwnersPathsController' => 'applications/owners/controller/PhabricatorOwnersPathsController.php', 'PhabricatorOwnersPathsSearchEngineAttachment' => 'applications/owners/engineextension/PhabricatorOwnersPathsSearchEngineAttachment.php', 'PhabricatorOwnersSchemaSpec' => 'applications/owners/storage/PhabricatorOwnersSchemaSpec.php', 'PhabricatorOwnersSearchField' => 'applications/owners/searchfield/PhabricatorOwnersSearchField.php', 'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php', 'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php', 'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php', 'PhabricatorPHIDInterface' => 'applications/phid/interface/PhabricatorPHIDInterface.php', 'PhabricatorPHIDListEditField' => 'applications/transactions/editfield/PhabricatorPHIDListEditField.php', 'PhabricatorPHIDListEditType' => 'applications/transactions/edittype/PhabricatorPHIDListEditType.php', 'PhabricatorPHIDResolver' => 'applications/phid/resolver/PhabricatorPHIDResolver.php', 'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php', 'PhabricatorPHIDTypeTestCase' => 'applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php', 'PhabricatorPHIDsSearchField' => 'applications/search/field/PhabricatorPHIDsSearchField.php', 'PhabricatorPHPASTApplication' => 'applications/phpast/application/PhabricatorPHPASTApplication.php', 'PhabricatorPHPConfigSetupCheck' => 'applications/config/check/PhabricatorPHPConfigSetupCheck.php', 'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php', 'PhabricatorPHPPreflightSetupCheck' => 'applications/config/check/PhabricatorPHPPreflightSetupCheck.php', 'PhabricatorPackagesApplication' => 'applications/packages/application/PhabricatorPackagesApplication.php', 'PhabricatorPackagesController' => 'applications/packages/controller/PhabricatorPackagesController.php', 'PhabricatorPackagesCreatePublisherCapability' => 'applications/packages/capability/PhabricatorPackagesCreatePublisherCapability.php', 'PhabricatorPackagesDAO' => 'applications/packages/storage/PhabricatorPackagesDAO.php', 'PhabricatorPackagesEditEngine' => 'applications/packages/editor/PhabricatorPackagesEditEngine.php', 'PhabricatorPackagesEditor' => 'applications/packages/editor/PhabricatorPackagesEditor.php', 'PhabricatorPackagesNgrams' => 'applications/packages/storage/PhabricatorPackagesNgrams.php', 'PhabricatorPackagesPackage' => 'applications/packages/storage/PhabricatorPackagesPackage.php', 'PhabricatorPackagesPackageController' => 'applications/packages/controller/PhabricatorPackagesPackageController.php', 'PhabricatorPackagesPackageDatasource' => 'applications/packages/typeahead/PhabricatorPackagesPackageDatasource.php', 'PhabricatorPackagesPackageDefaultEditCapability' => 'applications/packages/capability/PhabricatorPackagesPackageDefaultEditCapability.php', 'PhabricatorPackagesPackageDefaultViewCapability' => 'applications/packages/capability/PhabricatorPackagesPackageDefaultViewCapability.php', 'PhabricatorPackagesPackageEditConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPackageEditConduitAPIMethod.php', 'PhabricatorPackagesPackageEditController' => 'applications/packages/controller/PhabricatorPackagesPackageEditController.php', 'PhabricatorPackagesPackageEditEngine' => 'applications/packages/editor/PhabricatorPackagesPackageEditEngine.php', 'PhabricatorPackagesPackageEditor' => 'applications/packages/editor/PhabricatorPackagesPackageEditor.php', 'PhabricatorPackagesPackageKeyTransaction' => 'applications/packages/xaction/package/PhabricatorPackagesPackageKeyTransaction.php', 'PhabricatorPackagesPackageListController' => 'applications/packages/controller/PhabricatorPackagesPackageListController.php', 'PhabricatorPackagesPackageListView' => 'applications/packages/view/PhabricatorPackagesPackageListView.php', 'PhabricatorPackagesPackageNameNgrams' => 'applications/packages/storage/PhabricatorPackagesPackageNameNgrams.php', 'PhabricatorPackagesPackageNameTransaction' => 'applications/packages/xaction/package/PhabricatorPackagesPackageNameTransaction.php', 'PhabricatorPackagesPackagePHIDType' => 'applications/packages/phid/PhabricatorPackagesPackagePHIDType.php', 'PhabricatorPackagesPackagePublisherTransaction' => 'applications/packages/xaction/package/PhabricatorPackagesPackagePublisherTransaction.php', 'PhabricatorPackagesPackageQuery' => 'applications/packages/query/PhabricatorPackagesPackageQuery.php', 'PhabricatorPackagesPackageSearchConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPackageSearchConduitAPIMethod.php', 'PhabricatorPackagesPackageSearchEngine' => 'applications/packages/query/PhabricatorPackagesPackageSearchEngine.php', 'PhabricatorPackagesPackageTransaction' => 'applications/packages/storage/PhabricatorPackagesPackageTransaction.php', 'PhabricatorPackagesPackageTransactionQuery' => 'applications/packages/query/PhabricatorPackagesPackageTransactionQuery.php', 'PhabricatorPackagesPackageTransactionType' => 'applications/packages/xaction/package/PhabricatorPackagesPackageTransactionType.php', 'PhabricatorPackagesPackageViewController' => 'applications/packages/controller/PhabricatorPackagesPackageViewController.php', 'PhabricatorPackagesPublisher' => 'applications/packages/storage/PhabricatorPackagesPublisher.php', 'PhabricatorPackagesPublisherController' => 'applications/packages/controller/PhabricatorPackagesPublisherController.php', 'PhabricatorPackagesPublisherDatasource' => 'applications/packages/typeahead/PhabricatorPackagesPublisherDatasource.php', 'PhabricatorPackagesPublisherDefaultEditCapability' => 'applications/packages/capability/PhabricatorPackagesPublisherDefaultEditCapability.php', 'PhabricatorPackagesPublisherEditConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPublisherEditConduitAPIMethod.php', 'PhabricatorPackagesPublisherEditController' => 'applications/packages/controller/PhabricatorPackagesPublisherEditController.php', 'PhabricatorPackagesPublisherEditEngine' => 'applications/packages/editor/PhabricatorPackagesPublisherEditEngine.php', 'PhabricatorPackagesPublisherEditor' => 'applications/packages/editor/PhabricatorPackagesPublisherEditor.php', 'PhabricatorPackagesPublisherKeyTransaction' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherKeyTransaction.php', 'PhabricatorPackagesPublisherListController' => 'applications/packages/controller/PhabricatorPackagesPublisherListController.php', 'PhabricatorPackagesPublisherListView' => 'applications/packages/view/PhabricatorPackagesPublisherListView.php', 'PhabricatorPackagesPublisherNameNgrams' => 'applications/packages/storage/PhabricatorPackagesPublisherNameNgrams.php', 'PhabricatorPackagesPublisherNameTransaction' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherNameTransaction.php', 'PhabricatorPackagesPublisherPHIDType' => 'applications/packages/phid/PhabricatorPackagesPublisherPHIDType.php', 'PhabricatorPackagesPublisherQuery' => 'applications/packages/query/PhabricatorPackagesPublisherQuery.php', 'PhabricatorPackagesPublisherSearchConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPublisherSearchConduitAPIMethod.php', 'PhabricatorPackagesPublisherSearchEngine' => 'applications/packages/query/PhabricatorPackagesPublisherSearchEngine.php', 'PhabricatorPackagesPublisherTransaction' => 'applications/packages/storage/PhabricatorPackagesPublisherTransaction.php', 'PhabricatorPackagesPublisherTransactionQuery' => 'applications/packages/query/PhabricatorPackagesPublisherTransactionQuery.php', 'PhabricatorPackagesPublisherTransactionType' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherTransactionType.php', 'PhabricatorPackagesPublisherViewController' => 'applications/packages/controller/PhabricatorPackagesPublisherViewController.php', 'PhabricatorPackagesQuery' => 'applications/packages/query/PhabricatorPackagesQuery.php', 'PhabricatorPackagesSchemaSpec' => 'applications/packages/storage/PhabricatorPackagesSchemaSpec.php', 'PhabricatorPackagesTransactionType' => 'applications/packages/xaction/PhabricatorPackagesTransactionType.php', 'PhabricatorPackagesVersion' => 'applications/packages/storage/PhabricatorPackagesVersion.php', 'PhabricatorPackagesVersionController' => 'applications/packages/controller/PhabricatorPackagesVersionController.php', 'PhabricatorPackagesVersionEditConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesVersionEditConduitAPIMethod.php', 'PhabricatorPackagesVersionEditController' => 'applications/packages/controller/PhabricatorPackagesVersionEditController.php', 'PhabricatorPackagesVersionEditEngine' => 'applications/packages/editor/PhabricatorPackagesVersionEditEngine.php', 'PhabricatorPackagesVersionEditor' => 'applications/packages/editor/PhabricatorPackagesVersionEditor.php', 'PhabricatorPackagesVersionListController' => 'applications/packages/controller/PhabricatorPackagesVersionListController.php', 'PhabricatorPackagesVersionListView' => 'applications/packages/view/PhabricatorPackagesVersionListView.php', 'PhabricatorPackagesVersionNameNgrams' => 'applications/packages/storage/PhabricatorPackagesVersionNameNgrams.php', 'PhabricatorPackagesVersionNameTransaction' => 'applications/packages/xaction/version/PhabricatorPackagesVersionNameTransaction.php', 'PhabricatorPackagesVersionPHIDType' => 'applications/packages/phid/PhabricatorPackagesVersionPHIDType.php', 'PhabricatorPackagesVersionPackageTransaction' => 'applications/packages/xaction/version/PhabricatorPackagesVersionPackageTransaction.php', 'PhabricatorPackagesVersionQuery' => 'applications/packages/query/PhabricatorPackagesVersionQuery.php', 'PhabricatorPackagesVersionSearchConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesVersionSearchConduitAPIMethod.php', 'PhabricatorPackagesVersionSearchEngine' => 'applications/packages/query/PhabricatorPackagesVersionSearchEngine.php', 'PhabricatorPackagesVersionTransaction' => 'applications/packages/storage/PhabricatorPackagesVersionTransaction.php', 'PhabricatorPackagesVersionTransactionQuery' => 'applications/packages/query/PhabricatorPackagesVersionTransactionQuery.php', 'PhabricatorPackagesVersionTransactionType' => 'applications/packages/xaction/version/PhabricatorPackagesVersionTransactionType.php', 'PhabricatorPackagesVersionViewController' => 'applications/packages/controller/PhabricatorPackagesVersionViewController.php', 'PhabricatorPackagesView' => 'applications/packages/view/PhabricatorPackagesView.php', 'PhabricatorPagerUIExample' => 'applications/uiexample/examples/PhabricatorPagerUIExample.php', 'PhabricatorPassphraseApplication' => 'applications/passphrase/application/PhabricatorPassphraseApplication.php', 'PhabricatorPasswordAuthProvider' => 'applications/auth/provider/PhabricatorPasswordAuthProvider.php', 'PhabricatorPasswordHasher' => 'infrastructure/util/password/PhabricatorPasswordHasher.php', 'PhabricatorPasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorPasswordHasherTestCase.php', 'PhabricatorPasswordHasherUnavailableException' => 'infrastructure/util/password/PhabricatorPasswordHasherUnavailableException.php', 'PhabricatorPasswordSettingsPanel' => 'applications/settings/panel/PhabricatorPasswordSettingsPanel.php', 'PhabricatorPaste' => 'applications/paste/storage/PhabricatorPaste.php', 'PhabricatorPasteApplication' => 'applications/paste/application/PhabricatorPasteApplication.php', 'PhabricatorPasteArchiveController' => 'applications/paste/controller/PhabricatorPasteArchiveController.php', 'PhabricatorPasteConfigOptions' => 'applications/paste/config/PhabricatorPasteConfigOptions.php', 'PhabricatorPasteContentSearchEngineAttachment' => 'applications/paste/engineextension/PhabricatorPasteContentSearchEngineAttachment.php', 'PhabricatorPasteContentTransaction' => 'applications/paste/xaction/PhabricatorPasteContentTransaction.php', 'PhabricatorPasteController' => 'applications/paste/controller/PhabricatorPasteController.php', 'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php', 'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php', 'PhabricatorPasteEditEngine' => 'applications/paste/editor/PhabricatorPasteEditEngine.php', 'PhabricatorPasteEditor' => 'applications/paste/editor/PhabricatorPasteEditor.php', 'PhabricatorPasteFilenameContextFreeGrammar' => 'applications/paste/lipsum/PhabricatorPasteFilenameContextFreeGrammar.php', 'PhabricatorPasteLanguageTransaction' => 'applications/paste/xaction/PhabricatorPasteLanguageTransaction.php', 'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php', 'PhabricatorPastePastePHIDType' => 'applications/paste/phid/PhabricatorPastePastePHIDType.php', 'PhabricatorPasteQuery' => 'applications/paste/query/PhabricatorPasteQuery.php', 'PhabricatorPasteRawController' => 'applications/paste/controller/PhabricatorPasteRawController.php', 'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php', 'PhabricatorPasteSchemaSpec' => 'applications/paste/storage/PhabricatorPasteSchemaSpec.php', 'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php', 'PhabricatorPasteSnippet' => 'applications/paste/snippet/PhabricatorPasteSnippet.php', 'PhabricatorPasteStatusTransaction' => 'applications/paste/xaction/PhabricatorPasteStatusTransaction.php', 'PhabricatorPasteTestDataGenerator' => 'applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php', 'PhabricatorPasteTitleTransaction' => 'applications/paste/xaction/PhabricatorPasteTitleTransaction.php', 'PhabricatorPasteTransaction' => 'applications/paste/storage/PhabricatorPasteTransaction.php', 'PhabricatorPasteTransactionComment' => 'applications/paste/storage/PhabricatorPasteTransactionComment.php', 'PhabricatorPasteTransactionQuery' => 'applications/paste/query/PhabricatorPasteTransactionQuery.php', 'PhabricatorPasteTransactionType' => 'applications/paste/xaction/PhabricatorPasteTransactionType.php', 'PhabricatorPasteViewController' => 'applications/paste/controller/PhabricatorPasteViewController.php', 'PhabricatorPathSetupCheck' => 'applications/config/check/PhabricatorPathSetupCheck.php', 'PhabricatorPeopleAnyOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleAnyOwnerDatasource.php', 'PhabricatorPeopleApplication' => 'applications/people/application/PhabricatorPeopleApplication.php', 'PhabricatorPeopleApproveController' => 'applications/people/controller/PhabricatorPeopleApproveController.php', 'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php', 'PhabricatorPeopleCreateController' => 'applications/people/controller/PhabricatorPeopleCreateController.php', 'PhabricatorPeopleDatasource' => 'applications/people/typeahead/PhabricatorPeopleDatasource.php', 'PhabricatorPeopleDeleteController' => 'applications/people/controller/PhabricatorPeopleDeleteController.php', 'PhabricatorPeopleDetailsProfilePanel' => 'applications/people/profilepanel/PhabricatorPeopleDetailsProfilePanel.php', 'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php', 'PhabricatorPeopleEmpowerController' => 'applications/people/controller/PhabricatorPeopleEmpowerController.php', 'PhabricatorPeopleExternalPHIDType' => 'applications/people/phid/PhabricatorPeopleExternalPHIDType.php', 'PhabricatorPeopleIconSet' => 'applications/people/icon/PhabricatorPeopleIconSet.php', 'PhabricatorPeopleInviteController' => 'applications/people/controller/PhabricatorPeopleInviteController.php', 'PhabricatorPeopleInviteListController' => 'applications/people/controller/PhabricatorPeopleInviteListController.php', 'PhabricatorPeopleInviteSendController' => 'applications/people/controller/PhabricatorPeopleInviteSendController.php', 'PhabricatorPeopleLdapController' => 'applications/people/controller/PhabricatorPeopleLdapController.php', 'PhabricatorPeopleListController' => 'applications/people/controller/PhabricatorPeopleListController.php', 'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php', 'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php', 'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php', 'PhabricatorPeopleMainMenuBarExtension' => 'applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php', 'PhabricatorPeopleManageProfilePanel' => 'applications/people/profilepanel/PhabricatorPeopleManageProfilePanel.php', 'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php', 'PhabricatorPeopleNoOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleNoOwnerDatasource.php', 'PhabricatorPeopleOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleOwnerDatasource.php', 'PhabricatorPeopleProfileController' => 'applications/people/controller/PhabricatorPeopleProfileController.php', 'PhabricatorPeopleProfileEditController' => 'applications/people/controller/PhabricatorPeopleProfileEditController.php', 'PhabricatorPeopleProfileManageController' => 'applications/people/controller/PhabricatorPeopleProfileManageController.php', 'PhabricatorPeopleProfilePanelEngine' => 'applications/people/engine/PhabricatorPeopleProfilePanelEngine.php', 'PhabricatorPeopleProfilePictureController' => 'applications/people/controller/PhabricatorPeopleProfilePictureController.php', 'PhabricatorPeopleProfileViewController' => 'applications/people/controller/PhabricatorPeopleProfileViewController.php', 'PhabricatorPeopleQuery' => 'applications/people/query/PhabricatorPeopleQuery.php', 'PhabricatorPeopleRenameController' => 'applications/people/controller/PhabricatorPeopleRenameController.php', 'PhabricatorPeopleSearchEngine' => 'applications/people/query/PhabricatorPeopleSearchEngine.php', 'PhabricatorPeopleTestDataGenerator' => 'applications/people/lipsum/PhabricatorPeopleTestDataGenerator.php', 'PhabricatorPeopleTransactionQuery' => 'applications/people/query/PhabricatorPeopleTransactionQuery.php', 'PhabricatorPeopleUserFunctionDatasource' => 'applications/people/typeahead/PhabricatorPeopleUserFunctionDatasource.php', 'PhabricatorPeopleUserPHIDType' => 'applications/people/phid/PhabricatorPeopleUserPHIDType.php', 'PhabricatorPeopleWelcomeController' => 'applications/people/controller/PhabricatorPeopleWelcomeController.php', 'PhabricatorPersonaAuthProvider' => 'applications/auth/provider/PhabricatorPersonaAuthProvider.php', 'PhabricatorPhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorPhabricatorAuthProvider.php', 'PhabricatorPhameApplication' => 'applications/phame/application/PhabricatorPhameApplication.php', 'PhabricatorPhameBlogPHIDType' => 'applications/phame/phid/PhabricatorPhameBlogPHIDType.php', 'PhabricatorPhamePostPHIDType' => 'applications/phame/phid/PhabricatorPhamePostPHIDType.php', 'PhabricatorPhluxApplication' => 'applications/phlux/application/PhabricatorPhluxApplication.php', 'PhabricatorPholioApplication' => 'applications/pholio/application/PhabricatorPholioApplication.php', 'PhabricatorPholioConfigOptions' => 'applications/pholio/config/PhabricatorPholioConfigOptions.php', 'PhabricatorPholioMockTestDataGenerator' => 'applications/pholio/lipsum/PhabricatorPholioMockTestDataGenerator.php', 'PhabricatorPhortuneApplication' => 'applications/phortune/application/PhabricatorPhortuneApplication.php', 'PhabricatorPhortuneContentSource' => 'applications/phortune/contentsource/PhabricatorPhortuneContentSource.php', 'PhabricatorPhortuneManagementInvoiceWorkflow' => 'applications/phortune/management/PhabricatorPhortuneManagementInvoiceWorkflow.php', 'PhabricatorPhortuneManagementWorkflow' => 'applications/phortune/management/PhabricatorPhortuneManagementWorkflow.php', 'PhabricatorPhragmentApplication' => 'applications/phragment/application/PhabricatorPhragmentApplication.php', 'PhabricatorPhrequentApplication' => 'applications/phrequent/application/PhabricatorPhrequentApplication.php', 'PhabricatorPhrictionApplication' => 'applications/phriction/application/PhabricatorPhrictionApplication.php', 'PhabricatorPhrictionConfigOptions' => 'applications/phriction/config/PhabricatorPhrictionConfigOptions.php', 'PhabricatorPhurlApplication' => 'applications/phurl/application/PhabricatorPhurlApplication.php', 'PhabricatorPhurlConfigOptions' => 'applications/config/option/PhabricatorPhurlConfigOptions.php', 'PhabricatorPhurlController' => 'applications/phurl/controller/PhabricatorPhurlController.php', 'PhabricatorPhurlDAO' => 'applications/phurl/storage/PhabricatorPhurlDAO.php', 'PhabricatorPhurlLinkRemarkupRule' => 'applications/phurl/remarkup/PhabricatorPhurlLinkRemarkupRule.php', 'PhabricatorPhurlRemarkupRule' => 'applications/phurl/remarkup/PhabricatorPhurlRemarkupRule.php', 'PhabricatorPhurlSchemaSpec' => 'applications/phurl/storage/PhabricatorPhurlSchemaSpec.php', 'PhabricatorPhurlShortURLController' => 'applications/phurl/controller/PhabricatorPhurlShortURLController.php', 'PhabricatorPhurlShortURLDefaultController' => 'applications/phurl/controller/PhabricatorPhurlShortURLDefaultController.php', 'PhabricatorPhurlURL' => 'applications/phurl/storage/PhabricatorPhurlURL.php', 'PhabricatorPhurlURLAccessController' => 'applications/phurl/controller/PhabricatorPhurlURLAccessController.php', 'PhabricatorPhurlURLCommentController' => 'applications/phurl/controller/PhabricatorPhurlURLCommentController.php', 'PhabricatorPhurlURLCreateCapability' => 'applications/phurl/capability/PhabricatorPhurlURLCreateCapability.php', 'PhabricatorPhurlURLEditConduitAPIMethod' => 'applications/phurl/conduit/PhabricatorPhurlURLEditConduitAPIMethod.php', 'PhabricatorPhurlURLEditController' => 'applications/phurl/controller/PhabricatorPhurlURLEditController.php', 'PhabricatorPhurlURLEditEngine' => 'applications/phurl/editor/PhabricatorPhurlURLEditEngine.php', 'PhabricatorPhurlURLEditor' => 'applications/phurl/editor/PhabricatorPhurlURLEditor.php', 'PhabricatorPhurlURLListController' => 'applications/phurl/controller/PhabricatorPhurlURLListController.php', 'PhabricatorPhurlURLMailReceiver' => 'applications/phurl/mail/PhabricatorPhurlURLMailReceiver.php', 'PhabricatorPhurlURLNameNgrams' => 'applications/phurl/storage/PhabricatorPhurlURLNameNgrams.php', 'PhabricatorPhurlURLPHIDType' => 'applications/phurl/phid/PhabricatorPhurlURLPHIDType.php', 'PhabricatorPhurlURLQuery' => 'applications/phurl/query/PhabricatorPhurlURLQuery.php', 'PhabricatorPhurlURLReplyHandler' => 'applications/phurl/mail/PhabricatorPhurlURLReplyHandler.php', 'PhabricatorPhurlURLSearchConduitAPIMethod' => 'applications/phurl/conduit/PhabricatorPhurlURLSearchConduitAPIMethod.php', 'PhabricatorPhurlURLSearchEngine' => 'applications/phurl/query/PhabricatorPhurlURLSearchEngine.php', 'PhabricatorPhurlURLTransaction' => 'applications/phurl/storage/PhabricatorPhurlURLTransaction.php', 'PhabricatorPhurlURLTransactionComment' => 'applications/phurl/storage/PhabricatorPhurlURLTransactionComment.php', 'PhabricatorPhurlURLTransactionQuery' => 'applications/phurl/query/PhabricatorPhurlURLTransactionQuery.php', 'PhabricatorPhurlURLViewController' => 'applications/phurl/controller/PhabricatorPhurlURLViewController.php', 'PhabricatorPinnedApplicationsSetting' => 'applications/settings/setting/PhabricatorPinnedApplicationsSetting.php', 'PhabricatorPirateEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorPirateEnglishTranslation.php', 'PhabricatorPlatformSite' => 'aphront/site/PhabricatorPlatformSite.php', 'PhabricatorPointsEditField' => 'applications/transactions/editfield/PhabricatorPointsEditField.php', 'PhabricatorPolicies' => 'applications/policy/constants/PhabricatorPolicies.php', 'PhabricatorPolicy' => 'applications/policy/storage/PhabricatorPolicy.php', 'PhabricatorPolicyApplication' => 'applications/policy/application/PhabricatorPolicyApplication.php', 'PhabricatorPolicyAwareQuery' => 'infrastructure/query/policy/PhabricatorPolicyAwareQuery.php', 'PhabricatorPolicyAwareTestQuery' => 'applications/policy/__tests__/PhabricatorPolicyAwareTestQuery.php', 'PhabricatorPolicyCanEditCapability' => 'applications/policy/capability/PhabricatorPolicyCanEditCapability.php', 'PhabricatorPolicyCanJoinCapability' => 'applications/policy/capability/PhabricatorPolicyCanJoinCapability.php', 'PhabricatorPolicyCanViewCapability' => 'applications/policy/capability/PhabricatorPolicyCanViewCapability.php', 'PhabricatorPolicyCapability' => 'applications/policy/capability/PhabricatorPolicyCapability.php', 'PhabricatorPolicyCapabilityTestCase' => 'applications/policy/capability/__tests__/PhabricatorPolicyCapabilityTestCase.php', 'PhabricatorPolicyConfigOptions' => 'applications/policy/config/PhabricatorPolicyConfigOptions.php', 'PhabricatorPolicyConstants' => 'applications/policy/constants/PhabricatorPolicyConstants.php', 'PhabricatorPolicyController' => 'applications/policy/controller/PhabricatorPolicyController.php', 'PhabricatorPolicyDAO' => 'applications/policy/storage/PhabricatorPolicyDAO.php', 'PhabricatorPolicyDataTestCase' => 'applications/policy/__tests__/PhabricatorPolicyDataTestCase.php', 'PhabricatorPolicyEditController' => 'applications/policy/controller/PhabricatorPolicyEditController.php', 'PhabricatorPolicyEditEngineExtension' => 'applications/policy/editor/PhabricatorPolicyEditEngineExtension.php', 'PhabricatorPolicyEditField' => 'applications/transactions/editfield/PhabricatorPolicyEditField.php', 'PhabricatorPolicyException' => 'applications/policy/exception/PhabricatorPolicyException.php', 'PhabricatorPolicyExplainController' => 'applications/policy/controller/PhabricatorPolicyExplainController.php', 'PhabricatorPolicyFavoritesSetting' => 'applications/settings/setting/PhabricatorPolicyFavoritesSetting.php', 'PhabricatorPolicyFilter' => 'applications/policy/filter/PhabricatorPolicyFilter.php', 'PhabricatorPolicyInterface' => 'applications/policy/interface/PhabricatorPolicyInterface.php', 'PhabricatorPolicyManagementShowWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementShowWorkflow.php', 'PhabricatorPolicyManagementUnlockWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementUnlockWorkflow.php', 'PhabricatorPolicyManagementWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementWorkflow.php', 'PhabricatorPolicyPHIDTypePolicy' => 'applications/policy/phid/PhabricatorPolicyPHIDTypePolicy.php', 'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php', 'PhabricatorPolicyRequestExceptionHandler' => 'aphront/handler/PhabricatorPolicyRequestExceptionHandler.php', 'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php', 'PhabricatorPolicySearchEngineExtension' => 'applications/policy/engineextension/PhabricatorPolicySearchEngineExtension.php', 'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php', 'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php', 'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php', 'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php', 'PhabricatorProfileMenuCollapsedSetting' => 'applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php', 'PhabricatorProfilePanel' => 'applications/search/profilepanel/PhabricatorProfilePanel.php', 'PhabricatorProfilePanelConfiguration' => 'applications/search/storage/PhabricatorProfilePanelConfiguration.php', 'PhabricatorProfilePanelConfigurationQuery' => 'applications/search/query/PhabricatorProfilePanelConfigurationQuery.php', 'PhabricatorProfilePanelConfigurationTransaction' => 'applications/search/storage/PhabricatorProfilePanelConfigurationTransaction.php', 'PhabricatorProfilePanelConfigurationTransactionQuery' => 'applications/search/query/PhabricatorProfilePanelConfigurationTransactionQuery.php', 'PhabricatorProfilePanelEditEngine' => 'applications/search/editor/PhabricatorProfilePanelEditEngine.php', 'PhabricatorProfilePanelEditor' => 'applications/search/editor/PhabricatorProfilePanelEditor.php', 'PhabricatorProfilePanelEngine' => 'applications/search/engine/PhabricatorProfilePanelEngine.php', 'PhabricatorProfilePanelIconSet' => 'applications/search/profilepanel/PhabricatorProfilePanelIconSet.php', 'PhabricatorProfilePanelPHIDType' => 'applications/search/phidtype/PhabricatorProfilePanelPHIDType.php', 'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php', 'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php', 'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php', 'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php', 'PhabricatorProjectBoardBackgroundController' => 'applications/project/controller/PhabricatorProjectBoardBackgroundController.php', 'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php', 'PhabricatorProjectBoardDisableController' => 'applications/project/controller/PhabricatorProjectBoardDisableController.php', 'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php', 'PhabricatorProjectBoardManageController' => 'applications/project/controller/PhabricatorProjectBoardManageController.php', 'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php', 'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php', 'PhabricatorProjectCardView' => 'applications/project/view/PhabricatorProjectCardView.php', 'PhabricatorProjectColorsConfigOptionType' => 'applications/project/config/PhabricatorProjectColorsConfigOptionType.php', 'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php', 'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php', 'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php', 'PhabricatorProjectColumnHideController' => 'applications/project/controller/PhabricatorProjectColumnHideController.php', 'PhabricatorProjectColumnPHIDType' => 'applications/project/phid/PhabricatorProjectColumnPHIDType.php', 'PhabricatorProjectColumnPosition' => 'applications/project/storage/PhabricatorProjectColumnPosition.php', 'PhabricatorProjectColumnPositionQuery' => 'applications/project/query/PhabricatorProjectColumnPositionQuery.php', 'PhabricatorProjectColumnQuery' => 'applications/project/query/PhabricatorProjectColumnQuery.php', 'PhabricatorProjectColumnTransaction' => 'applications/project/storage/PhabricatorProjectColumnTransaction.php', 'PhabricatorProjectColumnTransactionEditor' => 'applications/project/editor/PhabricatorProjectColumnTransactionEditor.php', 'PhabricatorProjectColumnTransactionQuery' => 'applications/project/query/PhabricatorProjectColumnTransactionQuery.php', 'PhabricatorProjectConfigOptions' => 'applications/project/config/PhabricatorProjectConfigOptions.php', 'PhabricatorProjectConfiguredCustomField' => 'applications/project/customfield/PhabricatorProjectConfiguredCustomField.php', 'PhabricatorProjectController' => 'applications/project/controller/PhabricatorProjectController.php', 'PhabricatorProjectCoreTestCase' => 'applications/project/__tests__/PhabricatorProjectCoreTestCase.php', 'PhabricatorProjectCoverController' => 'applications/project/controller/PhabricatorProjectCoverController.php', 'PhabricatorProjectCustomField' => 'applications/project/customfield/PhabricatorProjectCustomField.php', 'PhabricatorProjectCustomFieldNumericIndex' => 'applications/project/storage/PhabricatorProjectCustomFieldNumericIndex.php', 'PhabricatorProjectCustomFieldStorage' => 'applications/project/storage/PhabricatorProjectCustomFieldStorage.php', 'PhabricatorProjectCustomFieldStringIndex' => 'applications/project/storage/PhabricatorProjectCustomFieldStringIndex.php', 'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php', 'PhabricatorProjectDatasource' => 'applications/project/typeahead/PhabricatorProjectDatasource.php', 'PhabricatorProjectDefaultController' => 'applications/project/controller/PhabricatorProjectDefaultController.php', 'PhabricatorProjectDescriptionField' => 'applications/project/customfield/PhabricatorProjectDescriptionField.php', 'PhabricatorProjectDetailsProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php', 'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php', 'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php', 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', 'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php', 'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php', 'PhabricatorProjectHeraldAdapter' => 'applications/project/herald/PhabricatorProjectHeraldAdapter.php', 'PhabricatorProjectHeraldFieldGroup' => 'applications/project/herald/PhabricatorProjectHeraldFieldGroup.php', 'PhabricatorProjectHovercardEngineExtension' => 'applications/project/engineextension/PhabricatorProjectHovercardEngineExtension.php', 'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php', 'PhabricatorProjectIconsConfigOptionType' => 'applications/project/config/PhabricatorProjectIconsConfigOptionType.php', 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', 'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php', 'PhabricatorProjectLockController' => 'applications/project/controller/PhabricatorProjectLockController.php', 'PhabricatorProjectLogicalAncestorDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalAncestorDatasource.php', 'PhabricatorProjectLogicalDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalDatasource.php', 'PhabricatorProjectLogicalOrNotDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php', 'PhabricatorProjectLogicalUserDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalUserDatasource.php', 'PhabricatorProjectLogicalViewerDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php', 'PhabricatorProjectManageController' => 'applications/project/controller/PhabricatorProjectManageController.php', 'PhabricatorProjectManageProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectManageProfilePanel.php', 'PhabricatorProjectMaterializedMemberEdgeType' => 'applications/project/edge/PhabricatorProjectMaterializedMemberEdgeType.php', 'PhabricatorProjectMemberListView' => 'applications/project/view/PhabricatorProjectMemberListView.php', 'PhabricatorProjectMemberOfProjectEdgeType' => 'applications/project/edge/PhabricatorProjectMemberOfProjectEdgeType.php', 'PhabricatorProjectMembersAddController' => 'applications/project/controller/PhabricatorProjectMembersAddController.php', 'PhabricatorProjectMembersDatasource' => 'applications/project/typeahead/PhabricatorProjectMembersDatasource.php', 'PhabricatorProjectMembersPolicyRule' => 'applications/project/policyrule/PhabricatorProjectMembersPolicyRule.php', 'PhabricatorProjectMembersProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php', 'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php', 'PhabricatorProjectMembersViewController' => 'applications/project/controller/PhabricatorProjectMembersViewController.php', 'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php', 'PhabricatorProjectNameContextFreeGrammar' => 'applications/project/lipsum/PhabricatorProjectNameContextFreeGrammar.php', 'PhabricatorProjectNoProjectsDatasource' => 'applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php', 'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php', 'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php', 'PhabricatorProjectOrUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserFunctionDatasource.php', 'PhabricatorProjectPHIDResolver' => 'applications/phid/resolver/PhabricatorProjectPHIDResolver.php', 'PhabricatorProjectPanelController' => 'applications/project/controller/PhabricatorProjectPanelController.php', 'PhabricatorProjectPointsProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectPointsProfilePanel.php', 'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php', 'PhabricatorProjectProfilePanelEngine' => 'applications/project/engine/PhabricatorProjectProfilePanelEngine.php', 'PhabricatorProjectProjectHasMemberEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasMemberEdgeType.php', 'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php', 'PhabricatorProjectProjectPHIDType' => 'applications/project/phid/PhabricatorProjectProjectPHIDType.php', 'PhabricatorProjectQuery' => 'applications/project/query/PhabricatorProjectQuery.php', 'PhabricatorProjectRemoveHeraldAction' => 'applications/project/herald/PhabricatorProjectRemoveHeraldAction.php', 'PhabricatorProjectSchemaSpec' => 'applications/project/storage/PhabricatorProjectSchemaSpec.php', 'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php', 'PhabricatorProjectSearchField' => 'applications/project/searchfield/PhabricatorProjectSearchField.php', 'PhabricatorProjectSilenceController' => 'applications/project/controller/PhabricatorProjectSilenceController.php', 'PhabricatorProjectSilencedEdgeType' => 'applications/project/edge/PhabricatorProjectSilencedEdgeType.php', 'PhabricatorProjectSlug' => 'applications/project/storage/PhabricatorProjectSlug.php', 'PhabricatorProjectStandardCustomField' => 'applications/project/customfield/PhabricatorProjectStandardCustomField.php', 'PhabricatorProjectStatus' => 'applications/project/constants/PhabricatorProjectStatus.php', 'PhabricatorProjectSubprojectWarningController' => 'applications/project/controller/PhabricatorProjectSubprojectWarningController.php', 'PhabricatorProjectSubprojectsController' => 'applications/project/controller/PhabricatorProjectSubprojectsController.php', 'PhabricatorProjectSubprojectsProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectSubprojectsProfilePanel.php', 'PhabricatorProjectTestDataGenerator' => 'applications/project/lipsum/PhabricatorProjectTestDataGenerator.php', 'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php', 'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php', 'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php', 'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php', 'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php', 'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php', 'PhabricatorProjectUserListView' => 'applications/project/view/PhabricatorProjectUserListView.php', 'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php', 'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php', 'PhabricatorProjectWatcherListView' => 'applications/project/view/PhabricatorProjectWatcherListView.php', 'PhabricatorProjectWorkboardBackgroundColor' => 'applications/project/constants/PhabricatorProjectWorkboardBackgroundColor.php', 'PhabricatorProjectWorkboardProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php', 'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php', 'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php', 'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php', 'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php', 'PhabricatorProjectsMembersSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsMembersSearchEngineAttachment.php', 'PhabricatorProjectsMembershipIndexEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php', 'PhabricatorProjectsPolicyRule' => 'applications/project/policyrule/PhabricatorProjectsPolicyRule.php', 'PhabricatorProjectsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsSearchEngineAttachment.php', 'PhabricatorProjectsSearchEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsSearchEngineExtension.php', 'PhabricatorProjectsWatchersSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsWatchersSearchEngineAttachment.php', 'PhabricatorPronounSetting' => 'applications/settings/setting/PhabricatorPronounSetting.php', 'PhabricatorProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorProtocolAdapter.php', 'PhabricatorPygmentSetupCheck' => 'applications/config/check/PhabricatorPygmentSetupCheck.php', 'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php', 'PhabricatorQueryConstraint' => 'infrastructure/query/constraint/PhabricatorQueryConstraint.php', 'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php', 'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php', 'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php', 'PhabricatorQuickActions' => 'applications/settings/quickmenu/PhabricatorQuickActions.php', 'PhabricatorRateLimitRequestExceptionHandler' => 'aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php', 'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php', 'PhabricatorRecipientHasBadgeEdgeType' => 'applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php', 'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php', 'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php', 'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php', 'PhabricatorReleephApplication' => 'applications/releeph/application/PhabricatorReleephApplication.php', 'PhabricatorReleephApplicationConfigOptions' => 'applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php', 'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php', 'PhabricatorRemarkupCowsayBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupCowsayBlockInterpreter.php', 'PhabricatorRemarkupCustomBlockRule' => 'infrastructure/markup/rule/PhabricatorRemarkupCustomBlockRule.php', 'PhabricatorRemarkupCustomInlineRule' => 'infrastructure/markup/rule/PhabricatorRemarkupCustomInlineRule.php', 'PhabricatorRemarkupEditField' => 'applications/transactions/editfield/PhabricatorRemarkupEditField.php', 'PhabricatorRemarkupFigletBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupFigletBlockInterpreter.php', 'PhabricatorRemarkupUIExample' => 'applications/uiexample/examples/PhabricatorRemarkupUIExample.php', 'PhabricatorRepositoriesSetupCheck' => 'applications/config/check/PhabricatorRepositoriesSetupCheck.php', 'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php', 'PhabricatorRepositoryAuditRequest' => 'applications/repository/storage/PhabricatorRepositoryAuditRequest.php', 'PhabricatorRepositoryBranch' => 'applications/repository/storage/PhabricatorRepositoryBranch.php', 'PhabricatorRepositoryCommit' => 'applications/repository/storage/PhabricatorRepositoryCommit.php', 'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php', 'PhabricatorRepositoryCommitData' => 'applications/repository/storage/PhabricatorRepositoryCommitData.php', 'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php', 'PhabricatorRepositoryCommitHint' => 'applications/repository/storage/PhabricatorRepositoryCommitHint.php', 'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php', 'PhabricatorRepositoryCommitOwnersWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php', 'PhabricatorRepositoryCommitPHIDType' => 'applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php', 'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php', 'PhabricatorRepositoryCommitRef' => 'applications/repository/engine/PhabricatorRepositoryCommitRef.php', 'PhabricatorRepositoryCommitTestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryCommitTestCase.php', 'PhabricatorRepositoryConfigOptions' => 'applications/repository/config/PhabricatorRepositoryConfigOptions.php', 'PhabricatorRepositoryDAO' => 'applications/repository/storage/PhabricatorRepositoryDAO.php', 'PhabricatorRepositoryDiscoveryEngine' => 'applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php', 'PhabricatorRepositoryEditor' => 'applications/repository/editor/PhabricatorRepositoryEditor.php', 'PhabricatorRepositoryEngine' => 'applications/repository/engine/PhabricatorRepositoryEngine.php', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryGitCommitChangeParserWorker.php', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryGitCommitMessageParserWorker.php', 'PhabricatorRepositoryGitLFSRef' => 'applications/repository/storage/PhabricatorRepositoryGitLFSRef.php', 'PhabricatorRepositoryGitLFSRefQuery' => 'applications/repository/query/PhabricatorRepositoryGitLFSRefQuery.php', 'PhabricatorRepositoryGraphCache' => 'applications/repository/graphcache/PhabricatorRepositoryGraphCache.php', 'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php', 'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php', 'PhabricatorRepositoryManagementClusterizeWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php', 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php', 'PhabricatorRepositoryManagementHintWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementHintWorkflow.php', 'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php', 'PhabricatorRepositoryManagementListPathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListPathsWorkflow.php', 'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php', 'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementLookupUsersWorkflow.php', 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php', 'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php', 'PhabricatorRepositoryManagementMirrorWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMirrorWorkflow.php', 'PhabricatorRepositoryManagementMovePathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMovePathsWorkflow.php', 'PhabricatorRepositoryManagementParentsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php', 'PhabricatorRepositoryManagementPullWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php', 'PhabricatorRepositoryManagementRefsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRefsWorkflow.php', 'PhabricatorRepositoryManagementReparseWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php', 'PhabricatorRepositoryManagementThawWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementThawWorkflow.php', 'PhabricatorRepositoryManagementUpdateWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementUpdateWorkflow.php', 'PhabricatorRepositoryManagementWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementWorkflow.php', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryMercurialCommitChangeParserWorker.php', 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryMercurialCommitMessageParserWorker.php', 'PhabricatorRepositoryMirror' => 'applications/repository/storage/PhabricatorRepositoryMirror.php', 'PhabricatorRepositoryMirrorEngine' => 'applications/repository/engine/PhabricatorRepositoryMirrorEngine.php', 'PhabricatorRepositoryOldRef' => 'applications/repository/storage/PhabricatorRepositoryOldRef.php', 'PhabricatorRepositoryParsedChange' => 'applications/repository/data/PhabricatorRepositoryParsedChange.php', 'PhabricatorRepositoryPullEngine' => 'applications/repository/engine/PhabricatorRepositoryPullEngine.php', 'PhabricatorRepositoryPullEvent' => 'applications/repository/storage/PhabricatorRepositoryPullEvent.php', 'PhabricatorRepositoryPullEventPHIDType' => 'applications/repository/phid/PhabricatorRepositoryPullEventPHIDType.php', 'PhabricatorRepositoryPullEventQuery' => 'applications/repository/query/PhabricatorRepositoryPullEventQuery.php', 'PhabricatorRepositoryPullLocalDaemon' => 'applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php', 'PhabricatorRepositoryPushEvent' => 'applications/repository/storage/PhabricatorRepositoryPushEvent.php', 'PhabricatorRepositoryPushEventPHIDType' => 'applications/repository/phid/PhabricatorRepositoryPushEventPHIDType.php', 'PhabricatorRepositoryPushEventQuery' => 'applications/repository/query/PhabricatorRepositoryPushEventQuery.php', 'PhabricatorRepositoryPushLog' => 'applications/repository/storage/PhabricatorRepositoryPushLog.php', 'PhabricatorRepositoryPushLogPHIDType' => 'applications/repository/phid/PhabricatorRepositoryPushLogPHIDType.php', 'PhabricatorRepositoryPushLogQuery' => 'applications/repository/query/PhabricatorRepositoryPushLogQuery.php', 'PhabricatorRepositoryPushLogSearchEngine' => 'applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php', 'PhabricatorRepositoryPushMailWorker' => 'applications/repository/worker/PhabricatorRepositoryPushMailWorker.php', 'PhabricatorRepositoryPushReplyHandler' => 'applications/repository/mail/PhabricatorRepositoryPushReplyHandler.php', 'PhabricatorRepositoryQuery' => 'applications/repository/query/PhabricatorRepositoryQuery.php', 'PhabricatorRepositoryRefCursor' => 'applications/repository/storage/PhabricatorRepositoryRefCursor.php', 'PhabricatorRepositoryRefCursorPHIDType' => 'applications/repository/phid/PhabricatorRepositoryRefCursorPHIDType.php', 'PhabricatorRepositoryRefCursorQuery' => 'applications/repository/query/PhabricatorRepositoryRefCursorQuery.php', 'PhabricatorRepositoryRefEngine' => 'applications/repository/engine/PhabricatorRepositoryRefEngine.php', 'PhabricatorRepositoryRepositoryPHIDType' => 'applications/repository/phid/PhabricatorRepositoryRepositoryPHIDType.php', 'PhabricatorRepositorySchemaSpec' => 'applications/repository/storage/PhabricatorRepositorySchemaSpec.php', 'PhabricatorRepositorySearchEngine' => 'applications/repository/query/PhabricatorRepositorySearchEngine.php', 'PhabricatorRepositoryStatusMessage' => 'applications/repository/storage/PhabricatorRepositoryStatusMessage.php', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositorySvnCommitChangeParserWorker.php', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositorySvnCommitMessageParserWorker.php', 'PhabricatorRepositorySymbol' => 'applications/repository/storage/PhabricatorRepositorySymbol.php', 'PhabricatorRepositoryTestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php', 'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php', 'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php', 'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php', 'PhabricatorRepositoryURI' => 'applications/repository/storage/PhabricatorRepositoryURI.php', 'PhabricatorRepositoryURIIndex' => 'applications/repository/storage/PhabricatorRepositoryURIIndex.php', 'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php', 'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php', 'PhabricatorRepositoryURIPHIDType' => 'applications/repository/phid/PhabricatorRepositoryURIPHIDType.php', 'PhabricatorRepositoryURIQuery' => 'applications/repository/query/PhabricatorRepositoryURIQuery.php', 'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php', 'PhabricatorRepositoryURITransaction' => 'applications/repository/storage/PhabricatorRepositoryURITransaction.php', 'PhabricatorRepositoryURITransactionQuery' => 'applications/repository/query/PhabricatorRepositoryURITransactionQuery.php', 'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php', 'PhabricatorRepositoryVersion' => 'applications/repository/constants/PhabricatorRepositoryVersion.php', 'PhabricatorRepositoryWorkingCopyVersion' => 'applications/repository/storage/PhabricatorRepositoryWorkingCopyVersion.php', 'PhabricatorRequestExceptionHandler' => 'aphront/handler/PhabricatorRequestExceptionHandler.php', 'PhabricatorResourceSite' => 'aphront/site/PhabricatorResourceSite.php', 'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php', 'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php', 'PhabricatorSMS' => 'infrastructure/sms/storage/PhabricatorSMS.php', 'PhabricatorSMSConfigOptions' => 'applications/config/option/PhabricatorSMSConfigOptions.php', 'PhabricatorSMSDAO' => 'infrastructure/sms/storage/PhabricatorSMSDAO.php', 'PhabricatorSMSDemultiplexWorker' => 'infrastructure/sms/worker/PhabricatorSMSDemultiplexWorker.php', 'PhabricatorSMSImplementationAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationAdapter.php', 'PhabricatorSMSImplementationTestBlackholeAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationTestBlackholeAdapter.php', 'PhabricatorSMSImplementationTwilioAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationTwilioAdapter.php', 'PhabricatorSMSManagementListOutboundWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementListOutboundWorkflow.php', 'PhabricatorSMSManagementSendTestWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementSendTestWorkflow.php', 'PhabricatorSMSManagementShowOutboundWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementShowOutboundWorkflow.php', 'PhabricatorSMSManagementWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementWorkflow.php', 'PhabricatorSMSSendWorker' => 'infrastructure/sms/worker/PhabricatorSMSSendWorker.php', 'PhabricatorSMSWorker' => 'infrastructure/sms/worker/PhabricatorSMSWorker.php', 'PhabricatorSQLPatchList' => 'infrastructure/storage/patch/PhabricatorSQLPatchList.php', 'PhabricatorSSHKeyGenerator' => 'infrastructure/util/PhabricatorSSHKeyGenerator.php', 'PhabricatorSSHKeysSettingsPanel' => 'applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php', 'PhabricatorSSHLog' => 'infrastructure/log/PhabricatorSSHLog.php', 'PhabricatorSSHPassthruCommand' => 'infrastructure/ssh/PhabricatorSSHPassthruCommand.php', 'PhabricatorSSHPublicKeyInterface' => 'applications/auth/sshkey/PhabricatorSSHPublicKeyInterface.php', 'PhabricatorSSHWorkflow' => 'infrastructure/ssh/PhabricatorSSHWorkflow.php', 'PhabricatorSavedQuery' => 'applications/search/storage/PhabricatorSavedQuery.php', 'PhabricatorSavedQueryQuery' => 'applications/search/query/PhabricatorSavedQueryQuery.php', 'PhabricatorScheduleTaskTriggerAction' => 'infrastructure/daemon/workers/action/PhabricatorScheduleTaskTriggerAction.php', 'PhabricatorScopedEnv' => 'infrastructure/env/PhabricatorScopedEnv.php', 'PhabricatorSearchAbstractDocument' => 'applications/search/index/PhabricatorSearchAbstractDocument.php', 'PhabricatorSearchApplication' => 'applications/search/application/PhabricatorSearchApplication.php', 'PhabricatorSearchApplicationSearchEngine' => 'applications/search/query/PhabricatorSearchApplicationSearchEngine.php', 'PhabricatorSearchApplicationStorageEnginePanel' => 'applications/search/applicationpanel/PhabricatorSearchApplicationStorageEnginePanel.php', 'PhabricatorSearchBaseController' => 'applications/search/controller/PhabricatorSearchBaseController.php', 'PhabricatorSearchCheckboxesField' => 'applications/search/field/PhabricatorSearchCheckboxesField.php', 'PhabricatorSearchConfigOptions' => 'applications/search/config/PhabricatorSearchConfigOptions.php', 'PhabricatorSearchController' => 'applications/search/controller/PhabricatorSearchController.php', 'PhabricatorSearchCustomFieldProxyField' => 'applications/search/field/PhabricatorSearchCustomFieldProxyField.php', 'PhabricatorSearchDAO' => 'applications/search/storage/PhabricatorSearchDAO.php', 'PhabricatorSearchDatasource' => 'applications/search/typeahead/PhabricatorSearchDatasource.php', 'PhabricatorSearchDatasourceField' => 'applications/search/field/PhabricatorSearchDatasourceField.php', 'PhabricatorSearchDateControlField' => 'applications/search/field/PhabricatorSearchDateControlField.php', 'PhabricatorSearchDateField' => 'applications/search/field/PhabricatorSearchDateField.php', 'PhabricatorSearchDeleteController' => 'applications/search/controller/PhabricatorSearchDeleteController.php', 'PhabricatorSearchDocument' => 'applications/search/storage/document/PhabricatorSearchDocument.php', 'PhabricatorSearchDocumentField' => 'applications/search/storage/document/PhabricatorSearchDocumentField.php', 'PhabricatorSearchDocumentFieldType' => 'applications/search/constants/PhabricatorSearchDocumentFieldType.php', 'PhabricatorSearchDocumentQuery' => 'applications/search/query/PhabricatorSearchDocumentQuery.php', 'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/PhabricatorSearchDocumentRelationship.php', 'PhabricatorSearchDocumentTypeDatasource' => 'applications/search/typeahead/PhabricatorSearchDocumentTypeDatasource.php', 'PhabricatorSearchEditController' => 'applications/search/controller/PhabricatorSearchEditController.php', 'PhabricatorSearchEngineAPIMethod' => 'applications/search/engine/PhabricatorSearchEngineAPIMethod.php', 'PhabricatorSearchEngineAttachment' => 'applications/search/engineextension/PhabricatorSearchEngineAttachment.php', 'PhabricatorSearchEngineExtension' => 'applications/search/engineextension/PhabricatorSearchEngineExtension.php', 'PhabricatorSearchEngineExtensionModule' => 'applications/search/engineextension/PhabricatorSearchEngineExtensionModule.php', 'PhabricatorSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php', 'PhabricatorSearchField' => 'applications/search/field/PhabricatorSearchField.php', 'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php', 'PhabricatorSearchIndexVersion' => 'applications/search/storage/PhabricatorSearchIndexVersion.php', 'PhabricatorSearchIndexVersionDestructionEngineExtension' => 'applications/search/engineextension/PhabricatorSearchIndexVersionDestructionEngineExtension.php', 'PhabricatorSearchManagementIndexWorkflow' => 'applications/search/management/PhabricatorSearchManagementIndexWorkflow.php', 'PhabricatorSearchManagementInitWorkflow' => 'applications/search/management/PhabricatorSearchManagementInitWorkflow.php', 'PhabricatorSearchManagementWorkflow' => 'applications/search/management/PhabricatorSearchManagementWorkflow.php', 'PhabricatorSearchNgrams' => 'applications/search/ngrams/PhabricatorSearchNgrams.php', 'PhabricatorSearchNgramsDestructionEngineExtension' => 'applications/search/engineextension/PhabricatorSearchNgramsDestructionEngineExtension.php', 'PhabricatorSearchOrderController' => 'applications/search/controller/PhabricatorSearchOrderController.php', 'PhabricatorSearchOrderField' => 'applications/search/field/PhabricatorSearchOrderField.php', 'PhabricatorSearchRelationship' => 'applications/search/constants/PhabricatorSearchRelationship.php', 'PhabricatorSearchRelationshipController' => 'applications/search/controller/PhabricatorSearchRelationshipController.php', 'PhabricatorSearchRelationshipSourceController' => 'applications/search/controller/PhabricatorSearchRelationshipSourceController.php', 'PhabricatorSearchResultBucket' => 'applications/search/buckets/PhabricatorSearchResultBucket.php', 'PhabricatorSearchResultBucketGroup' => 'applications/search/buckets/PhabricatorSearchResultBucketGroup.php', 'PhabricatorSearchResultView' => 'applications/search/view/PhabricatorSearchResultView.php', 'PhabricatorSearchSchemaSpec' => 'applications/search/storage/PhabricatorSearchSchemaSpec.php', 'PhabricatorSearchScopeSetting' => 'applications/settings/setting/PhabricatorSearchScopeSetting.php', 'PhabricatorSearchSelectField' => 'applications/search/field/PhabricatorSearchSelectField.php', 'PhabricatorSearchStringListField' => 'applications/search/field/PhabricatorSearchStringListField.php', 'PhabricatorSearchSubscribersField' => 'applications/search/field/PhabricatorSearchSubscribersField.php', 'PhabricatorSearchTextField' => 'applications/search/field/PhabricatorSearchTextField.php', 'PhabricatorSearchThreeStateField' => 'applications/search/field/PhabricatorSearchThreeStateField.php', 'PhabricatorSearchTokenizerField' => 'applications/search/field/PhabricatorSearchTokenizerField.php', 'PhabricatorSearchWorker' => 'applications/search/worker/PhabricatorSearchWorker.php', 'PhabricatorSecurityConfigOptions' => 'applications/config/option/PhabricatorSecurityConfigOptions.php', 'PhabricatorSecuritySetupCheck' => 'applications/config/check/PhabricatorSecuritySetupCheck.php', 'PhabricatorSelectEditField' => 'applications/transactions/editfield/PhabricatorSelectEditField.php', 'PhabricatorSelectSetting' => 'applications/settings/setting/PhabricatorSelectSetting.php', 'PhabricatorSendGridConfigOptions' => 'applications/config/option/PhabricatorSendGridConfigOptions.php', 'PhabricatorSessionsSettingsPanel' => 'applications/settings/panel/PhabricatorSessionsSettingsPanel.php', 'PhabricatorSetting' => 'applications/settings/setting/PhabricatorSetting.php', 'PhabricatorSettingsAccountPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsAccountPanelGroup.php', 'PhabricatorSettingsAddEmailAction' => 'applications/settings/action/PhabricatorSettingsAddEmailAction.php', 'PhabricatorSettingsAdjustController' => 'applications/settings/controller/PhabricatorSettingsAdjustController.php', 'PhabricatorSettingsApplication' => 'applications/settings/application/PhabricatorSettingsApplication.php', 'PhabricatorSettingsApplicationsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsApplicationsPanelGroup.php', 'PhabricatorSettingsAuthenticationPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsAuthenticationPanelGroup.php', 'PhabricatorSettingsDeveloperPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsDeveloperPanelGroup.php', 'PhabricatorSettingsEditEngine' => 'applications/settings/editor/PhabricatorSettingsEditEngine.php', 'PhabricatorSettingsEmailPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsEmailPanelGroup.php', 'PhabricatorSettingsListController' => 'applications/settings/controller/PhabricatorSettingsListController.php', 'PhabricatorSettingsLogsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsLogsPanelGroup.php', 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php', 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 'PhabricatorSettingsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsPanelGroup.php', 'PhabricatorSettingsTimezoneController' => 'applications/settings/controller/PhabricatorSettingsTimezoneController.php', 'PhabricatorSetupCheck' => 'applications/config/check/PhabricatorSetupCheck.php', 'PhabricatorSetupCheckTestCase' => 'applications/config/check/__tests__/PhabricatorSetupCheckTestCase.php', 'PhabricatorSetupIssue' => 'applications/config/issue/PhabricatorSetupIssue.php', 'PhabricatorSetupIssueUIExample' => 'applications/uiexample/examples/PhabricatorSetupIssueUIExample.php', 'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php', 'PhabricatorShortSite' => 'aphront/site/PhabricatorShortSite.php', 'PhabricatorShowFiletreeSetting' => 'applications/settings/setting/PhabricatorShowFiletreeSetting.php', 'PhabricatorSimpleEditType' => 'applications/transactions/edittype/PhabricatorSimpleEditType.php', 'PhabricatorSite' => 'aphront/site/PhabricatorSite.php', 'PhabricatorSlackAuthProvider' => 'applications/auth/provider/PhabricatorSlackAuthProvider.php', 'PhabricatorSlowvoteApplication' => 'applications/slowvote/application/PhabricatorSlowvoteApplication.php', 'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/PhabricatorSlowvoteChoice.php', 'PhabricatorSlowvoteCloseController' => 'applications/slowvote/controller/PhabricatorSlowvoteCloseController.php', 'PhabricatorSlowvoteCommentController' => 'applications/slowvote/controller/PhabricatorSlowvoteCommentController.php', 'PhabricatorSlowvoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteController.php', 'PhabricatorSlowvoteDAO' => 'applications/slowvote/storage/PhabricatorSlowvoteDAO.php', 'PhabricatorSlowvoteDefaultViewCapability' => 'applications/slowvote/capability/PhabricatorSlowvoteDefaultViewCapability.php', 'PhabricatorSlowvoteEditController' => 'applications/slowvote/controller/PhabricatorSlowvoteEditController.php', 'PhabricatorSlowvoteEditor' => 'applications/slowvote/editor/PhabricatorSlowvoteEditor.php', 'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/PhabricatorSlowvoteListController.php', 'PhabricatorSlowvoteMailReceiver' => 'applications/slowvote/mail/PhabricatorSlowvoteMailReceiver.php', 'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/PhabricatorSlowvoteOption.php', 'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/PhabricatorSlowvotePoll.php', 'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/PhabricatorSlowvotePollController.php', 'PhabricatorSlowvotePollPHIDType' => 'applications/slowvote/phid/PhabricatorSlowvotePollPHIDType.php', 'PhabricatorSlowvoteQuery' => 'applications/slowvote/query/PhabricatorSlowvoteQuery.php', 'PhabricatorSlowvoteReplyHandler' => 'applications/slowvote/mail/PhabricatorSlowvoteReplyHandler.php', 'PhabricatorSlowvoteSchemaSpec' => 'applications/slowvote/storage/PhabricatorSlowvoteSchemaSpec.php', 'PhabricatorSlowvoteSearchEngine' => 'applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php', 'PhabricatorSlowvoteTransaction' => 'applications/slowvote/storage/PhabricatorSlowvoteTransaction.php', 'PhabricatorSlowvoteTransactionComment' => 'applications/slowvote/storage/PhabricatorSlowvoteTransactionComment.php', 'PhabricatorSlowvoteTransactionQuery' => 'applications/slowvote/query/PhabricatorSlowvoteTransactionQuery.php', 'PhabricatorSlowvoteVoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteVoteController.php', 'PhabricatorSlug' => 'infrastructure/util/PhabricatorSlug.php', 'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php', 'PhabricatorSortTableUIExample' => 'applications/uiexample/examples/PhabricatorSortTableUIExample.php', 'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php', 'PhabricatorSpaceEditField' => 'applications/transactions/editfield/PhabricatorSpaceEditField.php', 'PhabricatorSpacesApplication' => 'applications/spaces/application/PhabricatorSpacesApplication.php', 'PhabricatorSpacesArchiveController' => 'applications/spaces/controller/PhabricatorSpacesArchiveController.php', 'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php', 'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php', 'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php', 'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php', 'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php', 'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php', 'PhabricatorSpacesInterface' => 'applications/spaces/interface/PhabricatorSpacesInterface.php', 'PhabricatorSpacesListController' => 'applications/spaces/controller/PhabricatorSpacesListController.php', 'PhabricatorSpacesNamespace' => 'applications/spaces/storage/PhabricatorSpacesNamespace.php', 'PhabricatorSpacesNamespaceDatasource' => 'applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php', 'PhabricatorSpacesNamespaceEditor' => 'applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php', 'PhabricatorSpacesNamespacePHIDType' => 'applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php', 'PhabricatorSpacesNamespaceQuery' => 'applications/spaces/query/PhabricatorSpacesNamespaceQuery.php', 'PhabricatorSpacesNamespaceSearchEngine' => 'applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php', 'PhabricatorSpacesNamespaceTransaction' => 'applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php', 'PhabricatorSpacesNamespaceTransactionQuery' => 'applications/spaces/query/PhabricatorSpacesNamespaceTransactionQuery.php', 'PhabricatorSpacesNoAccessController' => 'applications/spaces/controller/PhabricatorSpacesNoAccessController.php', 'PhabricatorSpacesRemarkupRule' => 'applications/spaces/remarkup/PhabricatorSpacesRemarkupRule.php', 'PhabricatorSpacesSchemaSpec' => 'applications/spaces/storage/PhabricatorSpacesSchemaSpec.php', 'PhabricatorSpacesSearchEngineExtension' => 'applications/spaces/engineextension/PhabricatorSpacesSearchEngineExtension.php', 'PhabricatorSpacesSearchField' => 'applications/spaces/searchfield/PhabricatorSpacesSearchField.php', 'PhabricatorSpacesTestCase' => 'applications/spaces/__tests__/PhabricatorSpacesTestCase.php', 'PhabricatorSpacesViewController' => 'applications/spaces/controller/PhabricatorSpacesViewController.php', 'PhabricatorStandardCustomField' => 'infrastructure/customfield/standard/PhabricatorStandardCustomField.php', 'PhabricatorStandardCustomFieldBlueprints' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldBlueprints.php', 'PhabricatorStandardCustomFieldBool' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php', 'PhabricatorStandardCustomFieldCredential' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php', 'PhabricatorStandardCustomFieldDatasource' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldDatasource.php', 'PhabricatorStandardCustomFieldDate' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldDate.php', 'PhabricatorStandardCustomFieldHeader' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php', 'PhabricatorStandardCustomFieldInt' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php', 'PhabricatorStandardCustomFieldInterface' => 'infrastructure/customfield/interface/PhabricatorStandardCustomFieldInterface.php', 'PhabricatorStandardCustomFieldLink' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php', 'PhabricatorStandardCustomFieldPHIDs' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php', 'PhabricatorStandardCustomFieldRemarkup' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php', 'PhabricatorStandardCustomFieldSelect' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldSelect.php', 'PhabricatorStandardCustomFieldText' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php', 'PhabricatorStandardCustomFieldTokenizer' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php', 'PhabricatorStandardCustomFieldUsers' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php', 'PhabricatorStandardPageView' => 'view/page/PhabricatorStandardPageView.php', 'PhabricatorStandardSelectCustomFieldDatasource' => 'infrastructure/customfield/datasource/PhabricatorStandardSelectCustomFieldDatasource.php', 'PhabricatorStaticEditField' => 'applications/transactions/editfield/PhabricatorStaticEditField.php', 'PhabricatorStatusController' => 'applications/system/controller/PhabricatorStatusController.php', 'PhabricatorStatusUIExample' => 'applications/uiexample/examples/PhabricatorStatusUIExample.php', 'PhabricatorStorageFixtureScopeGuard' => 'infrastructure/testing/fixture/PhabricatorStorageFixtureScopeGuard.php', 'PhabricatorStorageManagementAPI' => 'infrastructure/storage/management/PhabricatorStorageManagementAPI.php', 'PhabricatorStorageManagementAdjustWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementAdjustWorkflow.php', 'PhabricatorStorageManagementDatabasesWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDatabasesWorkflow.php', 'PhabricatorStorageManagementDestroyWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php', 'PhabricatorStorageManagementDumpWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php', 'PhabricatorStorageManagementProbeWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementProbeWorkflow.php', 'PhabricatorStorageManagementQuickstartWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementQuickstartWorkflow.php', 'PhabricatorStorageManagementRenamespaceWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementRenamespaceWorkflow.php', 'PhabricatorStorageManagementShellWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementShellWorkflow.php', 'PhabricatorStorageManagementStatusWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementStatusWorkflow.php', 'PhabricatorStorageManagementUpgradeWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php', 'PhabricatorStorageManagementWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php', 'PhabricatorStoragePatch' => 'infrastructure/storage/management/PhabricatorStoragePatch.php', 'PhabricatorStorageSchemaSpec' => 'infrastructure/storage/schema/PhabricatorStorageSchemaSpec.php', 'PhabricatorStorageSetupCheck' => 'applications/config/check/PhabricatorStorageSetupCheck.php', 'PhabricatorStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php', 'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php', 'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php', 'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php', 'PhabricatorSubscribedToObjectEdgeType' => 'applications/transactions/edges/PhabricatorSubscribedToObjectEdgeType.php', 'PhabricatorSubscribersEditField' => 'applications/transactions/editfield/PhabricatorSubscribersEditField.php', 'PhabricatorSubscribersQuery' => 'applications/subscriptions/query/PhabricatorSubscribersQuery.php', 'PhabricatorSubscriptionTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorSubscriptionTriggerClock.php', 'PhabricatorSubscriptionsAddSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsAddSelfHeraldAction.php', 'PhabricatorSubscriptionsAddSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsAddSubscribersHeraldAction.php', 'PhabricatorSubscriptionsApplication' => 'applications/subscriptions/application/PhabricatorSubscriptionsApplication.php', 'PhabricatorSubscriptionsCurtainExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php', 'PhabricatorSubscriptionsEditController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php', 'PhabricatorSubscriptionsEditEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsEditEngineExtension.php', 'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php', 'PhabricatorSubscriptionsFulltextEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsFulltextEngineExtension.php', 'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php', 'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php', 'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSelfHeraldAction.php', 'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSubscribersHeraldAction.php', 'PhabricatorSubscriptionsSearchEngineAttachment' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php', 'PhabricatorSubscriptionsSearchEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineExtension.php', 'PhabricatorSubscriptionsSubscribeEmailCommand' => 'applications/subscriptions/command/PhabricatorSubscriptionsSubscribeEmailCommand.php', 'PhabricatorSubscriptionsSubscribersPolicyRule' => 'applications/subscriptions/policyrule/PhabricatorSubscriptionsSubscribersPolicyRule.php', 'PhabricatorSubscriptionsTransactionController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsTransactionController.php', 'PhabricatorSubscriptionsUIEventListener' => 'applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php', 'PhabricatorSubscriptionsUnsubscribeEmailCommand' => 'applications/subscriptions/command/PhabricatorSubscriptionsUnsubscribeEmailCommand.php', 'PhabricatorSupportApplication' => 'applications/support/application/PhabricatorSupportApplication.php', 'PhabricatorSyntaxHighlighter' => 'infrastructure/markup/PhabricatorSyntaxHighlighter.php', 'PhabricatorSyntaxHighlightingConfigOptions' => 'applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php', 'PhabricatorSyntaxStyle' => 'infrastructure/syntax/PhabricatorSyntaxStyle.php', 'PhabricatorSystemAction' => 'applications/system/action/PhabricatorSystemAction.php', 'PhabricatorSystemActionEngine' => 'applications/system/engine/PhabricatorSystemActionEngine.php', 'PhabricatorSystemActionGarbageCollector' => 'applications/system/garbagecollector/PhabricatorSystemActionGarbageCollector.php', 'PhabricatorSystemActionLog' => 'applications/system/storage/PhabricatorSystemActionLog.php', 'PhabricatorSystemActionRateLimitException' => 'applications/system/exception/PhabricatorSystemActionRateLimitException.php', 'PhabricatorSystemApplication' => 'applications/system/application/PhabricatorSystemApplication.php', 'PhabricatorSystemDAO' => 'applications/system/storage/PhabricatorSystemDAO.php', 'PhabricatorSystemDestructionGarbageCollector' => 'applications/system/garbagecollector/PhabricatorSystemDestructionGarbageCollector.php', 'PhabricatorSystemDestructionLog' => 'applications/system/storage/PhabricatorSystemDestructionLog.php', + 'PhabricatorSystemFaviconController' => 'applications/system/controller/PhabricatorSystemFaviconController.php', 'PhabricatorSystemReadOnlyController' => 'applications/system/controller/PhabricatorSystemReadOnlyController.php', 'PhabricatorSystemRemoveDestroyWorkflow' => 'applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php', 'PhabricatorSystemRemoveLogWorkflow' => 'applications/system/management/PhabricatorSystemRemoveLogWorkflow.php', 'PhabricatorSystemRemoveWorkflow' => 'applications/system/management/PhabricatorSystemRemoveWorkflow.php', 'PhabricatorSystemSelectEncodingController' => 'applications/system/controller/PhabricatorSystemSelectEncodingController.php', 'PhabricatorSystemSelectHighlightController' => 'applications/system/controller/PhabricatorSystemSelectHighlightController.php', 'PhabricatorTOTPAuthFactor' => 'applications/auth/factor/PhabricatorTOTPAuthFactor.php', 'PhabricatorTOTPAuthFactorTestCase' => 'applications/auth/factor/__tests__/PhabricatorTOTPAuthFactorTestCase.php', 'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php', 'PhabricatorTestApplication' => 'applications/base/controller/__tests__/PhabricatorTestApplication.php', 'PhabricatorTestCase' => 'infrastructure/testing/PhabricatorTestCase.php', 'PhabricatorTestController' => 'applications/base/controller/__tests__/PhabricatorTestController.php', 'PhabricatorTestDataGenerator' => 'applications/lipsum/generator/PhabricatorTestDataGenerator.php', 'PhabricatorTestNoCycleEdgeType' => 'applications/transactions/edges/PhabricatorTestNoCycleEdgeType.php', 'PhabricatorTestStorageEngine' => 'applications/files/engine/PhabricatorTestStorageEngine.php', 'PhabricatorTestWorker' => 'infrastructure/daemon/workers/__tests__/PhabricatorTestWorker.php', 'PhabricatorTextAreaEditField' => 'applications/transactions/editfield/PhabricatorTextAreaEditField.php', 'PhabricatorTextEditField' => 'applications/transactions/editfield/PhabricatorTextEditField.php', 'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php', 'PhabricatorTimeFormatSetting' => 'applications/settings/setting/PhabricatorTimeFormatSetting.php', 'PhabricatorTimeGuard' => 'infrastructure/time/PhabricatorTimeGuard.php', 'PhabricatorTimeTestCase' => 'infrastructure/time/__tests__/PhabricatorTimeTestCase.php', 'PhabricatorTimezoneIgnoreOffsetSetting' => 'applications/settings/setting/PhabricatorTimezoneIgnoreOffsetSetting.php', 'PhabricatorTimezoneSetting' => 'applications/settings/setting/PhabricatorTimezoneSetting.php', 'PhabricatorTimezoneSetupCheck' => 'applications/config/check/PhabricatorTimezoneSetupCheck.php', 'PhabricatorTitleGlyphsSetting' => 'applications/settings/setting/PhabricatorTitleGlyphsSetting.php', 'PhabricatorToken' => 'applications/tokens/storage/PhabricatorToken.php', 'PhabricatorTokenController' => 'applications/tokens/controller/PhabricatorTokenController.php', 'PhabricatorTokenCount' => 'applications/tokens/storage/PhabricatorTokenCount.php', 'PhabricatorTokenCountQuery' => 'applications/tokens/query/PhabricatorTokenCountQuery.php', 'PhabricatorTokenDAO' => 'applications/tokens/storage/PhabricatorTokenDAO.php', 'PhabricatorTokenDestructionEngineExtension' => 'applications/tokens/engineextension/PhabricatorTokenDestructionEngineExtension.php', 'PhabricatorTokenGiveController' => 'applications/tokens/controller/PhabricatorTokenGiveController.php', 'PhabricatorTokenGiven' => 'applications/tokens/storage/PhabricatorTokenGiven.php', 'PhabricatorTokenGivenController' => 'applications/tokens/controller/PhabricatorTokenGivenController.php', 'PhabricatorTokenGivenEditor' => 'applications/tokens/editor/PhabricatorTokenGivenEditor.php', 'PhabricatorTokenGivenFeedStory' => 'applications/tokens/feed/PhabricatorTokenGivenFeedStory.php', 'PhabricatorTokenGivenQuery' => 'applications/tokens/query/PhabricatorTokenGivenQuery.php', 'PhabricatorTokenLeaderController' => 'applications/tokens/controller/PhabricatorTokenLeaderController.php', 'PhabricatorTokenQuery' => 'applications/tokens/query/PhabricatorTokenQuery.php', 'PhabricatorTokenReceiverInterface' => 'applications/tokens/interface/PhabricatorTokenReceiverInterface.php', 'PhabricatorTokenReceiverQuery' => 'applications/tokens/query/PhabricatorTokenReceiverQuery.php', 'PhabricatorTokenTokenPHIDType' => 'applications/tokens/phid/PhabricatorTokenTokenPHIDType.php', 'PhabricatorTokenUIEventListener' => 'applications/tokens/event/PhabricatorTokenUIEventListener.php', 'PhabricatorTokenizerEditField' => 'applications/transactions/editfield/PhabricatorTokenizerEditField.php', 'PhabricatorTokensApplication' => 'applications/tokens/application/PhabricatorTokensApplication.php', 'PhabricatorTokensCurtainExtension' => 'applications/tokens/engineextension/PhabricatorTokensCurtainExtension.php', 'PhabricatorTokensSettingsPanel' => 'applications/settings/panel/PhabricatorTokensSettingsPanel.php', 'PhabricatorTokensToken' => 'applications/tokens/storage/PhabricatorTokensToken.php', 'PhabricatorTooltipUIExample' => 'applications/uiexample/examples/PhabricatorTooltipUIExample.php', 'PhabricatorTransactionChange' => 'applications/transactions/data/PhabricatorTransactionChange.php', 'PhabricatorTransactionRemarkupChange' => 'applications/transactions/data/PhabricatorTransactionRemarkupChange.php', 'PhabricatorTransactions' => 'applications/transactions/constants/PhabricatorTransactions.php', 'PhabricatorTransactionsApplication' => 'applications/transactions/application/PhabricatorTransactionsApplication.php', 'PhabricatorTransactionsDestructionEngineExtension' => 'applications/transactions/engineextension/PhabricatorTransactionsDestructionEngineExtension.php', 'PhabricatorTransactionsFulltextEngineExtension' => 'applications/transactions/engineextension/PhabricatorTransactionsFulltextEngineExtension.php', 'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php', 'PhabricatorTranslationSetting' => 'applications/settings/setting/PhabricatorTranslationSetting.php', 'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php', 'PhabricatorTriggerAction' => 'infrastructure/daemon/workers/action/PhabricatorTriggerAction.php', 'PhabricatorTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorTriggerClock.php', 'PhabricatorTriggerClockTestCase' => 'infrastructure/daemon/workers/clock/__tests__/PhabricatorTriggerClockTestCase.php', 'PhabricatorTriggerDaemon' => 'infrastructure/daemon/workers/PhabricatorTriggerDaemon.php', 'PhabricatorTrivialTestCase' => 'infrastructure/testing/__tests__/PhabricatorTrivialTestCase.php', 'PhabricatorTwitchAuthProvider' => 'applications/auth/provider/PhabricatorTwitchAuthProvider.php', 'PhabricatorTwitterAuthProvider' => 'applications/auth/provider/PhabricatorTwitterAuthProvider.php', 'PhabricatorTypeaheadApplication' => 'applications/typeahead/application/PhabricatorTypeaheadApplication.php', 'PhabricatorTypeaheadCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php', 'PhabricatorTypeaheadDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadDatasourceController.php', 'PhabricatorTypeaheadFunctionHelpController' => 'applications/typeahead/controller/PhabricatorTypeaheadFunctionHelpController.php', 'PhabricatorTypeaheadInvalidTokenException' => 'applications/typeahead/exception/PhabricatorTypeaheadInvalidTokenException.php', 'PhabricatorTypeaheadModularDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php', 'PhabricatorTypeaheadMonogramDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php', 'PhabricatorTypeaheadResult' => 'applications/typeahead/storage/PhabricatorTypeaheadResult.php', 'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadRuntimeCompositeDatasource.php', 'PhabricatorTypeaheadTokenView' => 'applications/typeahead/view/PhabricatorTypeaheadTokenView.php', 'PhabricatorUIConfigOptions' => 'applications/config/option/PhabricatorUIConfigOptions.php', 'PhabricatorUIExample' => 'applications/uiexample/examples/PhabricatorUIExample.php', 'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/PhabricatorUIExampleRenderController.php', 'PhabricatorUIExamplesApplication' => 'applications/uiexample/application/PhabricatorUIExamplesApplication.php', 'PhabricatorUSEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php', 'PhabricatorUnifiedDiffsSetting' => 'applications/settings/setting/PhabricatorUnifiedDiffsSetting.php', 'PhabricatorUnitTestContentSource' => 'infrastructure/contentsource/PhabricatorUnitTestContentSource.php', 'PhabricatorUnitsTestCase' => 'view/__tests__/PhabricatorUnitsTestCase.php', 'PhabricatorUnknownContentSource' => 'infrastructure/contentsource/PhabricatorUnknownContentSource.php', 'PhabricatorUnsubscribedFromObjectEdgeType' => 'applications/transactions/edges/PhabricatorUnsubscribedFromObjectEdgeType.php', 'PhabricatorUser' => 'applications/people/storage/PhabricatorUser.php', 'PhabricatorUserBlurbField' => 'applications/people/customfield/PhabricatorUserBlurbField.php', 'PhabricatorUserCache' => 'applications/people/storage/PhabricatorUserCache.php', 'PhabricatorUserCacheType' => 'applications/people/cache/PhabricatorUserCacheType.php', 'PhabricatorUserCardView' => 'applications/people/view/PhabricatorUserCardView.php', 'PhabricatorUserConfigOptions' => 'applications/people/config/PhabricatorUserConfigOptions.php', 'PhabricatorUserConfiguredCustomField' => 'applications/people/customfield/PhabricatorUserConfiguredCustomField.php', 'PhabricatorUserConfiguredCustomFieldStorage' => 'applications/people/storage/PhabricatorUserConfiguredCustomFieldStorage.php', 'PhabricatorUserCustomField' => 'applications/people/customfield/PhabricatorUserCustomField.php', 'PhabricatorUserCustomFieldNumericIndex' => 'applications/people/storage/PhabricatorUserCustomFieldNumericIndex.php', 'PhabricatorUserCustomFieldStringIndex' => 'applications/people/storage/PhabricatorUserCustomFieldStringIndex.php', 'PhabricatorUserDAO' => 'applications/people/storage/PhabricatorUserDAO.php', 'PhabricatorUserEditor' => 'applications/people/editor/PhabricatorUserEditor.php', 'PhabricatorUserEditorTestCase' => 'applications/people/editor/__tests__/PhabricatorUserEditorTestCase.php', 'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php', 'PhabricatorUserEmailTestCase' => 'applications/people/storage/__tests__/PhabricatorUserEmailTestCase.php', 'PhabricatorUserFulltextEngine' => 'applications/people/search/PhabricatorUserFulltextEngine.php', 'PhabricatorUserIconField' => 'applications/people/customfield/PhabricatorUserIconField.php', 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', 'PhabricatorUserLogView' => 'applications/people/view/PhabricatorUserLogView.php', 'PhabricatorUserMessageCountCacheType' => 'applications/people/cache/PhabricatorUserMessageCountCacheType.php', 'PhabricatorUserNotificationCountCacheType' => 'applications/people/cache/PhabricatorUserNotificationCountCacheType.php', 'PhabricatorUserPHIDResolver' => 'applications/phid/resolver/PhabricatorUserPHIDResolver.php', 'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php', 'PhabricatorUserPreferencesCacheType' => 'applications/people/cache/PhabricatorUserPreferencesCacheType.php', 'PhabricatorUserPreferencesEditor' => 'applications/settings/editor/PhabricatorUserPreferencesEditor.php', 'PhabricatorUserPreferencesPHIDType' => 'applications/settings/phid/PhabricatorUserPreferencesPHIDType.php', 'PhabricatorUserPreferencesQuery' => 'applications/settings/query/PhabricatorUserPreferencesQuery.php', 'PhabricatorUserPreferencesSearchEngine' => 'applications/settings/query/PhabricatorUserPreferencesSearchEngine.php', 'PhabricatorUserPreferencesTransaction' => 'applications/settings/storage/PhabricatorUserPreferencesTransaction.php', 'PhabricatorUserPreferencesTransactionQuery' => 'applications/settings/query/PhabricatorUserPreferencesTransactionQuery.php', 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', 'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php', 'PhabricatorUserProfileImageCacheType' => 'applications/people/cache/PhabricatorUserProfileImageCacheType.php', 'PhabricatorUserRealNameField' => 'applications/people/customfield/PhabricatorUserRealNameField.php', 'PhabricatorUserRolesField' => 'applications/people/customfield/PhabricatorUserRolesField.php', 'PhabricatorUserSchemaSpec' => 'applications/people/storage/PhabricatorUserSchemaSpec.php', 'PhabricatorUserSinceField' => 'applications/people/customfield/PhabricatorUserSinceField.php', 'PhabricatorUserStatusField' => 'applications/people/customfield/PhabricatorUserStatusField.php', 'PhabricatorUserTestCase' => 'applications/people/storage/__tests__/PhabricatorUserTestCase.php', 'PhabricatorUserTitleField' => 'applications/people/customfield/PhabricatorUserTitleField.php', 'PhabricatorUserTransaction' => 'applications/people/storage/PhabricatorUserTransaction.php', 'PhabricatorUsersEditField' => 'applications/transactions/editfield/PhabricatorUsersEditField.php', 'PhabricatorUsersPolicyRule' => 'applications/people/policyrule/PhabricatorUsersPolicyRule.php', 'PhabricatorUsersSearchField' => 'applications/people/searchfield/PhabricatorUsersSearchField.php', 'PhabricatorVCSResponse' => 'applications/repository/response/PhabricatorVCSResponse.php', 'PhabricatorVersionedDraft' => 'applications/draft/storage/PhabricatorVersionedDraft.php', 'PhabricatorVeryWowEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorVeryWowEnglishTranslation.php', 'PhabricatorViewerDatasource' => 'applications/people/typeahead/PhabricatorViewerDatasource.php', 'PhabricatorWatcherHasObjectEdgeType' => 'applications/transactions/edges/PhabricatorWatcherHasObjectEdgeType.php', 'PhabricatorWebContentSource' => 'infrastructure/contentsource/PhabricatorWebContentSource.php', 'PhabricatorWeekStartDaySetting' => 'applications/settings/setting/PhabricatorWeekStartDaySetting.php', 'PhabricatorWordPressAuthProvider' => 'applications/auth/provider/PhabricatorWordPressAuthProvider.php', 'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php', 'PhabricatorWorkerActiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php', 'PhabricatorWorkerArchiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php', 'PhabricatorWorkerArchiveTaskQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerArchiveTaskQuery.php', 'PhabricatorWorkerBulkJob' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerBulkJob.php', 'PhabricatorWorkerBulkJobCreateWorker' => 'infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobCreateWorker.php', 'PhabricatorWorkerBulkJobEditor' => 'infrastructure/daemon/workers/editor/PhabricatorWorkerBulkJobEditor.php', 'PhabricatorWorkerBulkJobPHIDType' => 'infrastructure/daemon/workers/phid/PhabricatorWorkerBulkJobPHIDType.php', 'PhabricatorWorkerBulkJobQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerBulkJobQuery.php', 'PhabricatorWorkerBulkJobSearchEngine' => 'infrastructure/daemon/workers/query/PhabricatorWorkerBulkJobSearchEngine.php', 'PhabricatorWorkerBulkJobTaskWorker' => 'infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobTaskWorker.php', 'PhabricatorWorkerBulkJobTestCase' => 'infrastructure/daemon/workers/__tests__/PhabricatorWorkerBulkJobTestCase.php', 'PhabricatorWorkerBulkJobTransaction' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerBulkJobTransaction.php', 'PhabricatorWorkerBulkJobTransactionQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerBulkJobTransactionQuery.php', 'PhabricatorWorkerBulkJobType' => 'infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobType.php', 'PhabricatorWorkerBulkJobWorker' => 'infrastructure/daemon/workers/bulk/PhabricatorWorkerBulkJobWorker.php', 'PhabricatorWorkerBulkTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerBulkTask.php', 'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerDAO.php', 'PhabricatorWorkerDestructionEngineExtension' => 'infrastructure/daemon/workers/engineextension/PhabricatorWorkerDestructionEngineExtension.php', 'PhabricatorWorkerLeaseQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php', 'PhabricatorWorkerManagementCancelWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php', 'PhabricatorWorkerManagementExecuteWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementExecuteWorkflow.php', 'PhabricatorWorkerManagementFloodWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementFloodWorkflow.php', 'PhabricatorWorkerManagementFreeWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php', 'PhabricatorWorkerManagementRetryWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php', 'PhabricatorWorkerManagementWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php', 'PhabricatorWorkerPermanentFailureException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerPermanentFailureException.php', 'PhabricatorWorkerSchemaSpec' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerSchemaSpec.php', 'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php', 'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTaskData.php', 'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/PhabricatorWorkerTaskDetailController.php', 'PhabricatorWorkerTestCase' => 'infrastructure/daemon/workers/__tests__/PhabricatorWorkerTestCase.php', 'PhabricatorWorkerTrigger' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTrigger.php', 'PhabricatorWorkerTriggerEvent' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTriggerEvent.php', 'PhabricatorWorkerTriggerManagementFireWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerTriggerManagementFireWorkflow.php', 'PhabricatorWorkerTriggerManagementWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerTriggerManagementWorkflow.php', 'PhabricatorWorkerTriggerPHIDType' => 'infrastructure/daemon/workers/phid/PhabricatorWorkerTriggerPHIDType.php', 'PhabricatorWorkerTriggerQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerTriggerQuery.php', 'PhabricatorWorkerYieldException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerYieldException.php', 'PhabricatorWorkingCopyDiscoveryTestCase' => 'applications/repository/engine/__tests__/PhabricatorWorkingCopyDiscoveryTestCase.php', 'PhabricatorWorkingCopyPullTestCase' => 'applications/repository/engine/__tests__/PhabricatorWorkingCopyPullTestCase.php', 'PhabricatorWorkingCopyTestCase' => 'applications/repository/engine/__tests__/PhabricatorWorkingCopyTestCase.php', 'PhabricatorXHPASTDAO' => 'applications/phpast/storage/PhabricatorXHPASTDAO.php', 'PhabricatorXHPASTParseTree' => 'applications/phpast/storage/PhabricatorXHPASTParseTree.php', 'PhabricatorXHPASTViewController' => 'applications/phpast/controller/PhabricatorXHPASTViewController.php', 'PhabricatorXHPASTViewFrameController' => 'applications/phpast/controller/PhabricatorXHPASTViewFrameController.php', 'PhabricatorXHPASTViewFramesetController' => 'applications/phpast/controller/PhabricatorXHPASTViewFramesetController.php', 'PhabricatorXHPASTViewInputController' => 'applications/phpast/controller/PhabricatorXHPASTViewInputController.php', 'PhabricatorXHPASTViewPanelController' => 'applications/phpast/controller/PhabricatorXHPASTViewPanelController.php', 'PhabricatorXHPASTViewRunController' => 'applications/phpast/controller/PhabricatorXHPASTViewRunController.php', 'PhabricatorXHPASTViewStreamController' => 'applications/phpast/controller/PhabricatorXHPASTViewStreamController.php', 'PhabricatorXHPASTViewTreeController' => 'applications/phpast/controller/PhabricatorXHPASTViewTreeController.php', 'PhabricatorXHProfApplication' => 'applications/xhprof/application/PhabricatorXHProfApplication.php', 'PhabricatorXHProfController' => 'applications/xhprof/controller/PhabricatorXHProfController.php', 'PhabricatorXHProfDAO' => 'applications/xhprof/storage/PhabricatorXHProfDAO.php', 'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/PhabricatorXHProfProfileController.php', 'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/PhabricatorXHProfProfileSymbolView.php', 'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/PhabricatorXHProfProfileTopLevelView.php', 'PhabricatorXHProfProfileView' => 'applications/xhprof/view/PhabricatorXHProfProfileView.php', 'PhabricatorXHProfSample' => 'applications/xhprof/storage/PhabricatorXHProfSample.php', 'PhabricatorXHProfSampleListController' => 'applications/xhprof/controller/PhabricatorXHProfSampleListController.php', 'PhabricatorYoutubeRemarkupRule' => 'infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php', 'Phame404Response' => 'applications/phame/site/Phame404Response.php', 'PhameBlog' => 'applications/phame/storage/PhameBlog.php', 'PhameBlog404Controller' => 'applications/phame/controller/blog/PhameBlog404Controller.php', 'PhameBlogArchiveController' => 'applications/phame/controller/blog/PhameBlogArchiveController.php', 'PhameBlogController' => 'applications/phame/controller/blog/PhameBlogController.php', 'PhameBlogCreateCapability' => 'applications/phame/capability/PhameBlogCreateCapability.php', 'PhameBlogDatasource' => 'applications/phame/typeahead/PhameBlogDatasource.php', 'PhameBlogEditConduitAPIMethod' => 'applications/phame/conduit/PhameBlogEditConduitAPIMethod.php', 'PhameBlogEditController' => 'applications/phame/controller/blog/PhameBlogEditController.php', 'PhameBlogEditEngine' => 'applications/phame/editor/PhameBlogEditEngine.php', 'PhameBlogEditor' => 'applications/phame/editor/PhameBlogEditor.php', 'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php', 'PhameBlogFulltextEngine' => 'applications/phame/search/PhameBlogFulltextEngine.php', 'PhameBlogHeaderPictureController' => 'applications/phame/controller/blog/PhameBlogHeaderPictureController.php', 'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php', 'PhameBlogListView' => 'applications/phame/view/PhameBlogListView.php', 'PhameBlogManageController' => 'applications/phame/controller/blog/PhameBlogManageController.php', 'PhameBlogProfilePictureController' => 'applications/phame/controller/blog/PhameBlogProfilePictureController.php', 'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php', 'PhameBlogReplyHandler' => 'applications/phame/mail/PhameBlogReplyHandler.php', 'PhameBlogSearchConduitAPIMethod' => 'applications/phame/conduit/PhameBlogSearchConduitAPIMethod.php', 'PhameBlogSearchEngine' => 'applications/phame/query/PhameBlogSearchEngine.php', 'PhameBlogSite' => 'applications/phame/site/PhameBlogSite.php', 'PhameBlogTransaction' => 'applications/phame/storage/PhameBlogTransaction.php', 'PhameBlogTransactionQuery' => 'applications/phame/query/PhameBlogTransactionQuery.php', 'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php', 'PhameConstants' => 'applications/phame/constants/PhameConstants.php', 'PhameController' => 'applications/phame/controller/PhameController.php', 'PhameDAO' => 'applications/phame/storage/PhameDAO.php', 'PhameDescriptionView' => 'applications/phame/view/PhameDescriptionView.php', 'PhameDraftListView' => 'applications/phame/view/PhameDraftListView.php', 'PhameHomeController' => 'applications/phame/controller/PhameHomeController.php', 'PhameLiveController' => 'applications/phame/controller/PhameLiveController.php', 'PhameNextPostView' => 'applications/phame/view/PhameNextPostView.php', 'PhamePost' => 'applications/phame/storage/PhamePost.php', 'PhamePostArchiveController' => 'applications/phame/controller/post/PhamePostArchiveController.php', 'PhamePostController' => 'applications/phame/controller/post/PhamePostController.php', 'PhamePostEditConduitAPIMethod' => 'applications/phame/conduit/PhamePostEditConduitAPIMethod.php', 'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php', 'PhamePostEditEngine' => 'applications/phame/editor/PhamePostEditEngine.php', 'PhamePostEditor' => 'applications/phame/editor/PhamePostEditor.php', 'PhamePostFulltextEngine' => 'applications/phame/search/PhamePostFulltextEngine.php', 'PhamePostHistoryController' => 'applications/phame/controller/post/PhamePostHistoryController.php', 'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php', 'PhamePostListView' => 'applications/phame/view/PhamePostListView.php', 'PhamePostMailReceiver' => 'applications/phame/mail/PhamePostMailReceiver.php', 'PhamePostMoveController' => 'applications/phame/controller/post/PhamePostMoveController.php', 'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php', 'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php', 'PhamePostRemarkupRule' => 'applications/phame/remarkup/PhamePostRemarkupRule.php', 'PhamePostReplyHandler' => 'applications/phame/mail/PhamePostReplyHandler.php', 'PhamePostSearchConduitAPIMethod' => 'applications/phame/conduit/PhamePostSearchConduitAPIMethod.php', 'PhamePostSearchEngine' => 'applications/phame/query/PhamePostSearchEngine.php', 'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php', 'PhamePostTransactionComment' => 'applications/phame/storage/PhamePostTransactionComment.php', 'PhamePostTransactionQuery' => 'applications/phame/query/PhamePostTransactionQuery.php', 'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php', 'PhameSchemaSpec' => 'applications/phame/storage/PhameSchemaSpec.php', 'PhameSite' => 'applications/phame/site/PhameSite.php', 'PhluxController' => 'applications/phlux/controller/PhluxController.php', 'PhluxDAO' => 'applications/phlux/storage/PhluxDAO.php', 'PhluxEditController' => 'applications/phlux/controller/PhluxEditController.php', 'PhluxListController' => 'applications/phlux/controller/PhluxListController.php', 'PhluxTransaction' => 'applications/phlux/storage/PhluxTransaction.php', 'PhluxTransactionQuery' => 'applications/phlux/query/PhluxTransactionQuery.php', 'PhluxVariable' => 'applications/phlux/storage/PhluxVariable.php', 'PhluxVariableEditor' => 'applications/phlux/editor/PhluxVariableEditor.php', 'PhluxVariablePHIDType' => 'applications/phlux/phid/PhluxVariablePHIDType.php', 'PhluxVariableQuery' => 'applications/phlux/query/PhluxVariableQuery.php', 'PhluxViewController' => 'applications/phlux/controller/PhluxViewController.php', 'PholioController' => 'applications/pholio/controller/PholioController.php', 'PholioDAO' => 'applications/pholio/storage/PholioDAO.php', 'PholioDefaultEditCapability' => 'applications/pholio/capability/PholioDefaultEditCapability.php', 'PholioDefaultViewCapability' => 'applications/pholio/capability/PholioDefaultViewCapability.php', 'PholioImage' => 'applications/pholio/storage/PholioImage.php', 'PholioImagePHIDType' => 'applications/pholio/phid/PholioImagePHIDType.php', 'PholioImageQuery' => 'applications/pholio/query/PholioImageQuery.php', 'PholioImageUploadController' => 'applications/pholio/controller/PholioImageUploadController.php', 'PholioInlineController' => 'applications/pholio/controller/PholioInlineController.php', 'PholioInlineListController' => 'applications/pholio/controller/PholioInlineListController.php', 'PholioMock' => 'applications/pholio/storage/PholioMock.php', 'PholioMockArchiveController' => 'applications/pholio/controller/PholioMockArchiveController.php', 'PholioMockAuthorHeraldField' => 'applications/pholio/herald/PholioMockAuthorHeraldField.php', 'PholioMockCommentController' => 'applications/pholio/controller/PholioMockCommentController.php', 'PholioMockDescriptionHeraldField' => 'applications/pholio/herald/PholioMockDescriptionHeraldField.php', 'PholioMockEditController' => 'applications/pholio/controller/PholioMockEditController.php', 'PholioMockEditor' => 'applications/pholio/editor/PholioMockEditor.php', 'PholioMockEmbedView' => 'applications/pholio/view/PholioMockEmbedView.php', 'PholioMockFulltextEngine' => 'applications/pholio/search/PholioMockFulltextEngine.php', 'PholioMockHasTaskEdgeType' => 'applications/pholio/edge/PholioMockHasTaskEdgeType.php', 'PholioMockHasTaskRelationship' => 'applications/pholio/relationships/PholioMockHasTaskRelationship.php', 'PholioMockHeraldField' => 'applications/pholio/herald/PholioMockHeraldField.php', 'PholioMockHeraldFieldGroup' => 'applications/pholio/herald/PholioMockHeraldFieldGroup.php', 'PholioMockImagesView' => 'applications/pholio/view/PholioMockImagesView.php', 'PholioMockListController' => 'applications/pholio/controller/PholioMockListController.php', 'PholioMockMailReceiver' => 'applications/pholio/mail/PholioMockMailReceiver.php', 'PholioMockNameHeraldField' => 'applications/pholio/herald/PholioMockNameHeraldField.php', 'PholioMockPHIDType' => 'applications/pholio/phid/PholioMockPHIDType.php', 'PholioMockQuery' => 'applications/pholio/query/PholioMockQuery.php', 'PholioMockRelationship' => 'applications/pholio/relationships/PholioMockRelationship.php', 'PholioMockRelationshipSource' => 'applications/search/relationship/PholioMockRelationshipSource.php', 'PholioMockSearchEngine' => 'applications/pholio/query/PholioMockSearchEngine.php', 'PholioMockThumbGridView' => 'applications/pholio/view/PholioMockThumbGridView.php', 'PholioMockViewController' => 'applications/pholio/controller/PholioMockViewController.php', 'PholioRemarkupRule' => 'applications/pholio/remarkup/PholioRemarkupRule.php', 'PholioReplyHandler' => 'applications/pholio/mail/PholioReplyHandler.php', 'PholioSchemaSpec' => 'applications/pholio/storage/PholioSchemaSpec.php', 'PholioTransaction' => 'applications/pholio/storage/PholioTransaction.php', 'PholioTransactionComment' => 'applications/pholio/storage/PholioTransactionComment.php', 'PholioTransactionQuery' => 'applications/pholio/query/PholioTransactionQuery.php', 'PholioTransactionView' => 'applications/pholio/view/PholioTransactionView.php', 'PholioUploadedImageView' => 'applications/pholio/view/PholioUploadedImageView.php', 'PhortuneAccount' => 'applications/phortune/storage/PhortuneAccount.php', 'PhortuneAccountEditController' => 'applications/phortune/controller/PhortuneAccountEditController.php', 'PhortuneAccountEditor' => 'applications/phortune/editor/PhortuneAccountEditor.php', 'PhortuneAccountHasMemberEdgeType' => 'applications/phortune/edge/PhortuneAccountHasMemberEdgeType.php', 'PhortuneAccountListController' => 'applications/phortune/controller/PhortuneAccountListController.php', 'PhortuneAccountPHIDType' => 'applications/phortune/phid/PhortuneAccountPHIDType.php', 'PhortuneAccountQuery' => 'applications/phortune/query/PhortuneAccountQuery.php', 'PhortuneAccountTransaction' => 'applications/phortune/storage/PhortuneAccountTransaction.php', 'PhortuneAccountTransactionQuery' => 'applications/phortune/query/PhortuneAccountTransactionQuery.php', 'PhortuneAccountViewController' => 'applications/phortune/controller/PhortuneAccountViewController.php', 'PhortuneAdHocCart' => 'applications/phortune/cart/PhortuneAdHocCart.php', 'PhortuneAdHocProduct' => 'applications/phortune/product/PhortuneAdHocProduct.php', 'PhortuneCart' => 'applications/phortune/storage/PhortuneCart.php', 'PhortuneCartAcceptController' => 'applications/phortune/controller/PhortuneCartAcceptController.php', 'PhortuneCartCancelController' => 'applications/phortune/controller/PhortuneCartCancelController.php', 'PhortuneCartCheckoutController' => 'applications/phortune/controller/PhortuneCartCheckoutController.php', 'PhortuneCartController' => 'applications/phortune/controller/PhortuneCartController.php', 'PhortuneCartEditor' => 'applications/phortune/editor/PhortuneCartEditor.php', 'PhortuneCartImplementation' => 'applications/phortune/cart/PhortuneCartImplementation.php', 'PhortuneCartListController' => 'applications/phortune/controller/PhortuneCartListController.php', 'PhortuneCartPHIDType' => 'applications/phortune/phid/PhortuneCartPHIDType.php', 'PhortuneCartQuery' => 'applications/phortune/query/PhortuneCartQuery.php', 'PhortuneCartReplyHandler' => 'applications/phortune/mail/PhortuneCartReplyHandler.php', 'PhortuneCartSearchEngine' => 'applications/phortune/query/PhortuneCartSearchEngine.php', 'PhortuneCartTransaction' => 'applications/phortune/storage/PhortuneCartTransaction.php', 'PhortuneCartTransactionQuery' => 'applications/phortune/query/PhortuneCartTransactionQuery.php', 'PhortuneCartUpdateController' => 'applications/phortune/controller/PhortuneCartUpdateController.php', 'PhortuneCartViewController' => 'applications/phortune/controller/PhortuneCartViewController.php', 'PhortuneCharge' => 'applications/phortune/storage/PhortuneCharge.php', 'PhortuneChargeListController' => 'applications/phortune/controller/PhortuneChargeListController.php', 'PhortuneChargePHIDType' => 'applications/phortune/phid/PhortuneChargePHIDType.php', 'PhortuneChargeQuery' => 'applications/phortune/query/PhortuneChargeQuery.php', 'PhortuneChargeSearchEngine' => 'applications/phortune/query/PhortuneChargeSearchEngine.php', 'PhortuneChargeTableView' => 'applications/phortune/view/PhortuneChargeTableView.php', 'PhortuneConstants' => 'applications/phortune/constants/PhortuneConstants.php', 'PhortuneController' => 'applications/phortune/controller/PhortuneController.php', 'PhortuneCreditCardForm' => 'applications/phortune/view/PhortuneCreditCardForm.php', 'PhortuneCurrency' => 'applications/phortune/currency/PhortuneCurrency.php', 'PhortuneCurrencySerializer' => 'applications/phortune/currency/PhortuneCurrencySerializer.php', 'PhortuneCurrencyTestCase' => 'applications/phortune/currency/__tests__/PhortuneCurrencyTestCase.php', 'PhortuneDAO' => 'applications/phortune/storage/PhortuneDAO.php', 'PhortuneErrCode' => 'applications/phortune/constants/PhortuneErrCode.php', 'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php', 'PhortuneMemberHasAccountEdgeType' => 'applications/phortune/edge/PhortuneMemberHasAccountEdgeType.php', 'PhortuneMemberHasMerchantEdgeType' => 'applications/phortune/edge/PhortuneMemberHasMerchantEdgeType.php', 'PhortuneMerchant' => 'applications/phortune/storage/PhortuneMerchant.php', 'PhortuneMerchantCapability' => 'applications/phortune/capability/PhortuneMerchantCapability.php', 'PhortuneMerchantController' => 'applications/phortune/controller/PhortuneMerchantController.php', 'PhortuneMerchantEditController' => 'applications/phortune/controller/PhortuneMerchantEditController.php', 'PhortuneMerchantEditor' => 'applications/phortune/editor/PhortuneMerchantEditor.php', 'PhortuneMerchantHasMemberEdgeType' => 'applications/phortune/edge/PhortuneMerchantHasMemberEdgeType.php', 'PhortuneMerchantInvoiceCreateController' => 'applications/phortune/controller/PhortuneMerchantInvoiceCreateController.php', 'PhortuneMerchantListController' => 'applications/phortune/controller/PhortuneMerchantListController.php', 'PhortuneMerchantPHIDType' => 'applications/phortune/phid/PhortuneMerchantPHIDType.php', 'PhortuneMerchantQuery' => 'applications/phortune/query/PhortuneMerchantQuery.php', 'PhortuneMerchantSearchEngine' => 'applications/phortune/query/PhortuneMerchantSearchEngine.php', 'PhortuneMerchantTransaction' => 'applications/phortune/storage/PhortuneMerchantTransaction.php', 'PhortuneMerchantTransactionQuery' => 'applications/phortune/query/PhortuneMerchantTransactionQuery.php', 'PhortuneMerchantViewController' => 'applications/phortune/controller/PhortuneMerchantViewController.php', 'PhortuneMonthYearExpiryControl' => 'applications/phortune/control/PhortuneMonthYearExpiryControl.php', 'PhortuneOrderTableView' => 'applications/phortune/view/PhortuneOrderTableView.php', 'PhortunePayPalPaymentProvider' => 'applications/phortune/provider/PhortunePayPalPaymentProvider.php', 'PhortunePaymentMethod' => 'applications/phortune/storage/PhortunePaymentMethod.php', 'PhortunePaymentMethodCreateController' => 'applications/phortune/controller/PhortunePaymentMethodCreateController.php', 'PhortunePaymentMethodDisableController' => 'applications/phortune/controller/PhortunePaymentMethodDisableController.php', 'PhortunePaymentMethodEditController' => 'applications/phortune/controller/PhortunePaymentMethodEditController.php', 'PhortunePaymentMethodPHIDType' => 'applications/phortune/phid/PhortunePaymentMethodPHIDType.php', 'PhortunePaymentMethodQuery' => 'applications/phortune/query/PhortunePaymentMethodQuery.php', 'PhortunePaymentProvider' => 'applications/phortune/provider/PhortunePaymentProvider.php', 'PhortunePaymentProviderConfig' => 'applications/phortune/storage/PhortunePaymentProviderConfig.php', 'PhortunePaymentProviderConfigEditor' => 'applications/phortune/editor/PhortunePaymentProviderConfigEditor.php', 'PhortunePaymentProviderConfigQuery' => 'applications/phortune/query/PhortunePaymentProviderConfigQuery.php', 'PhortunePaymentProviderConfigTransaction' => 'applications/phortune/storage/PhortunePaymentProviderConfigTransaction.php', 'PhortunePaymentProviderConfigTransactionQuery' => 'applications/phortune/query/PhortunePaymentProviderConfigTransactionQuery.php', 'PhortunePaymentProviderPHIDType' => 'applications/phortune/phid/PhortunePaymentProviderPHIDType.php', 'PhortunePaymentProviderTestCase' => 'applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php', 'PhortuneProduct' => 'applications/phortune/storage/PhortuneProduct.php', 'PhortuneProductImplementation' => 'applications/phortune/product/PhortuneProductImplementation.php', 'PhortuneProductListController' => 'applications/phortune/controller/PhortuneProductListController.php', 'PhortuneProductPHIDType' => 'applications/phortune/phid/PhortuneProductPHIDType.php', 'PhortuneProductQuery' => 'applications/phortune/query/PhortuneProductQuery.php', 'PhortuneProductViewController' => 'applications/phortune/controller/PhortuneProductViewController.php', 'PhortuneProviderActionController' => 'applications/phortune/controller/PhortuneProviderActionController.php', 'PhortuneProviderDisableController' => 'applications/phortune/controller/PhortuneProviderDisableController.php', 'PhortuneProviderEditController' => 'applications/phortune/controller/PhortuneProviderEditController.php', 'PhortunePurchase' => 'applications/phortune/storage/PhortunePurchase.php', 'PhortunePurchasePHIDType' => 'applications/phortune/phid/PhortunePurchasePHIDType.php', 'PhortunePurchaseQuery' => 'applications/phortune/query/PhortunePurchaseQuery.php', 'PhortuneSchemaSpec' => 'applications/phortune/storage/PhortuneSchemaSpec.php', 'PhortuneStripePaymentProvider' => 'applications/phortune/provider/PhortuneStripePaymentProvider.php', 'PhortuneSubscription' => 'applications/phortune/storage/PhortuneSubscription.php', 'PhortuneSubscriptionCart' => 'applications/phortune/cart/PhortuneSubscriptionCart.php', 'PhortuneSubscriptionEditController' => 'applications/phortune/controller/PhortuneSubscriptionEditController.php', 'PhortuneSubscriptionImplementation' => 'applications/phortune/subscription/PhortuneSubscriptionImplementation.php', 'PhortuneSubscriptionListController' => 'applications/phortune/controller/PhortuneSubscriptionListController.php', 'PhortuneSubscriptionPHIDType' => 'applications/phortune/phid/PhortuneSubscriptionPHIDType.php', 'PhortuneSubscriptionProduct' => 'applications/phortune/product/PhortuneSubscriptionProduct.php', 'PhortuneSubscriptionQuery' => 'applications/phortune/query/PhortuneSubscriptionQuery.php', 'PhortuneSubscriptionSearchEngine' => 'applications/phortune/query/PhortuneSubscriptionSearchEngine.php', 'PhortuneSubscriptionTableView' => 'applications/phortune/view/PhortuneSubscriptionTableView.php', 'PhortuneSubscriptionViewController' => 'applications/phortune/controller/PhortuneSubscriptionViewController.php', 'PhortuneSubscriptionWorker' => 'applications/phortune/worker/PhortuneSubscriptionWorker.php', 'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php', 'PhortuneWePayPaymentProvider' => 'applications/phortune/provider/PhortuneWePayPaymentProvider.php', 'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php', 'PhragmentCanCreateCapability' => 'applications/phragment/capability/PhragmentCanCreateCapability.php', 'PhragmentConduitAPIMethod' => 'applications/phragment/conduit/PhragmentConduitAPIMethod.php', 'PhragmentController' => 'applications/phragment/controller/PhragmentController.php', 'PhragmentCreateController' => 'applications/phragment/controller/PhragmentCreateController.php', 'PhragmentDAO' => 'applications/phragment/storage/PhragmentDAO.php', 'PhragmentFragment' => 'applications/phragment/storage/PhragmentFragment.php', 'PhragmentFragmentPHIDType' => 'applications/phragment/phid/PhragmentFragmentPHIDType.php', 'PhragmentFragmentQuery' => 'applications/phragment/query/PhragmentFragmentQuery.php', 'PhragmentFragmentVersion' => 'applications/phragment/storage/PhragmentFragmentVersion.php', 'PhragmentFragmentVersionPHIDType' => 'applications/phragment/phid/PhragmentFragmentVersionPHIDType.php', 'PhragmentFragmentVersionQuery' => 'applications/phragment/query/PhragmentFragmentVersionQuery.php', 'PhragmentGetPatchConduitAPIMethod' => 'applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php', 'PhragmentHistoryController' => 'applications/phragment/controller/PhragmentHistoryController.php', 'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php', 'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php', 'PhragmentPolicyController' => 'applications/phragment/controller/PhragmentPolicyController.php', 'PhragmentQueryFragmentsConduitAPIMethod' => 'applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php', 'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php', 'PhragmentSchemaSpec' => 'applications/phragment/storage/PhragmentSchemaSpec.php', 'PhragmentSnapshot' => 'applications/phragment/storage/PhragmentSnapshot.php', 'PhragmentSnapshotChild' => 'applications/phragment/storage/PhragmentSnapshotChild.php', 'PhragmentSnapshotChildQuery' => 'applications/phragment/query/PhragmentSnapshotChildQuery.php', 'PhragmentSnapshotCreateController' => 'applications/phragment/controller/PhragmentSnapshotCreateController.php', 'PhragmentSnapshotDeleteController' => 'applications/phragment/controller/PhragmentSnapshotDeleteController.php', 'PhragmentSnapshotPHIDType' => 'applications/phragment/phid/PhragmentSnapshotPHIDType.php', 'PhragmentSnapshotPromoteController' => 'applications/phragment/controller/PhragmentSnapshotPromoteController.php', 'PhragmentSnapshotQuery' => 'applications/phragment/query/PhragmentSnapshotQuery.php', 'PhragmentSnapshotViewController' => 'applications/phragment/controller/PhragmentSnapshotViewController.php', 'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php', 'PhragmentVersionController' => 'applications/phragment/controller/PhragmentVersionController.php', 'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php', 'PhrequentConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentConduitAPIMethod.php', 'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php', 'PhrequentCurtainExtension' => 'applications/phrequent/engineextension/PhrequentCurtainExtension.php', 'PhrequentDAO' => 'applications/phrequent/storage/PhrequentDAO.php', 'PhrequentListController' => 'applications/phrequent/controller/PhrequentListController.php', 'PhrequentPopConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentPopConduitAPIMethod.php', 'PhrequentPushConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentPushConduitAPIMethod.php', 'PhrequentSearchEngine' => 'applications/phrequent/query/PhrequentSearchEngine.php', 'PhrequentTimeBlock' => 'applications/phrequent/storage/PhrequentTimeBlock.php', 'PhrequentTimeBlockTestCase' => 'applications/phrequent/storage/__tests__/PhrequentTimeBlockTestCase.php', 'PhrequentTimeSlices' => 'applications/phrequent/storage/PhrequentTimeSlices.php', 'PhrequentTrackController' => 'applications/phrequent/controller/PhrequentTrackController.php', 'PhrequentTrackableInterface' => 'applications/phrequent/interface/PhrequentTrackableInterface.php', 'PhrequentTrackingConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentTrackingConduitAPIMethod.php', 'PhrequentTrackingEditor' => 'applications/phrequent/editor/PhrequentTrackingEditor.php', 'PhrequentUIEventListener' => 'applications/phrequent/event/PhrequentUIEventListener.php', 'PhrequentUserTime' => 'applications/phrequent/storage/PhrequentUserTime.php', 'PhrequentUserTimeQuery' => 'applications/phrequent/query/PhrequentUserTimeQuery.php', 'PhrictionChangeType' => 'applications/phriction/constants/PhrictionChangeType.php', 'PhrictionConduitAPIMethod' => 'applications/phriction/conduit/PhrictionConduitAPIMethod.php', 'PhrictionConstants' => 'applications/phriction/constants/PhrictionConstants.php', 'PhrictionContent' => 'applications/phriction/storage/PhrictionContent.php', 'PhrictionController' => 'applications/phriction/controller/PhrictionController.php', 'PhrictionCreateConduitAPIMethod' => 'applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php', 'PhrictionDAO' => 'applications/phriction/storage/PhrictionDAO.php', 'PhrictionDeleteController' => 'applications/phriction/controller/PhrictionDeleteController.php', 'PhrictionDiffController' => 'applications/phriction/controller/PhrictionDiffController.php', 'PhrictionDocument' => 'applications/phriction/storage/PhrictionDocument.php', 'PhrictionDocumentAuthorHeraldField' => 'applications/phriction/herald/PhrictionDocumentAuthorHeraldField.php', 'PhrictionDocumentContentHeraldField' => 'applications/phriction/herald/PhrictionDocumentContentHeraldField.php', 'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php', 'PhrictionDocumentFulltextEngine' => 'applications/phriction/search/PhrictionDocumentFulltextEngine.php', 'PhrictionDocumentHeraldAdapter' => 'applications/phriction/herald/PhrictionDocumentHeraldAdapter.php', 'PhrictionDocumentHeraldField' => 'applications/phriction/herald/PhrictionDocumentHeraldField.php', 'PhrictionDocumentHeraldFieldGroup' => 'applications/phriction/herald/PhrictionDocumentHeraldFieldGroup.php', 'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php', 'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php', 'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php', 'PhrictionDocumentStatus' => 'applications/phriction/constants/PhrictionDocumentStatus.php', 'PhrictionDocumentTitleHeraldField' => 'applications/phriction/herald/PhrictionDocumentTitleHeraldField.php', 'PhrictionEditConduitAPIMethod' => 'applications/phriction/conduit/PhrictionEditConduitAPIMethod.php', 'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php', 'PhrictionHistoryConduitAPIMethod' => 'applications/phriction/conduit/PhrictionHistoryConduitAPIMethod.php', 'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php', 'PhrictionInfoConduitAPIMethod' => 'applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php', 'PhrictionListController' => 'applications/phriction/controller/PhrictionListController.php', 'PhrictionMarkupPreviewController' => 'applications/phriction/controller/PhrictionMarkupPreviewController.php', 'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php', 'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php', 'PhrictionRemarkupRule' => 'applications/phriction/markup/PhrictionRemarkupRule.php', 'PhrictionReplyHandler' => 'applications/phriction/mail/PhrictionReplyHandler.php', 'PhrictionSchemaSpec' => 'applications/phriction/storage/PhrictionSchemaSpec.php', 'PhrictionSearchEngine' => 'applications/phriction/query/PhrictionSearchEngine.php', 'PhrictionTransaction' => 'applications/phriction/storage/PhrictionTransaction.php', 'PhrictionTransactionComment' => 'applications/phriction/storage/PhrictionTransactionComment.php', 'PhrictionTransactionEditor' => 'applications/phriction/editor/PhrictionTransactionEditor.php', 'PhrictionTransactionQuery' => 'applications/phriction/query/PhrictionTransactionQuery.php', 'PolicyLockOptionType' => 'applications/policy/config/PolicyLockOptionType.php', 'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php', 'PonderAnswer' => 'applications/ponder/storage/PonderAnswer.php', 'PonderAnswerCommentController' => 'applications/ponder/controller/PonderAnswerCommentController.php', 'PonderAnswerEditController' => 'applications/ponder/controller/PonderAnswerEditController.php', 'PonderAnswerEditor' => 'applications/ponder/editor/PonderAnswerEditor.php', 'PonderAnswerHistoryController' => 'applications/ponder/controller/PonderAnswerHistoryController.php', 'PonderAnswerMailReceiver' => 'applications/ponder/mail/PonderAnswerMailReceiver.php', 'PonderAnswerPHIDType' => 'applications/ponder/phid/PonderAnswerPHIDType.php', 'PonderAnswerQuery' => 'applications/ponder/query/PonderAnswerQuery.php', 'PonderAnswerReplyHandler' => 'applications/ponder/mail/PonderAnswerReplyHandler.php', 'PonderAnswerSaveController' => 'applications/ponder/controller/PonderAnswerSaveController.php', 'PonderAnswerStatus' => 'applications/ponder/constants/PonderAnswerStatus.php', 'PonderAnswerTransaction' => 'applications/ponder/storage/PonderAnswerTransaction.php', 'PonderAnswerTransactionComment' => 'applications/ponder/storage/PonderAnswerTransactionComment.php', 'PonderAnswerTransactionQuery' => 'applications/ponder/query/PonderAnswerTransactionQuery.php', 'PonderAnswerView' => 'applications/ponder/view/PonderAnswerView.php', 'PonderConstants' => 'applications/ponder/constants/PonderConstants.php', 'PonderController' => 'applications/ponder/controller/PonderController.php', 'PonderDAO' => 'applications/ponder/storage/PonderDAO.php', 'PonderDefaultViewCapability' => 'applications/ponder/capability/PonderDefaultViewCapability.php', 'PonderEditor' => 'applications/ponder/editor/PonderEditor.php', 'PonderFooterView' => 'applications/ponder/view/PonderFooterView.php', 'PonderModerateCapability' => 'applications/ponder/capability/PonderModerateCapability.php', 'PonderQuestion' => 'applications/ponder/storage/PonderQuestion.php', 'PonderQuestionCommentController' => 'applications/ponder/controller/PonderQuestionCommentController.php', 'PonderQuestionCreateMailReceiver' => 'applications/ponder/mail/PonderQuestionCreateMailReceiver.php', 'PonderQuestionEditController' => 'applications/ponder/controller/PonderQuestionEditController.php', 'PonderQuestionEditor' => 'applications/ponder/editor/PonderQuestionEditor.php', 'PonderQuestionFulltextEngine' => 'applications/ponder/search/PonderQuestionFulltextEngine.php', 'PonderQuestionHistoryController' => 'applications/ponder/controller/PonderQuestionHistoryController.php', 'PonderQuestionListController' => 'applications/ponder/controller/PonderQuestionListController.php', 'PonderQuestionMailReceiver' => 'applications/ponder/mail/PonderQuestionMailReceiver.php', 'PonderQuestionPHIDType' => 'applications/ponder/phid/PonderQuestionPHIDType.php', 'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php', 'PonderQuestionReplyHandler' => 'applications/ponder/mail/PonderQuestionReplyHandler.php', 'PonderQuestionSearchEngine' => 'applications/ponder/query/PonderQuestionSearchEngine.php', 'PonderQuestionStatus' => 'applications/ponder/constants/PonderQuestionStatus.php', 'PonderQuestionStatusController' => 'applications/ponder/controller/PonderQuestionStatusController.php', 'PonderQuestionTransaction' => 'applications/ponder/storage/PonderQuestionTransaction.php', 'PonderQuestionTransactionComment' => 'applications/ponder/storage/PonderQuestionTransactionComment.php', 'PonderQuestionTransactionQuery' => 'applications/ponder/query/PonderQuestionTransactionQuery.php', 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php', 'PonderSchemaSpec' => 'applications/ponder/storage/PonderSchemaSpec.php', 'ProjectAddProjectsEmailCommand' => 'applications/project/command/ProjectAddProjectsEmailCommand.php', 'ProjectBoardTaskCard' => 'applications/project/view/ProjectBoardTaskCard.php', 'ProjectCanLockProjectsCapability' => 'applications/project/capability/ProjectCanLockProjectsCapability.php', 'ProjectConduitAPIMethod' => 'applications/project/conduit/ProjectConduitAPIMethod.php', 'ProjectCreateConduitAPIMethod' => 'applications/project/conduit/ProjectCreateConduitAPIMethod.php', 'ProjectCreateProjectsCapability' => 'applications/project/capability/ProjectCreateProjectsCapability.php', 'ProjectDefaultEditCapability' => 'applications/project/capability/ProjectDefaultEditCapability.php', 'ProjectDefaultJoinCapability' => 'applications/project/capability/ProjectDefaultJoinCapability.php', 'ProjectDefaultViewCapability' => 'applications/project/capability/ProjectDefaultViewCapability.php', 'ProjectEditConduitAPIMethod' => 'applications/project/conduit/ProjectEditConduitAPIMethod.php', 'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php', 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 'ProjectRemarkupRuleTestCase' => 'applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php', 'ProjectReplyHandler' => 'applications/project/mail/ProjectReplyHandler.php', 'ProjectSearchConduitAPIMethod' => 'applications/project/conduit/ProjectSearchConduitAPIMethod.php', 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', 'ReleephBranchAccessController' => 'applications/releeph/controller/branch/ReleephBranchAccessController.php', 'ReleephBranchCommitFieldSpecification' => 'applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php', 'ReleephBranchController' => 'applications/releeph/controller/branch/ReleephBranchController.php', 'ReleephBranchCreateController' => 'applications/releeph/controller/branch/ReleephBranchCreateController.php', 'ReleephBranchEditController' => 'applications/releeph/controller/branch/ReleephBranchEditController.php', 'ReleephBranchEditor' => 'applications/releeph/editor/ReleephBranchEditor.php', 'ReleephBranchHistoryController' => 'applications/releeph/controller/branch/ReleephBranchHistoryController.php', 'ReleephBranchNamePreviewController' => 'applications/releeph/controller/branch/ReleephBranchNamePreviewController.php', 'ReleephBranchPHIDType' => 'applications/releeph/phid/ReleephBranchPHIDType.php', 'ReleephBranchPreviewView' => 'applications/releeph/view/branch/ReleephBranchPreviewView.php', 'ReleephBranchQuery' => 'applications/releeph/query/ReleephBranchQuery.php', 'ReleephBranchSearchEngine' => 'applications/releeph/query/ReleephBranchSearchEngine.php', 'ReleephBranchTemplate' => 'applications/releeph/view/branch/ReleephBranchTemplate.php', 'ReleephBranchTransaction' => 'applications/releeph/storage/ReleephBranchTransaction.php', 'ReleephBranchTransactionQuery' => 'applications/releeph/query/ReleephBranchTransactionQuery.php', 'ReleephBranchViewController' => 'applications/releeph/controller/branch/ReleephBranchViewController.php', 'ReleephCommitFinder' => 'applications/releeph/commitfinder/ReleephCommitFinder.php', 'ReleephCommitFinderException' => 'applications/releeph/commitfinder/ReleephCommitFinderException.php', 'ReleephCommitMessageFieldSpecification' => 'applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php', 'ReleephConduitAPIMethod' => 'applications/releeph/conduit/ReleephConduitAPIMethod.php', 'ReleephController' => 'applications/releeph/controller/ReleephController.php', 'ReleephDAO' => 'applications/releeph/storage/ReleephDAO.php', 'ReleephDefaultFieldSelector' => 'applications/releeph/field/selector/ReleephDefaultFieldSelector.php', 'ReleephDependsOnFieldSpecification' => 'applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php', 'ReleephDiffChurnFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php', 'ReleephDiffMessageFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php', 'ReleephDiffSizeFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php', 'ReleephFieldParseException' => 'applications/releeph/field/exception/ReleephFieldParseException.php', 'ReleephFieldSelector' => 'applications/releeph/field/selector/ReleephFieldSelector.php', 'ReleephFieldSpecification' => 'applications/releeph/field/specification/ReleephFieldSpecification.php', 'ReleephGetBranchesConduitAPIMethod' => 'applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php', 'ReleephIntentFieldSpecification' => 'applications/releeph/field/specification/ReleephIntentFieldSpecification.php', 'ReleephLevelFieldSpecification' => 'applications/releeph/field/specification/ReleephLevelFieldSpecification.php', 'ReleephOriginalCommitFieldSpecification' => 'applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php', 'ReleephProductActionController' => 'applications/releeph/controller/product/ReleephProductActionController.php', 'ReleephProductController' => 'applications/releeph/controller/product/ReleephProductController.php', 'ReleephProductCreateController' => 'applications/releeph/controller/product/ReleephProductCreateController.php', 'ReleephProductEditController' => 'applications/releeph/controller/product/ReleephProductEditController.php', 'ReleephProductEditor' => 'applications/releeph/editor/ReleephProductEditor.php', 'ReleephProductHistoryController' => 'applications/releeph/controller/product/ReleephProductHistoryController.php', 'ReleephProductListController' => 'applications/releeph/controller/product/ReleephProductListController.php', 'ReleephProductPHIDType' => 'applications/releeph/phid/ReleephProductPHIDType.php', 'ReleephProductQuery' => 'applications/releeph/query/ReleephProductQuery.php', 'ReleephProductSearchEngine' => 'applications/releeph/query/ReleephProductSearchEngine.php', 'ReleephProductTransaction' => 'applications/releeph/storage/ReleephProductTransaction.php', 'ReleephProductTransactionQuery' => 'applications/releeph/query/ReleephProductTransactionQuery.php', 'ReleephProductViewController' => 'applications/releeph/controller/product/ReleephProductViewController.php', 'ReleephProject' => 'applications/releeph/storage/ReleephProject.php', 'ReleephQueryBranchesConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php', 'ReleephQueryProductsConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php', 'ReleephQueryRequestsConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php', 'ReleephReasonFieldSpecification' => 'applications/releeph/field/specification/ReleephReasonFieldSpecification.php', 'ReleephRequest' => 'applications/releeph/storage/ReleephRequest.php', 'ReleephRequestActionController' => 'applications/releeph/controller/request/ReleephRequestActionController.php', 'ReleephRequestCommentController' => 'applications/releeph/controller/request/ReleephRequestCommentController.php', 'ReleephRequestConduitAPIMethod' => 'applications/releeph/conduit/ReleephRequestConduitAPIMethod.php', 'ReleephRequestController' => 'applications/releeph/controller/request/ReleephRequestController.php', 'ReleephRequestDifferentialCreateController' => 'applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php', 'ReleephRequestEditController' => 'applications/releeph/controller/request/ReleephRequestEditController.php', 'ReleephRequestMailReceiver' => 'applications/releeph/mail/ReleephRequestMailReceiver.php', 'ReleephRequestPHIDType' => 'applications/releeph/phid/ReleephRequestPHIDType.php', 'ReleephRequestQuery' => 'applications/releeph/query/ReleephRequestQuery.php', 'ReleephRequestReplyHandler' => 'applications/releeph/mail/ReleephRequestReplyHandler.php', 'ReleephRequestSearchEngine' => 'applications/releeph/query/ReleephRequestSearchEngine.php', 'ReleephRequestStatus' => 'applications/releeph/constants/ReleephRequestStatus.php', 'ReleephRequestTransaction' => 'applications/releeph/storage/ReleephRequestTransaction.php', 'ReleephRequestTransactionComment' => 'applications/releeph/storage/ReleephRequestTransactionComment.php', 'ReleephRequestTransactionQuery' => 'applications/releeph/query/ReleephRequestTransactionQuery.php', 'ReleephRequestTransactionalEditor' => 'applications/releeph/editor/ReleephRequestTransactionalEditor.php', 'ReleephRequestTypeaheadControl' => 'applications/releeph/view/request/ReleephRequestTypeaheadControl.php', 'ReleephRequestTypeaheadController' => 'applications/releeph/controller/request/ReleephRequestTypeaheadController.php', 'ReleephRequestView' => 'applications/releeph/view/ReleephRequestView.php', 'ReleephRequestViewController' => 'applications/releeph/controller/request/ReleephRequestViewController.php', 'ReleephRequestorFieldSpecification' => 'applications/releeph/field/specification/ReleephRequestorFieldSpecification.php', 'ReleephRevisionFieldSpecification' => 'applications/releeph/field/specification/ReleephRevisionFieldSpecification.php', 'ReleephSeverityFieldSpecification' => 'applications/releeph/field/specification/ReleephSeverityFieldSpecification.php', 'ReleephSummaryFieldSpecification' => 'applications/releeph/field/specification/ReleephSummaryFieldSpecification.php', 'ReleephWorkCanPushConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php', 'ReleephWorkGetAuthorInfoConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php', 'ReleephWorkGetBranchCommitMessageConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php', 'ReleephWorkGetBranchConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php', 'ReleephWorkGetCommitMessageConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php', 'ReleephWorkNextRequestConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php', 'ReleephWorkRecordConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php', 'ReleephWorkRecordPickStatusConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php', 'RemarkupProcessConduitAPIMethod' => 'applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php', 'RepositoryConduitAPIMethod' => 'applications/repository/conduit/RepositoryConduitAPIMethod.php', 'RepositoryQueryConduitAPIMethod' => 'applications/repository/conduit/RepositoryQueryConduitAPIMethod.php', 'ShellLogView' => 'applications/harbormaster/view/ShellLogView.php', 'SlowvoteConduitAPIMethod' => 'applications/slowvote/conduit/SlowvoteConduitAPIMethod.php', 'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php', 'SlowvoteInfoConduitAPIMethod' => 'applications/slowvote/conduit/SlowvoteInfoConduitAPIMethod.php', 'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php', 'SubscriptionListDialogBuilder' => 'applications/subscriptions/view/SubscriptionListDialogBuilder.php', 'SubscriptionListStringBuilder' => 'applications/subscriptions/view/SubscriptionListStringBuilder.php', 'TokenConduitAPIMethod' => 'applications/tokens/conduit/TokenConduitAPIMethod.php', 'TokenGiveConduitAPIMethod' => 'applications/tokens/conduit/TokenGiveConduitAPIMethod.php', 'TokenGivenConduitAPIMethod' => 'applications/tokens/conduit/TokenGivenConduitAPIMethod.php', 'TokenQueryConduitAPIMethod' => 'applications/tokens/conduit/TokenQueryConduitAPIMethod.php', 'UserConduitAPIMethod' => 'applications/people/conduit/UserConduitAPIMethod.php', 'UserDisableConduitAPIMethod' => 'applications/people/conduit/UserDisableConduitAPIMethod.php', 'UserEnableConduitAPIMethod' => 'applications/people/conduit/UserEnableConduitAPIMethod.php', 'UserFindConduitAPIMethod' => 'applications/people/conduit/UserFindConduitAPIMethod.php', 'UserQueryConduitAPIMethod' => 'applications/people/conduit/UserQueryConduitAPIMethod.php', 'UserSearchConduitAPIMethod' => 'applications/people/conduit/UserSearchConduitAPIMethod.php', 'UserWhoAmIConduitAPIMethod' => 'applications/people/conduit/UserWhoAmIConduitAPIMethod.php', ), 'function' => array( 'celerity_generate_unique_node_id' => 'applications/celerity/api.php', 'celerity_get_resource_uri' => 'applications/celerity/api.php', 'javelin_tag' => 'infrastructure/javelin/markup.php', 'phabricator_date' => 'view/viewutils.php', 'phabricator_datetime' => 'view/viewutils.php', 'phabricator_form' => 'infrastructure/javelin/markup.php', 'phabricator_format_local_time' => 'view/viewutils.php', 'phabricator_relative_date' => 'view/viewutils.php', 'phabricator_time' => 'view/viewutils.php', 'phid_get_subtype' => 'applications/phid/utils.php', 'phid_get_type' => 'applications/phid/utils.php', 'phid_group_by_type' => 'applications/phid/utils.php', 'require_celerity_resource' => 'applications/celerity/api.php', ), 'xmap' => array( 'AlmanacAddress' => 'Phobject', 'AlmanacBinding' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'AlmanacPropertyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorExtendedPolicyInterface', ), 'AlmanacBindingDisableController' => 'AlmanacServiceController', 'AlmanacBindingEditController' => 'AlmanacServiceController', 'AlmanacBindingEditor' => 'AlmanacEditor', 'AlmanacBindingPHIDType' => 'PhabricatorPHIDType', 'AlmanacBindingPropertyEditEngine' => 'AlmanacPropertyEditEngine', 'AlmanacBindingQuery' => 'AlmanacQuery', 'AlmanacBindingTableView' => 'AphrontView', 'AlmanacBindingTransaction' => 'AlmanacTransaction', 'AlmanacBindingTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacBindingViewController' => 'AlmanacServiceController', 'AlmanacBindingsSearchEngineAttachment' => 'AlmanacSearchEngineAttachment', 'AlmanacClusterDatabaseServiceType' => 'AlmanacClusterServiceType', 'AlmanacClusterRepositoryServiceType' => 'AlmanacClusterServiceType', 'AlmanacClusterServiceType' => 'AlmanacServiceType', 'AlmanacConsoleController' => 'AlmanacController', 'AlmanacController' => 'PhabricatorController', 'AlmanacCreateDevicesCapability' => 'PhabricatorPolicyCapability', 'AlmanacCreateNamespacesCapability' => 'PhabricatorPolicyCapability', 'AlmanacCreateNetworksCapability' => 'PhabricatorPolicyCapability', 'AlmanacCreateServicesCapability' => 'PhabricatorPolicyCapability', 'AlmanacCustomServiceType' => 'AlmanacServiceType', 'AlmanacDAO' => 'PhabricatorLiskDAO', 'AlmanacDevice' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', 'PhabricatorSSHPublicKeyInterface', 'AlmanacPropertyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorNgramsInterface', 'PhabricatorConduitResultInterface', 'PhabricatorExtendedPolicyInterface', ), 'AlmanacDeviceController' => 'AlmanacController', 'AlmanacDeviceEditController' => 'AlmanacDeviceController', 'AlmanacDeviceEditEngine' => 'PhabricatorEditEngine', 'AlmanacDeviceEditor' => 'AlmanacEditor', 'AlmanacDeviceListController' => 'AlmanacDeviceController', 'AlmanacDeviceNameNgrams' => 'PhabricatorSearchNgrams', 'AlmanacDevicePHIDType' => 'PhabricatorPHIDType', 'AlmanacDevicePropertyEditEngine' => 'AlmanacPropertyEditEngine', 'AlmanacDeviceQuery' => 'AlmanacQuery', 'AlmanacDeviceSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacDeviceTransaction' => 'AlmanacTransaction', 'AlmanacDeviceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacDeviceViewController' => 'AlmanacDeviceController', 'AlmanacDrydockPoolServiceType' => 'AlmanacServiceType', 'AlmanacEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacInterface' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorExtendedPolicyInterface', ), 'AlmanacInterfaceDatasource' => 'PhabricatorTypeaheadDatasource', 'AlmanacInterfaceDeleteController' => 'AlmanacDeviceController', 'AlmanacInterfaceEditController' => 'AlmanacDeviceController', 'AlmanacInterfacePHIDType' => 'PhabricatorPHIDType', 'AlmanacInterfaceQuery' => 'AlmanacQuery', 'AlmanacInterfaceTableView' => 'AphrontView', 'AlmanacKeys' => 'Phobject', 'AlmanacManageClusterServicesCapability' => 'PhabricatorPolicyCapability', 'AlmanacManagementRegisterWorkflow' => 'AlmanacManagementWorkflow', 'AlmanacManagementTrustKeyWorkflow' => 'AlmanacManagementWorkflow', 'AlmanacManagementUntrustKeyWorkflow' => 'AlmanacManagementWorkflow', 'AlmanacManagementWorkflow' => 'PhabricatorManagementWorkflow', 'AlmanacNames' => 'Phobject', 'AlmanacNamesTestCase' => 'PhabricatorTestCase', 'AlmanacNamespace' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', 'AlmanacPropertyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorNgramsInterface', ), 'AlmanacNamespaceController' => 'AlmanacController', 'AlmanacNamespaceEditController' => 'AlmanacNamespaceController', 'AlmanacNamespaceEditEngine' => 'PhabricatorEditEngine', 'AlmanacNamespaceEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacNamespaceListController' => 'AlmanacNamespaceController', 'AlmanacNamespaceNameNgrams' => 'PhabricatorSearchNgrams', 'AlmanacNamespacePHIDType' => 'PhabricatorPHIDType', 'AlmanacNamespaceQuery' => 'AlmanacQuery', 'AlmanacNamespaceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacNamespaceTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacNamespaceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacNamespaceViewController' => 'AlmanacNamespaceController', 'AlmanacNetwork' => array( 'AlmanacDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorNgramsInterface', ), 'AlmanacNetworkController' => 'AlmanacController', 'AlmanacNetworkEditController' => 'AlmanacNetworkController', 'AlmanacNetworkEditEngine' => 'PhabricatorEditEngine', 'AlmanacNetworkEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacNetworkListController' => 'AlmanacNetworkController', 'AlmanacNetworkNameNgrams' => 'PhabricatorSearchNgrams', 'AlmanacNetworkPHIDType' => 'PhabricatorPHIDType', 'AlmanacNetworkQuery' => 'AlmanacQuery', 'AlmanacNetworkSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacNetworkTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacNetworkTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacNetworkViewController' => 'AlmanacNetworkController', 'AlmanacPropertiesDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'AlmanacPropertiesSearchEngineAttachment' => 'AlmanacSearchEngineAttachment', 'AlmanacProperty' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', ), 'AlmanacPropertyController' => 'AlmanacController', 'AlmanacPropertyDeleteController' => 'AlmanacPropertyController', 'AlmanacPropertyEditController' => 'AlmanacPropertyController', 'AlmanacPropertyEditEngine' => 'PhabricatorEditEngine', 'AlmanacPropertyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'AlmanacQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'AlmanacSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'AlmanacSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'AlmanacService' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', 'AlmanacPropertyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorNgramsInterface', 'PhabricatorConduitResultInterface', 'PhabricatorExtendedPolicyInterface', ), 'AlmanacServiceController' => 'AlmanacController', 'AlmanacServiceDatasource' => 'PhabricatorTypeaheadDatasource', 'AlmanacServiceEditController' => 'AlmanacServiceController', 'AlmanacServiceEditEngine' => 'PhabricatorEditEngine', 'AlmanacServiceEditor' => 'AlmanacEditor', 'AlmanacServiceListController' => 'AlmanacServiceController', 'AlmanacServiceNameNgrams' => 'PhabricatorSearchNgrams', 'AlmanacServicePHIDType' => 'PhabricatorPHIDType', 'AlmanacServicePropertyEditEngine' => 'AlmanacPropertyEditEngine', 'AlmanacServiceQuery' => 'AlmanacQuery', 'AlmanacServiceSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'AlmanacServiceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacServiceTransaction' => 'AlmanacTransaction', 'AlmanacServiceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacServiceType' => 'Phobject', 'AlmanacServiceTypeDatasource' => 'PhabricatorTypeaheadDatasource', 'AlmanacServiceTypeTestCase' => 'PhabricatorTestCase', 'AlmanacServiceViewController' => 'AlmanacServiceController', 'AlmanacTransaction' => 'PhabricatorApplicationTransaction', 'AphlictDropdownDataQuery' => 'Phobject', 'Aphront304Response' => 'AphrontResponse', 'Aphront400Response' => 'AphrontResponse', 'Aphront403Response' => 'AphrontHTMLResponse', 'Aphront404Response' => 'AphrontHTMLResponse', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontApplicationConfiguration' => 'Phobject', 'AphrontBarView' => 'AphrontView', 'AphrontBoolHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontCalendarEventView' => 'AphrontView', 'AphrontController' => 'Phobject', 'AphrontCursorPagerView' => 'AphrontView', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => array( 'AphrontView', 'AphrontResponseProducerInterface', ), 'AphrontEpochHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontException' => 'Exception', + 'AphrontFileHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormCheckboxControl' => 'AphrontFormControl', 'AphrontFormControl' => 'AphrontView', 'AphrontFormDateControl' => 'AphrontFormControl', 'AphrontFormDateControlValue' => 'Phobject', 'AphrontFormDividerControl' => 'AphrontFormControl', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormHandlesControl' => 'AphrontFormControl', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormPasswordControl' => 'AphrontFormControl', 'AphrontFormPolicyControl' => 'AphrontFormControl', 'AphrontFormRadioButtonControl' => 'AphrontFormControl', 'AphrontFormRecaptchaControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormTextWithSubmitControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormTypeaheadControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontGlyphBarView' => 'AphrontBarView', 'AphrontHTMLResponse' => 'AphrontResponse', 'AphrontHTTPParameterType' => 'Phobject', 'AphrontHTTPProxyResponse' => 'AphrontResponse', 'AphrontHTTPSink' => 'Phobject', 'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase', 'AphrontIntHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink', 'AphrontJSONResponse' => 'AphrontResponse', 'AphrontJavelinView' => 'AphrontView', 'AphrontKeyboardShortcutsAvailableView' => 'AphrontView', 'AphrontListFilterView' => 'AphrontView', 'AphrontListHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontMalformedRequestException' => 'AphrontException', 'AphrontMoreView' => 'AphrontView', 'AphrontMultiColumnView' => 'AphrontView', 'AphrontMySQLDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontNullView' => 'AphrontView', 'AphrontPHIDHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontPHIDListHTTPParameterType' => 'AphrontListHTTPParameterType', 'AphrontPHPHTTPSink' => 'AphrontHTTPSink', 'AphrontPageView' => 'AphrontView', 'AphrontPlainTextResponse' => 'AphrontResponse', 'AphrontProgressBarView' => 'AphrontBarView', 'AphrontProjectListHTTPParameterType' => 'AphrontListHTTPParameterType', 'AphrontProxyResponse' => array( 'AphrontResponse', 'AphrontResponseProducerInterface', ), 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontRedirectResponseTestCase' => 'PhabricatorTestCase', 'AphrontReloadResponse' => 'AphrontRedirectResponse', 'AphrontRequest' => 'Phobject', 'AphrontRequestExceptionHandler' => 'Phobject', 'AphrontRequestTestCase' => 'PhabricatorTestCase', 'AphrontResponse' => 'Phobject', 'AphrontRoutingMap' => 'Phobject', 'AphrontRoutingResult' => 'Phobject', 'AphrontSelectHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontSideNavFilterView' => 'AphrontView', 'AphrontSite' => 'Phobject', 'AphrontStackTraceView' => 'AphrontView', 'AphrontStandaloneHTMLResponse' => 'AphrontHTMLResponse', 'AphrontStringHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontStringListHTTPParameterType' => 'AphrontListHTTPParameterType', 'AphrontTableView' => 'AphrontView', 'AphrontTagView' => 'AphrontView', 'AphrontTokenizerTemplateView' => 'AphrontView', 'AphrontTypeaheadTemplateView' => 'AphrontView', 'AphrontUnhandledExceptionResponse' => 'AphrontStandaloneHTMLResponse', 'AphrontUserListHTTPParameterType' => 'AphrontListHTTPParameterType', 'AphrontView' => array( 'Phobject', 'PhutilSafeHTMLProducerInterface', ), 'AphrontWebpageResponse' => 'AphrontHTMLResponse', 'ArcanistConduitAPIMethod' => 'ConduitAPIMethod', 'AuditConduitAPIMethod' => 'ConduitAPIMethod', 'AuditQueryConduitAPIMethod' => 'AuditConduitAPIMethod', 'AuthManageProvidersCapability' => 'PhabricatorPolicyCapability', 'CalendarTimeUtil' => 'Phobject', 'CalendarTimeUtilTestCase' => 'PhabricatorTestCase', 'CelerityAPI' => 'Phobject', 'CelerityDefaultPostprocessor' => 'CelerityPostprocessor', 'CelerityHighContrastPostprocessor' => 'CelerityPostprocessor', 'CelerityLargeFontPostprocessor' => 'CelerityPostprocessor', 'CelerityManagementMapWorkflow' => 'CelerityManagementWorkflow', 'CelerityManagementSyntaxWorkflow' => 'CelerityManagementWorkflow', 'CelerityManagementWorkflow' => 'PhabricatorManagementWorkflow', 'CelerityPhabricatorResourceController' => 'CelerityResourceController', 'CelerityPhabricatorResources' => 'CelerityResourcesOnDisk', 'CelerityPhysicalResources' => 'CelerityResources', 'CelerityPhysicalResourcesTestCase' => 'PhabricatorTestCase', 'CelerityPostprocessor' => 'Phobject', 'CelerityPostprocessorTestCase' => 'PhabricatorTestCase', 'CelerityResourceController' => 'PhabricatorController', 'CelerityResourceGraph' => 'AbstractDirectedGraph', 'CelerityResourceMap' => 'Phobject', 'CelerityResourceMapGenerator' => 'Phobject', 'CelerityResourceTransformer' => 'Phobject', 'CelerityResourceTransformerTestCase' => 'PhabricatorTestCase', 'CelerityResources' => 'Phobject', 'CelerityResourcesOnDisk' => 'CelerityPhysicalResources', 'CeleritySpriteGenerator' => 'Phobject', 'CelerityStaticResourceResponse' => 'Phobject', 'ChatLogConduitAPIMethod' => 'ConduitAPIMethod', 'ChatLogQueryConduitAPIMethod' => 'ChatLogConduitAPIMethod', 'ChatLogRecordConduitAPIMethod' => 'ChatLogConduitAPIMethod', 'ConduitAPIMethod' => array( 'Phobject', 'PhabricatorPolicyInterface', ), 'ConduitAPIMethodTestCase' => 'PhabricatorTestCase', 'ConduitAPIRequest' => 'Phobject', 'ConduitAPIResponse' => 'Phobject', 'ConduitApplicationNotInstalledException' => 'ConduitMethodNotFoundException', 'ConduitBoolParameterType' => 'ConduitParameterType', 'ConduitCall' => 'Phobject', 'ConduitCallTestCase' => 'PhabricatorTestCase', 'ConduitColumnsParameterType' => 'ConduitParameterType', 'ConduitConnectConduitAPIMethod' => 'ConduitAPIMethod', 'ConduitEpochParameterType' => 'ConduitParameterType', 'ConduitException' => 'Exception', 'ConduitGetCapabilitiesConduitAPIMethod' => 'ConduitAPIMethod', 'ConduitGetCertificateConduitAPIMethod' => 'ConduitAPIMethod', 'ConduitIntListParameterType' => 'ConduitListParameterType', 'ConduitIntParameterType' => 'ConduitParameterType', 'ConduitListParameterType' => 'ConduitParameterType', 'ConduitLogGarbageCollector' => 'PhabricatorGarbageCollector', 'ConduitMethodDoesNotExistException' => 'ConduitMethodNotFoundException', 'ConduitMethodNotFoundException' => 'ConduitException', 'ConduitPHIDListParameterType' => 'ConduitListParameterType', 'ConduitPHIDParameterType' => 'ConduitParameterType', 'ConduitParameterType' => 'Phobject', 'ConduitPingConduitAPIMethod' => 'ConduitAPIMethod', 'ConduitPointsParameterType' => 'ConduitParameterType', 'ConduitProjectListParameterType' => 'ConduitListParameterType', 'ConduitQueryConduitAPIMethod' => 'ConduitAPIMethod', 'ConduitResultSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'ConduitSSHWorkflow' => 'PhabricatorSSHWorkflow', 'ConduitStringListParameterType' => 'ConduitListParameterType', 'ConduitStringParameterType' => 'ConduitParameterType', 'ConduitTokenGarbageCollector' => 'PhabricatorGarbageCollector', 'ConduitUserListParameterType' => 'ConduitListParameterType', 'ConduitUserParameterType' => 'ConduitParameterType', 'ConduitWildParameterType' => 'ConduitParameterType', 'ConpherenceColumnViewController' => 'ConpherenceController', 'ConpherenceConduitAPIMethod' => 'ConduitAPIMethod', 'ConpherenceConfigOptions' => 'PhabricatorApplicationConfigOptions', 'ConpherenceConstants' => 'Phobject', 'ConpherenceController' => 'PhabricatorController', 'ConpherenceCreateThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceDAO' => 'PhabricatorLiskDAO', 'ConpherenceDurableColumnView' => 'AphrontTagView', 'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor', - 'ConpherenceFormDragAndDropUploadControl' => 'AphrontFormControl', 'ConpherenceFulltextQuery' => 'PhabricatorOffsetPagedQuery', 'ConpherenceIndex' => 'ConpherenceDAO', 'ConpherenceLayoutView' => 'AphrontTagView', 'ConpherenceListController' => 'ConpherenceController', 'ConpherenceMenuItemView' => 'AphrontTagView', 'ConpherenceNewRoomController' => 'ConpherenceController', 'ConpherenceNotificationPanelController' => 'ConpherenceController', 'ConpherenceParticipant' => 'ConpherenceDAO', 'ConpherenceParticipantController' => 'ConpherenceController', 'ConpherenceParticipantCountQuery' => 'PhabricatorOffsetPagedQuery', 'ConpherenceParticipantQuery' => 'PhabricatorOffsetPagedQuery', 'ConpherenceParticipantView' => 'AphrontView', 'ConpherenceParticipationStatus' => 'ConpherenceConstants', 'ConpherenceQueryThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceQueryTransactionConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceReplyHandler' => 'PhabricatorMailReplyHandler', 'ConpherenceRoomListController' => 'ConpherenceController', 'ConpherenceRoomPictureController' => 'ConpherenceController', 'ConpherenceRoomTestCase' => 'ConpherenceTestCase', 'ConpherenceSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'ConpherenceTestCase' => 'PhabricatorTestCase', 'ConpherenceThread' => array( 'ConpherenceDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorMentionableInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorNgramsInterface', ), + 'ConpherenceThreadDatasource' => 'PhabricatorTypeaheadDatasource', 'ConpherenceThreadIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 'ConpherenceThreadListView' => 'AphrontView', 'ConpherenceThreadMailReceiver' => 'PhabricatorObjectMailReceiver', 'ConpherenceThreadMembersPolicyRule' => 'PhabricatorPolicyRule', 'ConpherenceThreadQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ConpherenceThreadRemarkupRule' => 'PhabricatorObjectRemarkupRule', + 'ConpherenceThreadSearchController' => 'ConpherenceController', 'ConpherenceThreadSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'ConpherenceThreadTitleNgrams' => 'PhabricatorSearchNgrams', 'ConpherenceTransaction' => 'PhabricatorApplicationTransaction', 'ConpherenceTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ConpherenceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ConpherenceTransactionRenderer' => 'Phobject', 'ConpherenceTransactionView' => 'AphrontView', 'ConpherenceUpdateActions' => 'ConpherenceConstants', 'ConpherenceUpdateController' => 'ConpherenceController', 'ConpherenceUpdateThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceViewController' => 'ConpherenceController', 'DarkConsoleController' => 'PhabricatorController', 'DarkConsoleCore' => 'Phobject', 'DarkConsoleDataController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', 'DarkConsoleErrorLogPluginAPI' => 'Phobject', 'DarkConsoleEventPlugin' => 'DarkConsolePlugin', 'DarkConsoleEventPluginAPI' => 'PhabricatorEventListener', 'DarkConsolePlugin' => 'Phobject', 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleStartupPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPluginAPI' => 'Phobject', 'DefaultDatabaseConfigurationProvider' => array( 'Phobject', 'DatabaseConfigurationProvider', ), 'DifferentialAction' => 'Phobject', 'DifferentialActionEmailCommand' => 'MetaMTAEmailTransactionCommand', 'DifferentialAddCommentView' => 'AphrontView', 'DifferentialAdjustmentMapTestCase' => 'PhutilTestCase', 'DifferentialAffectedPath' => 'DifferentialDAO', 'DifferentialApplyPatchField' => 'DifferentialCustomField', 'DifferentialAsanaRepresentationField' => 'DifferentialCustomField', 'DifferentialAuditorsField' => 'DifferentialStoredCustomField', 'DifferentialAuthorField' => 'DifferentialCustomField', 'DifferentialBlameRevisionField' => 'DifferentialStoredCustomField', 'DifferentialBlockHeraldAction' => 'HeraldAction', 'DifferentialBlockingReviewerDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DifferentialBranchField' => 'DifferentialCustomField', 'DifferentialChangeDetailMailView' => 'DifferentialMailView', 'DifferentialChangeHeraldFieldGroup' => 'HeraldFieldGroup', 'DifferentialChangeType' => 'Phobject', 'DifferentialChangesSinceLastUpdateField' => 'DifferentialCustomField', 'DifferentialChangeset' => array( 'DifferentialDAO', 'PhabricatorPolicyInterface', ), 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetFileTreeSideNavBuilder' => 'Phobject', 'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetOneUpMailRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetOneUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetOneUpTestRenderer' => 'DifferentialChangesetTestRenderer', 'DifferentialChangesetParser' => 'Phobject', 'DifferentialChangesetParserTestCase' => 'PhabricatorTestCase', 'DifferentialChangesetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialChangesetRenderer' => 'Phobject', 'DifferentialChangesetTestRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetTwoUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetTwoUpTestRenderer' => 'DifferentialChangesetTestRenderer', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialChildRevisionsField' => 'DifferentialCustomField', 'DifferentialCloseConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialCommitMessageParser' => 'Phobject', 'DifferentialCommitMessageParserTestCase' => 'PhabricatorTestCase', 'DifferentialCommitsField' => 'DifferentialCustomField', 'DifferentialConduitAPIMethod' => 'ConduitAPIMethod', 'DifferentialConflictsField' => 'DifferentialCustomField', 'DifferentialController' => 'PhabricatorController', 'DifferentialCoreCustomField' => 'DifferentialCustomField', 'DifferentialCreateCommentConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialCreateDiffConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialCreateInlineConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialCreateMailReceiver' => 'PhabricatorMailReceiver', 'DifferentialCreateRawDiffConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialCreateRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialCustomField' => 'PhabricatorCustomField', 'DifferentialCustomFieldDependsOnParser' => 'PhabricatorCustomFieldMonogramParser', 'DifferentialCustomFieldDependsOnParserTestCase' => 'PhabricatorTestCase', 'DifferentialCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'DifferentialCustomFieldRevertsParser' => 'PhabricatorCustomFieldMonogramParser', 'DifferentialCustomFieldRevertsParserTestCase' => 'PhabricatorTestCase', 'DifferentialCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'DifferentialCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDefaultViewCapability' => 'PhabricatorPolicyCapability', 'DifferentialDiff' => array( 'DifferentialDAO', 'PhabricatorPolicyInterface', 'HarbormasterBuildableInterface', 'HarbormasterCircleCIBuildableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), 'DifferentialDiffAffectedFilesHeraldField' => 'DifferentialDiffHeraldField', 'DifferentialDiffAuthorHeraldField' => 'DifferentialDiffHeraldField', 'DifferentialDiffAuthorProjectsHeraldField' => 'DifferentialDiffHeraldField', 'DifferentialDiffContentAddedHeraldField' => 'DifferentialDiffHeraldField', 'DifferentialDiffContentHeraldField' => 'DifferentialDiffHeraldField', 'DifferentialDiffContentRemovedHeraldField' => 'DifferentialDiffHeraldField', 'DifferentialDiffCreateController' => 'DifferentialController', 'DifferentialDiffEditor' => 'PhabricatorApplicationTransactionEditor', 'DifferentialDiffExtractionEngine' => 'Phobject', 'DifferentialDiffHeraldField' => 'HeraldField', 'DifferentialDiffHeraldFieldGroup' => 'HeraldFieldGroup', 'DifferentialDiffInlineCommentQuery' => 'PhabricatorDiffInlineCommentQuery', 'DifferentialDiffPHIDType' => 'PhabricatorPHIDType', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialDiffRepositoryHeraldField' => 'DifferentialDiffHeraldField', 'DifferentialDiffRepositoryProjectsHeraldField' => 'DifferentialDiffHeraldField', 'DifferentialDiffTestCase' => 'PhutilTestCase', 'DifferentialDiffTransaction' => 'PhabricatorApplicationTransaction', 'DifferentialDiffTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher', 'DifferentialDraft' => 'DifferentialDAO', 'DifferentialEditPolicyField' => 'DifferentialCoreCustomField', 'DifferentialExactUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DifferentialFieldParseException' => 'Exception', 'DifferentialFieldValidationException' => 'Exception', 'DifferentialFindConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetAllDiffsConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetCommitMessageConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetCommitPathsConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetDiffConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetRawDiffConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetRevisionCommentsConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetWorkingCopy' => 'Phobject', 'DifferentialGitHubLandingStrategy' => 'DifferentialLandingStrategy', 'DifferentialGitSVNIDField' => 'DifferentialCustomField', 'DifferentialHarbormasterField' => 'DifferentialCustomField', 'DifferentialHiddenComment' => 'DifferentialDAO', 'DifferentialHostField' => 'DifferentialCustomField', 'DifferentialHostedGitLandingStrategy' => 'DifferentialLandingStrategy', 'DifferentialHostedMercurialLandingStrategy' => 'DifferentialLandingStrategy', 'DifferentialHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', 'DifferentialHunk' => array( 'DifferentialDAO', 'PhabricatorPolicyInterface', ), 'DifferentialHunkParser' => 'Phobject', 'DifferentialHunkParserTestCase' => 'PhabricatorTestCase', 'DifferentialHunkQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialHunkTestCase' => 'PhutilTestCase', 'DifferentialInlineComment' => array( 'Phobject', 'PhabricatorInlineCommentInterface', ), 'DifferentialInlineCommentEditController' => 'PhabricatorInlineCommentController', 'DifferentialInlineCommentMailView' => 'DifferentialMailView', 'DifferentialInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController', 'DifferentialInlineCommentQuery' => 'PhabricatorOffsetPagedQuery', 'DifferentialJIRAIssuesField' => 'DifferentialStoredCustomField', 'DifferentialLandingActionMenuEventListener' => 'PhabricatorEventListener', 'DifferentialLandingStrategy' => 'Phobject', 'DifferentialLegacyHunk' => 'DifferentialHunk', 'DifferentialLineAdjustmentMap' => 'Phobject', 'DifferentialLintField' => 'DifferentialHarbormasterField', 'DifferentialLintStatus' => 'Phobject', 'DifferentialLocalCommitsView' => 'AphrontView', 'DifferentialMailView' => 'Phobject', 'DifferentialManiphestTasksField' => 'DifferentialCoreCustomField', 'DifferentialModernHunk' => 'DifferentialHunk', 'DifferentialNextStepField' => 'DifferentialCustomField', 'DifferentialParentRevisionsField' => 'DifferentialCustomField', 'DifferentialParseCacheGarbageCollector' => 'PhabricatorGarbageCollector', 'DifferentialParseCommitMessageConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialParseRenderTestCase' => 'PhabricatorTestCase', 'DifferentialPathField' => 'DifferentialCustomField', 'DifferentialProjectReviewersField' => 'DifferentialCustomField', 'DifferentialProjectsField' => 'DifferentialCoreCustomField', 'DifferentialQueryConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialQueryDiffsConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialRawDiffRenderer' => 'Phobject', 'DifferentialReleephRequestFieldSpecification' => 'Phobject', 'DifferentialRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DifferentialReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'DifferentialRepositoryDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DifferentialRepositoryField' => 'DifferentialCoreCustomField', 'DifferentialRepositoryLookup' => 'Phobject', 'DifferentialRequiredSignaturesField' => 'DifferentialCoreCustomField', 'DifferentialResponsibleDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DifferentialResponsibleUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DifferentialResponsibleViewerFunctionDatasource' => 'PhabricatorTypeaheadDatasource', 'DifferentialRevertPlanField' => 'DifferentialStoredCustomField', 'DifferentialReviewedByField' => 'DifferentialCoreCustomField', 'DifferentialReviewer' => 'Phobject', 'DifferentialReviewerDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DifferentialReviewerForRevisionEdgeType' => 'PhabricatorEdgeType', 'DifferentialReviewerStatus' => 'Phobject', 'DifferentialReviewersAddBlockingReviewersHeraldAction' => 'DifferentialReviewersHeraldAction', 'DifferentialReviewersAddBlockingSelfHeraldAction' => 'DifferentialReviewersHeraldAction', 'DifferentialReviewersAddReviewersHeraldAction' => 'DifferentialReviewersHeraldAction', 'DifferentialReviewersAddSelfHeraldAction' => 'DifferentialReviewersHeraldAction', 'DifferentialReviewersField' => 'DifferentialCoreCustomField', 'DifferentialReviewersHeraldAction' => 'HeraldAction', 'DifferentialReviewersView' => 'AphrontView', 'DifferentialRevision' => array( 'DifferentialDAO', 'PhabricatorTokenReceiverInterface', 'PhabricatorPolicyInterface', 'PhabricatorExtendedPolicyInterface', 'PhabricatorFlaggableInterface', 'PhrequentTrackableInterface', 'HarbormasterBuildableInterface', 'PhabricatorSubscribableInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorMentionableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorProjectInterface', 'PhabricatorFulltextInterface', 'PhabricatorConduitResultInterface', ), 'DifferentialRevisionAffectedFilesHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionAuthorHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionAuthorProjectsHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionCloseDetailsController' => 'DifferentialController', 'DifferentialRevisionContentAddedHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionContentHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionContentRemovedHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionControlSystem' => 'Phobject', 'DifferentialRevisionDependedOnByRevisionEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionDependsOnRevisionEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionFulltextEngine' => 'PhabricatorFulltextEngine', 'DifferentialRevisionGraph' => 'PhabricatorObjectGraph', 'DifferentialRevisionHasChildRelationship' => 'DifferentialRevisionRelationship', 'DifferentialRevisionHasCommitEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionHasCommitRelationship' => 'DifferentialRevisionRelationship', 'DifferentialRevisionHasParentRelationship' => 'DifferentialRevisionRelationship', 'DifferentialRevisionHasReviewerEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionHasTaskEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionHasTaskRelationship' => 'DifferentialRevisionRelationship', 'DifferentialRevisionHeraldField' => 'HeraldField', 'DifferentialRevisionHeraldFieldGroup' => 'HeraldFieldGroup', 'DifferentialRevisionIDField' => 'DifferentialCustomField', 'DifferentialRevisionLandController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionListView' => 'AphrontView', 'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver', 'DifferentialRevisionOperationController' => 'DifferentialController', 'DifferentialRevisionPHIDType' => 'PhabricatorPHIDType', 'DifferentialRevisionPackageHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionPackageOwnerHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialRevisionRelationship' => 'PhabricatorObjectRelationship', 'DifferentialRevisionRelationshipSource' => 'PhabricatorObjectRelationshipSource', 'DifferentialRevisionRepositoryHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionRepositoryProjectsHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionRequiredActionResultBucket' => 'DifferentialRevisionResultBucket', 'DifferentialRevisionResultBucket' => 'PhabricatorSearchResultBucket', 'DifferentialRevisionReviewersHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'DifferentialRevisionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DifferentialRevisionStatus' => 'Phobject', 'DifferentialRevisionSummaryHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionTitleHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'DifferentialSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'DifferentialSetDiffPropertyConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialStoredCustomField' => 'DifferentialCustomField', 'DifferentialSubscribersField' => 'DifferentialCoreCustomField', 'DifferentialSummaryField' => 'DifferentialCoreCustomField', 'DifferentialTestPlanField' => 'DifferentialCoreCustomField', 'DifferentialTitleField' => 'DifferentialCoreCustomField', 'DifferentialTransaction' => 'PhabricatorApplicationTransaction', 'DifferentialTransactionComment' => 'PhabricatorApplicationTransactionComment', 'DifferentialTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'DifferentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DifferentialTransactionView' => 'PhabricatorApplicationTransactionView', 'DifferentialUnitField' => 'DifferentialCustomField', 'DifferentialUnitStatus' => 'Phobject', 'DifferentialUnitTestResult' => 'Phobject', 'DifferentialUpdateRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialViewPolicyField' => 'DifferentialCoreCustomField', 'DiffusionAuditorDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DiffusionAuditorFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DiffusionAuditorsAddAuditorsHeraldAction' => 'DiffusionAuditorsHeraldAction', 'DiffusionAuditorsAddSelfHeraldAction' => 'DiffusionAuditorsHeraldAction', 'DiffusionAuditorsHeraldAction' => 'HeraldAction', 'DiffusionBlameConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionBlameQuery' => 'DiffusionQuery', 'DiffusionBlockHeraldAction' => 'HeraldAction', 'DiffusionBranchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionBranchTableController' => 'DiffusionController', 'DiffusionBranchTableView' => 'DiffusionView', 'DiffusionBrowseController' => 'DiffusionController', 'DiffusionBrowseQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionBrowseResultSet' => 'Phobject', 'DiffusionBrowseTableView' => 'DiffusionView', 'DiffusionCachedResolveRefsQuery' => 'DiffusionLowLevelQuery', 'DiffusionChangeController' => 'DiffusionController', 'DiffusionChangeHeraldFieldGroup' => 'HeraldFieldGroup', 'DiffusionCloneURIView' => 'AphrontView', 'DiffusionCommandEngine' => 'Phobject', 'DiffusionCommandEngineTestCase' => 'PhabricatorTestCase', 'DiffusionCommitAffectedFilesHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAuthorHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAutocloseHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitBranchesController' => 'DiffusionController', 'DiffusionCommitBranchesHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitCommitterHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitController' => 'DiffusionController', 'DiffusionCommitDiffContentAddedHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitDiffContentHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitDiffContentRemovedHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitDiffEnormousHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitEditController' => 'DiffusionController', 'DiffusionCommitFulltextEngine' => 'PhabricatorFulltextEngine', 'DiffusionCommitHasRevisionEdgeType' => 'PhabricatorEdgeType', 'DiffusionCommitHasRevisionRelationship' => 'DiffusionCommitRelationship', 'DiffusionCommitHasTaskEdgeType' => 'PhabricatorEdgeType', 'DiffusionCommitHasTaskRelationship' => 'DiffusionCommitRelationship', 'DiffusionCommitHash' => 'Phobject', 'DiffusionCommitHeraldField' => 'HeraldField', 'DiffusionCommitHeraldFieldGroup' => 'HeraldFieldGroup', 'DiffusionCommitHintQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DiffusionCommitHookEngine' => 'Phobject', 'DiffusionCommitHookRejectException' => 'Exception', 'DiffusionCommitMergeHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitMessageHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitPackageAuditHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitPackageHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitPackageOwnerHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitParentsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionCommitQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DiffusionCommitRef' => 'Phobject', 'DiffusionCommitRelationship' => 'PhabricatorObjectRelationship', 'DiffusionCommitRelationshipSource' => 'PhabricatorObjectRelationshipSource', 'DiffusionCommitRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionCommitRemarkupRuleTestCase' => 'PhabricatorTestCase', 'DiffusionCommitRepositoryHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitRepositoryProjectsHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitRevertedByCommitEdgeType' => 'PhabricatorEdgeType', 'DiffusionCommitRevertsCommitEdgeType' => 'PhabricatorEdgeType', 'DiffusionCommitReviewerHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitRevisionAcceptedHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitRevisionHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitRevisionReviewersHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitRevisionSubscribersHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitTagsController' => 'DiffusionController', 'DiffusionConduitAPIMethod' => 'ConduitAPIMethod', 'DiffusionController' => 'PhabricatorController', 'DiffusionCreateCommentConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionCreateRepositoriesCapability' => 'PhabricatorPolicyCapability', 'DiffusionDaemonLockException' => 'Exception', 'DiffusionDefaultEditCapability' => 'PhabricatorPolicyCapability', 'DiffusionDefaultPushCapability' => 'PhabricatorPolicyCapability', 'DiffusionDefaultViewCapability' => 'PhabricatorPolicyCapability', 'DiffusionDiffController' => 'DiffusionController', 'DiffusionDiffInlineCommentQuery' => 'PhabricatorDiffInlineCommentQuery', 'DiffusionDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher', 'DiffusionEmptyResultView' => 'DiffusionView', 'DiffusionExistsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionExternalController' => 'DiffusionController', 'DiffusionExternalSymbolQuery' => 'Phobject', 'DiffusionExternalSymbolsSource' => 'Phobject', 'DiffusionFileContentQuery' => 'DiffusionFileFutureQuery', 'DiffusionFileContentQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionFileFutureQuery' => 'DiffusionQuery', 'DiffusionFindSymbolsConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionGetLintMessagesConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionGetRecentCommitsByPathConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionGitBlameQuery' => 'DiffusionBlameQuery', 'DiffusionGitBranch' => 'Phobject', 'DiffusionGitBranchTestCase' => 'PhabricatorTestCase', 'DiffusionGitCommandEngine' => 'DiffusionCommandEngine', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionGitLFSAuthenticateWorkflow' => 'DiffusionGitSSHWorkflow', 'DiffusionGitLFSResponse' => 'AphrontResponse', 'DiffusionGitLFSTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType', 'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionGitReceivePackSSHWorkflow' => 'DiffusionGitSSHWorkflow', 'DiffusionGitRequest' => 'DiffusionRequest', 'DiffusionGitResponse' => 'AphrontResponse', 'DiffusionGitSSHWorkflow' => array( 'DiffusionSSHWorkflow', 'DiffusionRepositoryClusterEngineLogInterface', ), 'DiffusionGitUploadPackSSHWorkflow' => 'DiffusionGitSSHWorkflow', 'DiffusionHistoryController' => 'DiffusionController', 'DiffusionHistoryQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionHistoryTableView' => 'DiffusionView', 'DiffusionHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', 'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController', 'DiffusionInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController', 'DiffusionInternalGitRawDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionLastModifiedController' => 'DiffusionController', 'DiffusionLastModifiedQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionLintController' => 'DiffusionController', 'DiffusionLintCountQuery' => 'PhabricatorQuery', 'DiffusionLintSaveRunner' => 'Phobject', 'DiffusionLocalRepositoryFilter' => 'Phobject', 'DiffusionLookSoonConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionLowLevelCommitFieldsQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelCommitQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelGitRefQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelMercurialBranchesQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelMercurialPathsQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelMercurialPathsQueryTests' => 'PhabricatorTestCase', 'DiffusionLowLevelParentsQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelQuery' => 'Phobject', 'DiffusionLowLevelResolveRefsQuery' => 'DiffusionLowLevelQuery', 'DiffusionMercurialBlameQuery' => 'DiffusionBlameQuery', 'DiffusionMercurialCommandEngine' => 'DiffusionCommandEngine', 'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionMercurialRequest' => 'DiffusionRequest', 'DiffusionMercurialResponse' => 'AphrontResponse', 'DiffusionMercurialSSHWorkflow' => 'DiffusionSSHWorkflow', 'DiffusionMercurialServeSSHWorkflow' => 'DiffusionMercurialSSHWorkflow', 'DiffusionMercurialWireClientSSHProtocolChannel' => 'PhutilProtocolChannel', 'DiffusionMercurialWireProtocol' => 'Phobject', 'DiffusionMercurialWireProtocolTests' => 'PhabricatorTestCase', 'DiffusionMercurialWireSSHTestCase' => 'PhabricatorTestCase', 'DiffusionMergedCommitsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionPathChange' => 'Phobject', 'DiffusionPathChangeQuery' => 'Phobject', 'DiffusionPathCompleteController' => 'DiffusionController', 'DiffusionPathIDQuery' => 'Phobject', 'DiffusionPathQuery' => 'Phobject', 'DiffusionPathQueryTestCase' => 'PhabricatorTestCase', 'DiffusionPathTreeController' => 'DiffusionController', 'DiffusionPathValidateController' => 'DiffusionController', 'DiffusionPhpExternalSymbolsSource' => 'DiffusionExternalSymbolsSource', 'DiffusionPreCommitContentAffectedFilesHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentAuthorHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentAuthorRawHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentBranchesHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentCommitterHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentCommitterRawHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentDiffContentAddedHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentDiffContentHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentDiffContentRemovedHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentDiffEnormousHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentHeraldField' => 'HeraldField', 'DiffusionPreCommitContentMergeHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentMessageHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentPusherHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentPusherIsCommitterHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentPusherProjectsHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentRepositoryHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentRepositoryProjectsHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentRevisionAcceptedHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentRevisionHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentRevisionReviewersHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitContentRevisionSubscribersHeraldField' => 'DiffusionPreCommitContentHeraldField', 'DiffusionPreCommitRefChangeHeraldField' => 'DiffusionPreCommitRefHeraldField', 'DiffusionPreCommitRefHeraldField' => 'HeraldField', 'DiffusionPreCommitRefHeraldFieldGroup' => 'HeraldFieldGroup', 'DiffusionPreCommitRefNameHeraldField' => 'DiffusionPreCommitRefHeraldField', 'DiffusionPreCommitRefPusherHeraldField' => 'DiffusionPreCommitRefHeraldField', 'DiffusionPreCommitRefPusherProjectsHeraldField' => 'DiffusionPreCommitRefHeraldField', 'DiffusionPreCommitRefRepositoryHeraldField' => 'DiffusionPreCommitRefHeraldField', 'DiffusionPreCommitRefRepositoryProjectsHeraldField' => 'DiffusionPreCommitRefHeraldField', 'DiffusionPreCommitRefTypeHeraldField' => 'DiffusionPreCommitRefHeraldField', 'DiffusionPullEventGarbageCollector' => 'PhabricatorGarbageCollector', 'DiffusionPushCapability' => 'PhabricatorPolicyCapability', 'DiffusionPushEventViewController' => 'DiffusionPushLogController', 'DiffusionPushLogController' => 'DiffusionController', 'DiffusionPushLogListController' => 'DiffusionPushLogController', 'DiffusionPushLogListView' => 'AphrontView', 'DiffusionPythonExternalSymbolsSource' => 'DiffusionExternalSymbolsSource', 'DiffusionQuery' => 'PhabricatorQuery', 'DiffusionQueryCommitsConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionQueryConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionQueryPathsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionRawDiffQuery' => 'DiffusionFileFutureQuery', 'DiffusionRawDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionReadmeView' => 'DiffusionView', 'DiffusionRefDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionRefNotFoundException' => 'Exception', 'DiffusionRefTableController' => 'DiffusionController', 'DiffusionRefsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionRenameHistoryQuery' => 'Phobject', 'DiffusionRepositoryActionsManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryAutomationManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryBasicsManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryBranchesManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryByIDRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositoryClusterEngine' => 'Phobject', 'DiffusionRepositoryController' => 'DiffusionController', 'DiffusionRepositoryDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionRepositoryDefaultController' => 'DiffusionController', 'DiffusionRepositoryDocumentationManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryEditActivateController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DiffusionRepositoryEditController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryEditDangerousController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryEditDeleteController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryEditEngine' => 'PhabricatorEditEngine', 'DiffusionRepositoryEditUpdateController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryHistoryManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryListController' => 'DiffusionController', 'DiffusionRepositoryManageController' => 'DiffusionController', 'DiffusionRepositoryManagePanelsController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryManagementPanel' => 'Phobject', 'DiffusionRepositoryPath' => 'Phobject', 'DiffusionRepositoryPoliciesManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryRef' => 'Phobject', 'DiffusionRepositoryRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositorySearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'DiffusionRepositoryStagingManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryStatusManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryStorageManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositorySubversionManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositorySymbolsManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryTag' => 'Phobject', 'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryManageController', 'DiffusionRepositoryURICredentialController' => 'DiffusionController', 'DiffusionRepositoryURIDisableController' => 'DiffusionController', 'DiffusionRepositoryURIEditController' => 'DiffusionController', 'DiffusionRepositoryURIViewController' => 'DiffusionController', 'DiffusionRepositoryURIsIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 'DiffusionRepositoryURIsManagementPanel' => 'DiffusionRepositoryManagementPanel', 'DiffusionRepositoryURIsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'DiffusionRequest' => 'Phobject', 'DiffusionResolveRefsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionResolveUserQuery' => 'Phobject', 'DiffusionSSHWorkflow' => 'PhabricatorSSHWorkflow', 'DiffusionSearchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionServeController' => 'DiffusionController', 'DiffusionSetPasswordSettingsPanel' => 'PhabricatorSettingsPanel', 'DiffusionSetupException' => 'Exception', 'DiffusionSubversionCommandEngine' => 'DiffusionCommandEngine', 'DiffusionSubversionSSHWorkflow' => 'DiffusionSSHWorkflow', 'DiffusionSubversionServeSSHWorkflow' => 'DiffusionSubversionSSHWorkflow', 'DiffusionSubversionWireProtocol' => 'Phobject', 'DiffusionSubversionWireProtocolTestCase' => 'PhabricatorTestCase', 'DiffusionSvnBlameQuery' => 'DiffusionBlameQuery', 'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionSvnRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionSvnRequest' => 'DiffusionRequest', 'DiffusionSymbolController' => 'DiffusionController', 'DiffusionSymbolDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionSymbolQuery' => 'PhabricatorOffsetPagedQuery', 'DiffusionTagListController' => 'DiffusionController', 'DiffusionTagListView' => 'DiffusionView', 'DiffusionTaggedRepositoriesFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DiffusionTagsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionURIEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DiffusionURIEditEngine' => 'PhabricatorEditEngine', 'DiffusionURIEditor' => 'PhabricatorApplicationTransactionEditor', 'DiffusionURITestCase' => 'PhutilTestCase', 'DiffusionUpdateCoverageConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionView' => 'AphrontView', 'DivinerArticleAtomizer' => 'DivinerAtomizer', 'DivinerAtom' => 'Phobject', 'DivinerAtomCache' => 'DivinerDiskCache', 'DivinerAtomController' => 'DivinerController', 'DivinerAtomListController' => 'DivinerController', 'DivinerAtomPHIDType' => 'PhabricatorPHIDType', 'DivinerAtomQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DivinerAtomRef' => 'Phobject', 'DivinerAtomSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DivinerAtomizeWorkflow' => 'DivinerWorkflow', 'DivinerAtomizer' => 'Phobject', 'DivinerBookController' => 'DivinerController', 'DivinerBookDatasource' => 'PhabricatorTypeaheadDatasource', 'DivinerBookEditController' => 'DivinerController', 'DivinerBookItemView' => 'AphrontTagView', 'DivinerBookPHIDType' => 'PhabricatorPHIDType', 'DivinerBookQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DivinerController' => 'PhabricatorController', 'DivinerDAO' => 'PhabricatorLiskDAO', 'DivinerDefaultEditCapability' => 'PhabricatorPolicyCapability', 'DivinerDefaultRenderer' => 'DivinerRenderer', 'DivinerDefaultViewCapability' => 'PhabricatorPolicyCapability', 'DivinerDiskCache' => 'Phobject', 'DivinerFileAtomizer' => 'DivinerAtomizer', 'DivinerFindController' => 'DivinerController', 'DivinerGenerateWorkflow' => 'DivinerWorkflow', 'DivinerLiveAtom' => 'DivinerDAO', 'DivinerLiveBook' => array( 'DivinerDAO', 'PhabricatorPolicyInterface', 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFulltextInterface', ), 'DivinerLiveBookEditor' => 'PhabricatorApplicationTransactionEditor', 'DivinerLiveBookFulltextEngine' => 'PhabricatorFulltextEngine', 'DivinerLiveBookTransaction' => 'PhabricatorApplicationTransaction', 'DivinerLiveBookTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DivinerLivePublisher' => 'DivinerPublisher', 'DivinerLiveSymbol' => array( 'DivinerDAO', 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFulltextInterface', ), 'DivinerLiveSymbolFulltextEngine' => 'PhabricatorFulltextEngine', 'DivinerMainController' => 'DivinerController', 'DivinerPHPAtomizer' => 'DivinerAtomizer', 'DivinerParameterTableView' => 'AphrontTagView', 'DivinerPublishCache' => 'DivinerDiskCache', 'DivinerPublisher' => 'Phobject', 'DivinerRenderer' => 'Phobject', 'DivinerReturnTableView' => 'AphrontTagView', 'DivinerSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'DivinerSectionView' => 'AphrontTagView', 'DivinerStaticPublisher' => 'DivinerPublisher', 'DivinerSymbolRemarkupRule' => 'PhutilRemarkupRule', 'DivinerWorkflow' => 'PhabricatorManagementWorkflow', 'DoorkeeperAsanaFeedWorker' => 'DoorkeeperFeedWorker', 'DoorkeeperAsanaRemarkupRule' => 'DoorkeeperRemarkupRule', 'DoorkeeperBridge' => 'Phobject', 'DoorkeeperBridgeAsana' => 'DoorkeeperBridge', 'DoorkeeperBridgeGitHub' => 'DoorkeeperBridge', 'DoorkeeperBridgeGitHubIssue' => 'DoorkeeperBridgeGitHub', 'DoorkeeperBridgeGitHubUser' => 'DoorkeeperBridgeGitHub', 'DoorkeeperBridgeJIRA' => 'DoorkeeperBridge', 'DoorkeeperBridgeJIRATestCase' => 'PhabricatorTestCase', 'DoorkeeperBridgedObjectCurtainExtension' => 'PHUICurtainExtension', 'DoorkeeperDAO' => 'PhabricatorLiskDAO', 'DoorkeeperExternalObject' => array( 'DoorkeeperDAO', 'PhabricatorPolicyInterface', ), 'DoorkeeperExternalObjectPHIDType' => 'PhabricatorPHIDType', 'DoorkeeperExternalObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DoorkeeperFeedStoryPublisher' => 'Phobject', 'DoorkeeperFeedWorker' => 'FeedPushWorker', 'DoorkeeperImportEngine' => 'Phobject', 'DoorkeeperJIRAFeedWorker' => 'DoorkeeperFeedWorker', 'DoorkeeperJIRARemarkupRule' => 'DoorkeeperRemarkupRule', 'DoorkeeperMissingLinkException' => 'Exception', 'DoorkeeperObjectRef' => 'Phobject', 'DoorkeeperRemarkupRule' => 'PhutilRemarkupRule', 'DoorkeeperSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'DoorkeeperTagView' => 'AphrontView', 'DoorkeeperTagsController' => 'PhabricatorController', 'DrydockAlmanacServiceHostBlueprintImplementation' => 'DrydockBlueprintImplementation', 'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface', 'DrydockAuthorization' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', + 'PhabricatorConduitResultInterface', ), 'DrydockAuthorizationAuthorizeController' => 'DrydockController', 'DrydockAuthorizationListController' => 'DrydockController', 'DrydockAuthorizationListView' => 'AphrontView', 'DrydockAuthorizationPHIDType' => 'PhabricatorPHIDType', 'DrydockAuthorizationQuery' => 'DrydockQuery', + 'DrydockAuthorizationSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'DrydockAuthorizationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockAuthorizationViewController' => 'DrydockController', 'DrydockBlueprint' => array( 'DrydockDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorNgramsInterface', 'PhabricatorProjectInterface', + 'PhabricatorConduitResultInterface', ), 'DrydockBlueprintController' => 'DrydockController', 'DrydockBlueprintCoreCustomField' => array( 'DrydockBlueprintCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'DrydockBlueprintCustomField' => 'PhabricatorCustomField', 'DrydockBlueprintDatasource' => 'PhabricatorTypeaheadDatasource', 'DrydockBlueprintDisableController' => 'DrydockBlueprintController', 'DrydockBlueprintEditController' => 'DrydockBlueprintController', 'DrydockBlueprintEditEngine' => 'PhabricatorEditEngine', 'DrydockBlueprintEditor' => 'PhabricatorApplicationTransactionEditor', 'DrydockBlueprintImplementation' => 'Phobject', 'DrydockBlueprintImplementationTestCase' => 'PhabricatorTestCase', 'DrydockBlueprintListController' => 'DrydockBlueprintController', 'DrydockBlueprintNameNgrams' => 'PhabricatorSearchNgrams', 'DrydockBlueprintPHIDType' => 'PhabricatorPHIDType', 'DrydockBlueprintQuery' => 'DrydockQuery', + 'DrydockBlueprintSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'DrydockBlueprintSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockBlueprintTransaction' => 'PhabricatorApplicationTransaction', 'DrydockBlueprintTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DrydockBlueprintViewController' => 'DrydockBlueprintController', 'DrydockCommand' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockCommandError' => 'Phobject', 'DrydockCommandInterface' => 'DrydockInterface', 'DrydockCommandQuery' => 'DrydockQuery', 'DrydockConsoleController' => 'DrydockController', 'DrydockConstants' => 'Phobject', 'DrydockController' => 'PhabricatorController', 'DrydockCreateBlueprintsCapability' => 'PhabricatorPolicyCapability', 'DrydockDAO' => 'PhabricatorLiskDAO', 'DrydockDefaultEditCapability' => 'PhabricatorPolicyCapability', 'DrydockDefaultViewCapability' => 'PhabricatorPolicyCapability', 'DrydockFilesystemInterface' => 'DrydockInterface', 'DrydockInterface' => 'Phobject', 'DrydockLandRepositoryOperation' => 'DrydockRepositoryOperationType', 'DrydockLease' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockLeaseAcquiredLogType' => 'DrydockLogType', 'DrydockLeaseActivatedLogType' => 'DrydockLogType', 'DrydockLeaseActivationFailureLogType' => 'DrydockLogType', 'DrydockLeaseActivationYieldLogType' => 'DrydockLogType', 'DrydockLeaseController' => 'DrydockController', 'DrydockLeaseDatasource' => 'PhabricatorTypeaheadDatasource', 'DrydockLeaseDestroyedLogType' => 'DrydockLogType', 'DrydockLeaseListController' => 'DrydockLeaseController', 'DrydockLeaseListView' => 'AphrontView', 'DrydockLeaseNoAuthorizationsLogType' => 'DrydockLogType', 'DrydockLeaseNoBlueprintsLogType' => 'DrydockLogType', 'DrydockLeasePHIDType' => 'PhabricatorPHIDType', 'DrydockLeaseQuery' => 'DrydockQuery', 'DrydockLeaseQueuedLogType' => 'DrydockLogType', 'DrydockLeaseReclaimLogType' => 'DrydockLogType', 'DrydockLeaseReleaseController' => 'DrydockLeaseController', 'DrydockLeaseReleasedLogType' => 'DrydockLogType', 'DrydockLeaseSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockLeaseStatus' => 'DrydockConstants', 'DrydockLeaseUpdateWorker' => 'DrydockWorker', 'DrydockLeaseViewController' => 'DrydockLeaseController', 'DrydockLeaseWaitingForResourcesLogType' => 'DrydockLogType', 'DrydockLog' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockLogController' => 'DrydockController', 'DrydockLogGarbageCollector' => 'PhabricatorGarbageCollector', 'DrydockLogListController' => 'DrydockLogController', 'DrydockLogListView' => 'AphrontView', 'DrydockLogQuery' => 'DrydockQuery', 'DrydockLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockLogType' => 'Phobject', 'DrydockManagementCommandWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementLeaseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementReclaimWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementReleaseLeaseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementReleaseResourceWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementUpdateLeaseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementUpdateResourceWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementWorkflow' => 'PhabricatorManagementWorkflow', 'DrydockObjectAuthorizationView' => 'AphrontView', 'DrydockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DrydockRepositoryOperation' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockRepositoryOperationController' => 'DrydockController', 'DrydockRepositoryOperationDismissController' => 'DrydockRepositoryOperationController', 'DrydockRepositoryOperationListController' => 'DrydockRepositoryOperationController', 'DrydockRepositoryOperationPHIDType' => 'PhabricatorPHIDType', 'DrydockRepositoryOperationQuery' => 'DrydockQuery', 'DrydockRepositoryOperationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockRepositoryOperationStatusController' => 'DrydockRepositoryOperationController', 'DrydockRepositoryOperationStatusView' => 'AphrontView', 'DrydockRepositoryOperationType' => 'Phobject', 'DrydockRepositoryOperationUpdateWorker' => 'DrydockWorker', 'DrydockRepositoryOperationViewController' => 'DrydockRepositoryOperationController', 'DrydockResource' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockResourceActivationFailureLogType' => 'DrydockLogType', 'DrydockResourceActivationYieldLogType' => 'DrydockLogType', 'DrydockResourceController' => 'DrydockController', 'DrydockResourceDatasource' => 'PhabricatorTypeaheadDatasource', 'DrydockResourceListController' => 'DrydockResourceController', 'DrydockResourceListView' => 'AphrontView', 'DrydockResourcePHIDType' => 'PhabricatorPHIDType', 'DrydockResourceQuery' => 'DrydockQuery', 'DrydockResourceReclaimLogType' => 'DrydockLogType', 'DrydockResourceReleaseController' => 'DrydockResourceController', 'DrydockResourceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockResourceStatus' => 'DrydockConstants', 'DrydockResourceUpdateWorker' => 'DrydockWorker', 'DrydockResourceViewController' => 'DrydockResourceController', 'DrydockSFTPFilesystemInterface' => 'DrydockFilesystemInterface', 'DrydockSSHCommandInterface' => 'DrydockCommandInterface', 'DrydockSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'DrydockSlotLock' => 'DrydockDAO', 'DrydockSlotLockException' => 'Exception', 'DrydockSlotLockFailureLogType' => 'DrydockLogType', 'DrydockTestRepositoryOperation' => 'DrydockRepositoryOperationType', 'DrydockWebrootInterface' => 'DrydockInterface', 'DrydockWorker' => 'PhabricatorWorker', 'DrydockWorkingCopyBlueprintImplementation' => 'DrydockBlueprintImplementation', 'FeedConduitAPIMethod' => 'ConduitAPIMethod', 'FeedPublishConduitAPIMethod' => 'FeedConduitAPIMethod', 'FeedPublisherHTTPWorker' => 'FeedPushWorker', 'FeedPublisherWorker' => 'FeedPushWorker', 'FeedPushWorker' => 'PhabricatorWorker', 'FeedQueryConduitAPIMethod' => 'FeedConduitAPIMethod', 'FeedStoryNotificationGarbageCollector' => 'PhabricatorGarbageCollector', 'FileAllocateConduitAPIMethod' => 'FileConduitAPIMethod', 'FileConduitAPIMethod' => 'ConduitAPIMethod', 'FileCreateMailReceiver' => 'PhabricatorMailReceiver', 'FileDownloadConduitAPIMethod' => 'FileConduitAPIMethod', 'FileInfoConduitAPIMethod' => 'FileConduitAPIMethod', 'FileMailReceiver' => 'PhabricatorObjectMailReceiver', 'FileQueryChunksConduitAPIMethod' => 'FileConduitAPIMethod', 'FileReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'FileUploadChunkConduitAPIMethod' => 'FileConduitAPIMethod', 'FileUploadConduitAPIMethod' => 'FileConduitAPIMethod', 'FileUploadHashConduitAPIMethod' => 'FileConduitAPIMethod', 'FilesDefaultViewCapability' => 'PhabricatorPolicyCapability', 'FlagConduitAPIMethod' => 'ConduitAPIMethod', 'FlagDeleteConduitAPIMethod' => 'FlagConduitAPIMethod', 'FlagEditConduitAPIMethod' => 'FlagConduitAPIMethod', 'FlagQueryConduitAPIMethod' => 'FlagConduitAPIMethod', 'FundBacker' => array( 'FundDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', ), 'FundBackerCart' => 'PhortuneCartImplementation', 'FundBackerEditor' => 'PhabricatorApplicationTransactionEditor', 'FundBackerListController' => 'FundController', 'FundBackerPHIDType' => 'PhabricatorPHIDType', 'FundBackerProduct' => 'PhortuneProductImplementation', 'FundBackerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'FundBackerSearchEngine' => 'PhabricatorApplicationSearchEngine', 'FundBackerTransaction' => 'PhabricatorApplicationTransaction', 'FundBackerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'FundController' => 'PhabricatorController', 'FundCreateInitiativesCapability' => 'PhabricatorPolicyCapability', 'FundDAO' => 'PhabricatorLiskDAO', 'FundDefaultViewCapability' => 'PhabricatorPolicyCapability', 'FundInitiative' => array( 'FundDAO', 'PhabricatorPolicyInterface', 'PhabricatorProjectInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', 'PhabricatorMentionableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFulltextInterface', ), 'FundInitiativeBackController' => 'FundController', 'FundInitiativeCloseController' => 'FundController', 'FundInitiativeCommentController' => 'FundController', 'FundInitiativeEditController' => 'FundController', 'FundInitiativeEditor' => 'PhabricatorApplicationTransactionEditor', 'FundInitiativeFulltextEngine' => 'PhabricatorFulltextEngine', 'FundInitiativeListController' => 'FundController', 'FundInitiativePHIDType' => 'PhabricatorPHIDType', 'FundInitiativeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'FundInitiativeRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'FundInitiativeReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'FundInitiativeSearchEngine' => 'PhabricatorApplicationSearchEngine', 'FundInitiativeTransaction' => 'PhabricatorApplicationTransaction', 'FundInitiativeTransactionComment' => 'PhabricatorApplicationTransactionComment', 'FundInitiativeTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'FundInitiativeViewController' => 'FundController', 'FundSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'HarbormasterArcLintBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterArcUnitBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterArtifact' => 'Phobject', 'HarbormasterAutotargetsTestCase' => 'PhabricatorTestCase', 'HarbormasterBuild' => array( 'HarbormasterDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorConduitResultInterface', ), 'HarbormasterBuildAbortedException' => 'Exception', 'HarbormasterBuildActionController' => 'HarbormasterController', 'HarbormasterBuildArcanistAutoplan' => 'HarbormasterBuildAutoplan', 'HarbormasterBuildArtifact' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), 'HarbormasterBuildArtifactPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildAutoplan' => 'Phobject', 'HarbormasterBuildCommand' => 'HarbormasterDAO', 'HarbormasterBuildDependencyDatasource' => 'PhabricatorTypeaheadDatasource', 'HarbormasterBuildEngine' => 'Phobject', 'HarbormasterBuildFailureException' => 'Exception', 'HarbormasterBuildGraph' => 'AbstractDirectedGraph', 'HarbormasterBuildInitiatorDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'HarbormasterBuildLintMessage' => 'HarbormasterDAO', 'HarbormasterBuildListController' => 'HarbormasterController', 'HarbormasterBuildLog' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), 'HarbormasterBuildLogChunk' => 'HarbormasterDAO', 'HarbormasterBuildLogChunkIterator' => 'PhutilBufferedIterator', 'HarbormasterBuildLogPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildMessage' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), 'HarbormasterBuildMessageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildPlan' => array( 'HarbormasterDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorNgramsInterface', 'PhabricatorProjectInterface', ), 'HarbormasterBuildPlanDatasource' => 'PhabricatorTypeaheadDatasource', 'HarbormasterBuildPlanDefaultEditCapability' => 'PhabricatorPolicyCapability', 'HarbormasterBuildPlanDefaultViewCapability' => 'PhabricatorPolicyCapability', 'HarbormasterBuildPlanEditEngine' => 'PhabricatorEditEngine', 'HarbormasterBuildPlanEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildPlanNameNgrams' => 'PhabricatorSearchNgrams', 'HarbormasterBuildPlanPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildPlanQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildPlanSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HarbormasterBuildPlanTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildPlanTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildRequest' => 'Phobject', 'HarbormasterBuildSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'HarbormasterBuildSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HarbormasterBuildStatus' => 'Phobject', 'HarbormasterBuildStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'HarbormasterBuildStep' => array( 'HarbormasterDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', ), 'HarbormasterBuildStepCoreCustomField' => array( 'HarbormasterBuildStepCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'HarbormasterBuildStepCustomField' => 'PhabricatorCustomField', 'HarbormasterBuildStepEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildStepGroup' => 'Phobject', 'HarbormasterBuildStepImplementation' => 'Phobject', 'HarbormasterBuildStepImplementationTestCase' => 'PhabricatorTestCase', 'HarbormasterBuildStepPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildStepTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildStepTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildTarget' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), 'HarbormasterBuildTargetPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildTargetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildUnitMessage' => 'HarbormasterDAO', 'HarbormasterBuildViewController' => 'HarbormasterController', 'HarbormasterBuildWorker' => 'HarbormasterWorker', 'HarbormasterBuildable' => array( 'HarbormasterDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'HarbormasterBuildableInterface', ), 'HarbormasterBuildableActionController' => 'HarbormasterController', 'HarbormasterBuildableListController' => 'HarbormasterController', 'HarbormasterBuildablePHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildableQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildableSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HarbormasterBuildableTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildableTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildableTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildableViewController' => 'HarbormasterController', 'HarbormasterBuiltinBuildStepGroup' => 'HarbormasterBuildStepGroup', 'HarbormasterCircleCIBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterCircleCIHookController' => 'HarbormasterController', 'HarbormasterConduitAPIMethod' => 'ConduitAPIMethod', 'HarbormasterController' => 'PhabricatorController', 'HarbormasterCreateArtifactConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterCreatePlansCapability' => 'PhabricatorPolicyCapability', 'HarbormasterDAO' => 'PhabricatorLiskDAO', 'HarbormasterDrydockBuildStepGroup' => 'HarbormasterBuildStepGroup', 'HarbormasterDrydockCommandBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterDrydockLeaseArtifact' => 'HarbormasterArtifact', 'HarbormasterExecFuture' => 'Future', 'HarbormasterExternalBuildStepGroup' => 'HarbormasterBuildStepGroup', 'HarbormasterFileArtifact' => 'HarbormasterArtifact', 'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterHostArtifact' => 'HarbormasterDrydockLeaseArtifact', 'HarbormasterLeaseWorkingCopyBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterLintMessagesController' => 'HarbormasterController', 'HarbormasterLintPropertyView' => 'AphrontView', 'HarbormasterManagementArchiveLogsWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementRestartWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementWorkflow' => 'PhabricatorManagementWorkflow', 'HarbormasterMessageType' => 'Phobject', 'HarbormasterObject' => 'HarbormasterDAO', 'HarbormasterOtherBuildStepGroup' => 'HarbormasterBuildStepGroup', 'HarbormasterPlanController' => 'HarbormasterController', 'HarbormasterPlanDisableController' => 'HarbormasterPlanController', 'HarbormasterPlanEditController' => 'HarbormasterPlanController', 'HarbormasterPlanListController' => 'HarbormasterPlanController', 'HarbormasterPlanRunController' => 'HarbormasterPlanController', 'HarbormasterPlanViewController' => 'HarbormasterPlanController', 'HarbormasterPrototypeBuildStepGroup' => 'HarbormasterBuildStepGroup', 'HarbormasterPublishFragmentBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterQueryAutotargetsConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryBuildablesConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryBuildsConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryBuildsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'HarbormasterRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'HarbormasterRunBuildPlansHeraldAction' => 'HeraldAction', 'HarbormasterSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'HarbormasterScratchTable' => 'HarbormasterDAO', 'HarbormasterSendMessageConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterSleepBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterStepAddController' => 'HarbormasterPlanController', 'HarbormasterStepDeleteController' => 'HarbormasterPlanController', 'HarbormasterStepEditController' => 'HarbormasterPlanController', 'HarbormasterStepViewController' => 'HarbormasterPlanController', 'HarbormasterTargetEngine' => 'Phobject', 'HarbormasterTargetWorker' => 'HarbormasterWorker', 'HarbormasterTestBuildStepGroup' => 'HarbormasterBuildStepGroup', 'HarbormasterThrowExceptionBuildStep' => 'HarbormasterBuildStepImplementation', 'HarbormasterUIEventListener' => 'PhabricatorEventListener', 'HarbormasterURIArtifact' => 'HarbormasterArtifact', 'HarbormasterUnitMessageListController' => 'HarbormasterController', 'HarbormasterUnitMessageViewController' => 'HarbormasterController', 'HarbormasterUnitPropertyView' => 'AphrontView', 'HarbormasterUnitStatus' => 'Phobject', 'HarbormasterUnitSummaryView' => 'AphrontView', 'HarbormasterUploadArtifactBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterWorker' => 'PhabricatorWorker', 'HarbormasterWorkingCopyArtifact' => 'HarbormasterDrydockLeaseArtifact', 'HeraldAction' => 'Phobject', 'HeraldActionGroup' => 'HeraldGroup', 'HeraldActionRecord' => 'HeraldDAO', 'HeraldAdapter' => 'Phobject', 'HeraldAlwaysField' => 'HeraldField', 'HeraldAnotherRuleField' => 'HeraldField', 'HeraldApplicationActionGroup' => 'HeraldActionGroup', 'HeraldApplyTranscript' => 'Phobject', 'HeraldBasicFieldGroup' => 'HeraldFieldGroup', 'HeraldCommitAdapter' => array( 'HeraldAdapter', 'HarbormasterBuildableAdapterInterface', ), 'HeraldCondition' => 'HeraldDAO', 'HeraldConditionTranscript' => 'Phobject', 'HeraldContentSourceField' => 'HeraldField', 'HeraldController' => 'PhabricatorController', 'HeraldDAO' => 'PhabricatorLiskDAO', 'HeraldDifferentialAdapter' => 'HeraldAdapter', 'HeraldDifferentialDiffAdapter' => 'HeraldDifferentialAdapter', 'HeraldDifferentialRevisionAdapter' => array( 'HeraldDifferentialAdapter', 'HarbormasterBuildableAdapterInterface', ), 'HeraldDisableController' => 'HeraldController', 'HeraldDoNothingAction' => 'HeraldAction', 'HeraldEditFieldGroup' => 'HeraldFieldGroup', 'HeraldEffect' => 'Phobject', 'HeraldEmptyFieldValue' => 'HeraldFieldValue', 'HeraldEngine' => 'Phobject', 'HeraldExactProjectsField' => 'HeraldField', 'HeraldField' => 'Phobject', 'HeraldFieldGroup' => 'HeraldGroup', 'HeraldFieldTestCase' => 'PhutilTestCase', 'HeraldFieldValue' => 'Phobject', 'HeraldGroup' => 'Phobject', 'HeraldInvalidActionException' => 'Exception', 'HeraldInvalidConditionException' => 'Exception', 'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability', 'HeraldManiphestTaskAdapter' => 'HeraldAdapter', 'HeraldNewController' => 'HeraldController', 'HeraldNewObjectField' => 'HeraldField', 'HeraldNotifyActionGroup' => 'HeraldActionGroup', 'HeraldObjectTranscript' => 'Phobject', 'HeraldPhameBlogAdapter' => 'HeraldAdapter', 'HeraldPhamePostAdapter' => 'HeraldAdapter', 'HeraldPholioMockAdapter' => 'HeraldAdapter', 'HeraldPonderQuestionAdapter' => 'HeraldAdapter', 'HeraldPreCommitAdapter' => 'HeraldAdapter', 'HeraldPreCommitContentAdapter' => 'HeraldPreCommitAdapter', 'HeraldPreCommitRefAdapter' => 'HeraldPreCommitAdapter', 'HeraldPreventActionGroup' => 'HeraldActionGroup', 'HeraldProjectsField' => 'HeraldField', 'HeraldRecursiveConditionsException' => 'Exception', 'HeraldRelatedFieldGroup' => 'HeraldFieldGroup', 'HeraldRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'HeraldRepetitionPolicyConfig' => 'Phobject', 'HeraldRule' => array( 'HeraldDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSubscribableInterface', ), 'HeraldRuleController' => 'HeraldController', 'HeraldRuleDatasource' => 'PhabricatorTypeaheadDatasource', 'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor', 'HeraldRuleListController' => 'HeraldController', 'HeraldRulePHIDType' => 'PhabricatorPHIDType', 'HeraldRuleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HeraldRuleSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HeraldRuleSerializer' => 'Phobject', 'HeraldRuleTestCase' => 'PhabricatorTestCase', 'HeraldRuleTransaction' => 'PhabricatorApplicationTransaction', 'HeraldRuleTransactionComment' => 'PhabricatorApplicationTransactionComment', 'HeraldRuleTranscript' => 'Phobject', 'HeraldRuleTypeConfig' => 'Phobject', 'HeraldRuleViewController' => 'HeraldController', 'HeraldSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'HeraldSelectFieldValue' => 'HeraldFieldValue', 'HeraldSpaceField' => 'HeraldField', 'HeraldSubscribersField' => 'HeraldField', 'HeraldSupportActionGroup' => 'HeraldActionGroup', 'HeraldSupportFieldGroup' => 'HeraldFieldGroup', 'HeraldTestConsoleController' => 'HeraldController', 'HeraldTextFieldValue' => 'HeraldFieldValue', 'HeraldTokenizerFieldValue' => 'HeraldFieldValue', 'HeraldTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HeraldTranscript' => array( 'HeraldDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'HeraldTranscriptController' => 'HeraldController', 'HeraldTranscriptDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'HeraldTranscriptGarbageCollector' => 'PhabricatorGarbageCollector', 'HeraldTranscriptListController' => 'HeraldController', 'HeraldTranscriptPHIDType' => 'PhabricatorPHIDType', 'HeraldTranscriptQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HeraldTranscriptTestCase' => 'PhabricatorTestCase', 'HeraldUtilityActionGroup' => 'HeraldActionGroup', 'Javelin' => 'Phobject', 'JavelinReactorUIExample' => 'PhabricatorUIExample', 'JavelinUIExample' => 'PhabricatorUIExample', 'JavelinViewExampleServerView' => 'AphrontView', 'JavelinViewUIExample' => 'PhabricatorUIExample', 'LegalpadController' => 'PhabricatorController', 'LegalpadCreateDocumentsCapability' => 'PhabricatorPolicyCapability', 'LegalpadDAO' => 'PhabricatorLiskDAO', 'LegalpadDefaultEditCapability' => 'PhabricatorPolicyCapability', 'LegalpadDefaultViewCapability' => 'PhabricatorPolicyCapability', 'LegalpadDocument' => array( 'LegalpadDAO', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), 'LegalpadDocumentBody' => array( 'LegalpadDAO', 'PhabricatorMarkupInterface', ), 'LegalpadDocumentCommentController' => 'LegalpadController', 'LegalpadDocumentDatasource' => 'PhabricatorTypeaheadDatasource', 'LegalpadDocumentDoneController' => 'LegalpadController', 'LegalpadDocumentEditController' => 'LegalpadController', 'LegalpadDocumentEditor' => 'PhabricatorApplicationTransactionEditor', 'LegalpadDocumentListController' => 'LegalpadController', 'LegalpadDocumentManageController' => 'LegalpadController', 'LegalpadDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'LegalpadDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine', 'LegalpadDocumentSignController' => 'LegalpadController', 'LegalpadDocumentSignature' => array( 'LegalpadDAO', 'PhabricatorPolicyInterface', ), 'LegalpadDocumentSignatureAddController' => 'LegalpadController', 'LegalpadDocumentSignatureListController' => 'LegalpadController', 'LegalpadDocumentSignatureQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentSignatureSearchEngine' => 'PhabricatorApplicationSearchEngine', 'LegalpadDocumentSignatureVerificationController' => 'LegalpadController', 'LegalpadDocumentSignatureViewController' => 'LegalpadController', 'LegalpadMailReceiver' => 'PhabricatorObjectMailReceiver', 'LegalpadObjectNeedsSignatureEdgeType' => 'PhabricatorEdgeType', 'LegalpadReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'LegalpadRequireSignatureHeraldAction' => 'HeraldAction', 'LegalpadSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'LegalpadSignatureNeededByObjectEdgeType' => 'PhabricatorEdgeType', 'LegalpadTransaction' => 'PhabricatorApplicationTransaction', 'LegalpadTransactionComment' => 'PhabricatorApplicationTransactionComment', 'LegalpadTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'LegalpadTransactionView' => 'PhabricatorApplicationTransactionView', 'LiskChunkTestCase' => 'PhabricatorTestCase', 'LiskDAO' => 'Phobject', 'LiskDAOSet' => 'Phobject', 'LiskDAOTestCase' => 'PhabricatorTestCase', 'LiskEphemeralObjectException' => 'Exception', 'LiskFixtureTestCase' => 'PhabricatorTestCase', 'LiskIsolationTestCase' => 'PhabricatorTestCase', 'LiskIsolationTestDAO' => 'LiskDAO', 'LiskIsolationTestDAOException' => 'Exception', 'LiskMigrationIterator' => 'PhutilBufferedIterator', 'LiskRawMigrationIterator' => 'PhutilBufferedIterator', 'MacroConduitAPIMethod' => 'ConduitAPIMethod', 'MacroCreateMemeConduitAPIMethod' => 'MacroConduitAPIMethod', 'MacroQueryConduitAPIMethod' => 'MacroConduitAPIMethod', 'ManiphestAssignEmailCommand' => 'ManiphestEmailCommand', 'ManiphestAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'ManiphestBatchEditController' => 'ManiphestController', 'ManiphestBulkEditCapability' => 'PhabricatorPolicyCapability', 'ManiphestClaimEmailCommand' => 'ManiphestEmailCommand', 'ManiphestCloseEmailCommand' => 'ManiphestEmailCommand', 'ManiphestConduitAPIMethod' => 'ConduitAPIMethod', 'ManiphestConfiguredCustomField' => array( 'ManiphestCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'ManiphestConstants' => 'Phobject', 'ManiphestController' => 'PhabricatorController', 'ManiphestCreateMailReceiver' => 'PhabricatorMailReceiver', 'ManiphestCreateTaskConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestCustomField' => 'PhabricatorCustomField', 'ManiphestCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'ManiphestCustomFieldStatusParser' => 'PhabricatorCustomFieldMonogramParser', 'ManiphestCustomFieldStatusParserTestCase' => 'PhabricatorTestCase', 'ManiphestCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'ManiphestCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'ManiphestDAO' => 'PhabricatorLiskDAO', 'ManiphestDefaultEditCapability' => 'PhabricatorPolicyCapability', 'ManiphestDefaultViewCapability' => 'PhabricatorPolicyCapability', 'ManiphestEditAssignCapability' => 'PhabricatorPolicyCapability', 'ManiphestEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'ManiphestEditEngine' => 'PhabricatorEditEngine', 'ManiphestEditPoliciesCapability' => 'PhabricatorPolicyCapability', 'ManiphestEditPriorityCapability' => 'PhabricatorPolicyCapability', 'ManiphestEditProjectsCapability' => 'PhabricatorPolicyCapability', 'ManiphestEditStatusCapability' => 'PhabricatorPolicyCapability', 'ManiphestEmailCommand' => 'MetaMTAEmailTransactionCommand', 'ManiphestExcelDefaultFormat' => 'ManiphestExcelFormat', 'ManiphestExcelFormat' => 'Phobject', 'ManiphestExcelFormatTestCase' => 'PhabricatorTestCase', 'ManiphestExportController' => 'ManiphestController', 'ManiphestGetTaskTransactionsConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', 'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestNameIndex' => 'ManiphestDAO', 'ManiphestPointsConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestPriorityConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestPriorityEmailCommand' => 'ManiphestEmailCommand', 'ManiphestProjectNameFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'ManiphestQueryConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestQueryStatusesConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'ManiphestReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'ManiphestReportController' => 'ManiphestController', 'ManiphestSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'ManiphestSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand', 'ManiphestSubpriorityController' => 'ManiphestController', 'ManiphestTask' => array( 'ManiphestDAO', 'PhabricatorSubscribableInterface', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhabricatorMentionableInterface', 'PhrequentTrackableInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', 'PhabricatorSpacesInterface', 'PhabricatorConduitResultInterface', 'PhabricatorFulltextInterface', 'DoorkeeperBridgedObjectInterface', ), 'ManiphestTaskAssignHeraldAction' => 'HeraldAction', 'ManiphestTaskAssignOtherHeraldAction' => 'ManiphestTaskAssignHeraldAction', 'ManiphestTaskAssignSelfHeraldAction' => 'ManiphestTaskAssignHeraldAction', 'ManiphestTaskAssigneeHeraldField' => 'ManiphestTaskHeraldField', 'ManiphestTaskAuthorHeraldField' => 'ManiphestTaskHeraldField', 'ManiphestTaskAuthorPolicyRule' => 'PhabricatorPolicyRule', 'ManiphestTaskCloseAsDuplicateRelationship' => 'ManiphestTaskRelationship', 'ManiphestTaskClosedStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskDependedOnByTaskEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskDependsOnTaskEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskDescriptionHeraldField' => 'ManiphestTaskHeraldField', 'ManiphestTaskDetailController' => 'ManiphestController', 'ManiphestTaskEditBulkJobType' => 'PhabricatorWorkerBulkJobType', 'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskFulltextEngine' => 'PhabricatorFulltextEngine', 'ManiphestTaskGraph' => 'PhabricatorObjectGraph', 'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskHasCommitRelationship' => 'ManiphestTaskRelationship', 'ManiphestTaskHasDuplicateTaskEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskHasMockEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskHasMockRelationship' => 'ManiphestTaskRelationship', 'ManiphestTaskHasParentRelationship' => 'ManiphestTaskRelationship', 'ManiphestTaskHasRevisionEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskHasRevisionRelationship' => 'ManiphestTaskRelationship', 'ManiphestTaskHasSubtaskRelationship' => 'ManiphestTaskRelationship', 'ManiphestTaskHeraldField' => 'HeraldField', 'ManiphestTaskHeraldFieldGroup' => 'HeraldFieldGroup', 'ManiphestTaskIsDuplicateOfTaskEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskListController' => 'ManiphestController', 'ManiphestTaskListHTTPParameterType' => 'AphrontListHTTPParameterType', 'ManiphestTaskListView' => 'ManiphestView', 'ManiphestTaskMailReceiver' => 'PhabricatorObjectMailReceiver', 'ManiphestTaskMergeInRelationship' => 'ManiphestTaskRelationship', 'ManiphestTaskOpenStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskPHIDResolver' => 'PhabricatorPHIDResolver', 'ManiphestTaskPHIDType' => 'PhabricatorPHIDType', 'ManiphestTaskPoints' => 'Phobject', 'ManiphestTaskPriority' => 'ManiphestConstants', 'ManiphestTaskPriorityDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskPriorityHeraldAction' => 'HeraldAction', 'ManiphestTaskPriorityHeraldField' => 'ManiphestTaskHeraldField', 'ManiphestTaskQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ManiphestTaskRelationship' => 'PhabricatorObjectRelationship', 'ManiphestTaskRelationshipSource' => 'PhabricatorObjectRelationshipSource', 'ManiphestTaskResultListView' => 'ManiphestView', 'ManiphestTaskSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ManiphestTaskStatus' => 'ManiphestConstants', 'ManiphestTaskStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskStatusFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'ManiphestTaskStatusHeraldAction' => 'HeraldAction', 'ManiphestTaskStatusHeraldField' => 'ManiphestTaskHeraldField', 'ManiphestTaskStatusTestCase' => 'PhabricatorTestCase', 'ManiphestTaskTestCase' => 'PhabricatorTestCase', 'ManiphestTaskTitleHeraldField' => 'ManiphestTaskHeraldField', 'ManiphestTransaction' => 'PhabricatorApplicationTransaction', 'ManiphestTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ManiphestTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'ManiphestTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ManiphestUpdateConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestView' => 'AphrontView', 'MetaMTAEmailTransactionCommand' => 'Phobject', 'MetaMTAEmailTransactionCommandTestCase' => 'PhabricatorTestCase', 'MetaMTAMailReceivedGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTAMailSentGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTAReceivedMailStatus' => 'Phobject', 'MultimeterContext' => 'MultimeterDimension', 'MultimeterControl' => 'Phobject', 'MultimeterController' => 'PhabricatorController', 'MultimeterDAO' => 'PhabricatorLiskDAO', 'MultimeterDimension' => 'MultimeterDAO', 'MultimeterEvent' => 'MultimeterDAO', 'MultimeterEventGarbageCollector' => 'PhabricatorGarbageCollector', 'MultimeterHost' => 'MultimeterDimension', 'MultimeterLabel' => 'MultimeterDimension', 'MultimeterSampleController' => 'MultimeterController', 'MultimeterViewer' => 'MultimeterDimension', 'NuanceConduitAPIMethod' => 'ConduitAPIMethod', 'NuanceConsoleController' => 'NuanceController', 'NuanceContentSource' => 'PhabricatorContentSource', 'NuanceController' => 'PhabricatorController', 'NuanceDAO' => 'PhabricatorLiskDAO', 'NuanceGitHubEventItemType' => 'NuanceItemType', 'NuanceGitHubImportCursor' => 'NuanceImportCursor', 'NuanceGitHubIssuesImportCursor' => 'NuanceGitHubImportCursor', 'NuanceGitHubRawEvent' => 'Phobject', 'NuanceGitHubRawEventTestCase' => 'PhabricatorTestCase', 'NuanceGitHubRepositoryImportCursor' => 'NuanceGitHubImportCursor', 'NuanceGitHubRepositorySourceDefinition' => 'NuanceSourceDefinition', 'NuanceImportCursor' => 'Phobject', 'NuanceImportCursorData' => array( 'NuanceDAO', 'PhabricatorPolicyInterface', ), 'NuanceImportCursorDataQuery' => 'NuanceQuery', 'NuanceImportCursorPHIDType' => 'PhabricatorPHIDType', 'NuanceItem' => array( 'NuanceDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', ), 'NuanceItemActionController' => 'NuanceController', 'NuanceItemCommand' => array( 'NuanceDAO', 'PhabricatorPolicyInterface', ), 'NuanceItemCommandQuery' => 'NuanceQuery', 'NuanceItemController' => 'NuanceController', 'NuanceItemEditor' => 'PhabricatorApplicationTransactionEditor', 'NuanceItemListController' => 'NuanceItemController', 'NuanceItemManageController' => 'NuanceController', 'NuanceItemPHIDType' => 'PhabricatorPHIDType', 'NuanceItemQuery' => 'NuanceQuery', 'NuanceItemSearchEngine' => 'PhabricatorApplicationSearchEngine', 'NuanceItemTransaction' => 'NuanceTransaction', 'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceItemType' => 'Phobject', 'NuanceItemUpdateWorker' => 'NuanceWorker', 'NuanceItemViewController' => 'NuanceController', 'NuanceManagementImportWorkflow' => 'NuanceManagementWorkflow', 'NuanceManagementUpdateWorkflow' => 'NuanceManagementWorkflow', 'NuanceManagementWorkflow' => 'PhabricatorManagementWorkflow', 'NuancePhabricatorFormSourceDefinition' => 'NuanceSourceDefinition', 'NuanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'NuanceQueue' => array( 'NuanceDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', ), 'NuanceQueueController' => 'NuanceController', 'NuanceQueueDatasource' => 'PhabricatorTypeaheadDatasource', 'NuanceQueueEditController' => 'NuanceQueueController', 'NuanceQueueEditEngine' => 'PhabricatorEditEngine', 'NuanceQueueEditor' => 'PhabricatorApplicationTransactionEditor', 'NuanceQueueListController' => 'NuanceQueueController', 'NuanceQueuePHIDType' => 'PhabricatorPHIDType', 'NuanceQueueQuery' => 'NuanceQuery', 'NuanceQueueSearchEngine' => 'PhabricatorApplicationSearchEngine', 'NuanceQueueTransaction' => 'NuanceTransaction', 'NuanceQueueTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceQueueViewController' => 'NuanceQueueController', 'NuanceSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'NuanceSource' => array( 'NuanceDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorNgramsInterface', ), 'NuanceSourceActionController' => 'NuanceController', 'NuanceSourceController' => 'NuanceController', 'NuanceSourceDefaultEditCapability' => 'PhabricatorPolicyCapability', 'NuanceSourceDefaultViewCapability' => 'PhabricatorPolicyCapability', 'NuanceSourceDefinition' => 'Phobject', 'NuanceSourceDefinitionTestCase' => 'PhabricatorTestCase', 'NuanceSourceEditController' => 'NuanceSourceController', 'NuanceSourceEditEngine' => 'PhabricatorEditEngine', 'NuanceSourceEditor' => 'PhabricatorApplicationTransactionEditor', 'NuanceSourceListController' => 'NuanceSourceController', 'NuanceSourceManageCapability' => 'PhabricatorPolicyCapability', 'NuanceSourceNameNgrams' => 'PhabricatorSearchNgrams', 'NuanceSourcePHIDType' => 'PhabricatorPHIDType', 'NuanceSourceQuery' => 'NuanceQuery', 'NuanceSourceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'NuanceSourceTransaction' => 'NuanceTransaction', 'NuanceSourceTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceSourceViewController' => 'NuanceSourceController', 'NuanceTransaction' => 'PhabricatorApplicationTransaction', 'NuanceWorker' => 'PhabricatorWorker', 'OwnersConduitAPIMethod' => 'ConduitAPIMethod', 'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler', 'OwnersQueryConduitAPIMethod' => 'OwnersConduitAPIMethod', 'OwnersSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PHIDConduitAPIMethod' => 'ConduitAPIMethod', 'PHIDInfoConduitAPIMethod' => 'PHIDConduitAPIMethod', 'PHIDLookupConduitAPIMethod' => 'PHIDConduitAPIMethod', 'PHIDQueryConduitAPIMethod' => 'PHIDConduitAPIMethod', 'PHUI' => 'Phobject', 'PHUIActionPanelExample' => 'PhabricatorUIExample', 'PHUIActionPanelView' => 'AphrontTagView', 'PHUIApplicationMenuView' => 'Phobject', 'PHUIBadgeBoxView' => 'AphrontTagView', 'PHUIBadgeExample' => 'PhabricatorUIExample', 'PHUIBadgeMiniView' => 'AphrontTagView', 'PHUIBadgeView' => 'AphrontTagView', 'PHUIBigInfoView' => 'AphrontTagView', 'PHUIBoxExample' => 'PhabricatorUIExample', 'PHUIBoxView' => 'AphrontTagView', 'PHUIButtonBarExample' => 'PhabricatorUIExample', 'PHUIButtonBarView' => 'AphrontTagView', 'PHUIButtonExample' => 'PhabricatorUIExample', 'PHUIButtonView' => 'AphrontTagView', 'PHUICMSView' => 'AphrontTagView', 'PHUICalendarDayView' => 'AphrontView', 'PHUICalendarListView' => 'AphrontTagView', 'PHUICalendarMonthView' => 'AphrontView', 'PHUICalendarWeekView' => 'AphrontView', 'PHUICalendarWidgetView' => 'AphrontTagView', 'PHUIColorPalletteExample' => 'PhabricatorUIExample', 'PHUICrumbView' => 'AphrontView', 'PHUICrumbsView' => 'AphrontView', 'PHUICurtainExtension' => 'Phobject', 'PHUICurtainPanelView' => 'AphrontTagView', 'PHUICurtainView' => 'AphrontTagView', 'PHUIDiffGraphView' => 'Phobject', 'PHUIDiffGraphViewTestCase' => 'PhabricatorTestCase', 'PHUIDiffInlineCommentDetailView' => 'PHUIDiffInlineCommentView', 'PHUIDiffInlineCommentEditView' => 'PHUIDiffInlineCommentView', 'PHUIDiffInlineCommentRowScaffold' => 'AphrontView', 'PHUIDiffInlineCommentTableScaffold' => 'AphrontView', 'PHUIDiffInlineCommentUndoView' => 'PHUIDiffInlineCommentView', 'PHUIDiffInlineCommentView' => 'AphrontView', 'PHUIDiffOneUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold', 'PHUIDiffRevealIconView' => 'AphrontView', 'PHUIDiffTableOfContentsItemView' => 'AphrontView', 'PHUIDiffTableOfContentsListView' => 'AphrontView', 'PHUIDiffTwoUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold', 'PHUIDocumentSummaryView' => 'AphrontTagView', 'PHUIDocumentViewPro' => 'AphrontTagView', 'PHUIFeedStoryExample' => 'PhabricatorUIExample', 'PHUIFeedStoryView' => 'AphrontView', 'PHUIFormDividerControl' => 'AphrontFormControl', 'PHUIFormFileControl' => 'AphrontFormControl', 'PHUIFormFreeformDateControl' => 'AphrontFormControl', 'PHUIFormIconSetControl' => 'AphrontFormControl', 'PHUIFormInsetView' => 'AphrontView', 'PHUIFormLayoutView' => 'AphrontView', 'PHUIFormNumberControl' => 'AphrontFormControl', 'PHUIHandleListView' => 'AphrontTagView', 'PHUIHandleTagListView' => 'AphrontTagView', 'PHUIHandleView' => 'AphrontView', 'PHUIHeadThingView' => 'AphrontTagView', 'PHUIHeaderView' => 'AphrontTagView', 'PHUIHovercardUIExample' => 'PhabricatorUIExample', 'PHUIHovercardView' => 'AphrontTagView', 'PHUIIconCircleView' => 'AphrontTagView', 'PHUIIconExample' => 'PhabricatorUIExample', 'PHUIIconView' => 'AphrontTagView', 'PHUIImageMaskExample' => 'PhabricatorUIExample', 'PHUIImageMaskView' => 'AphrontTagView', 'PHUIInfoExample' => 'PhabricatorUIExample', 'PHUIInfoPanelExample' => 'PhabricatorUIExample', 'PHUIInfoPanelView' => 'AphrontView', 'PHUIInfoView' => 'AphrontView', 'PHUIInvisibleCharacterTestCase' => 'PhabricatorTestCase', 'PHUIInvisibleCharacterView' => 'AphrontView', 'PHUIListExample' => 'PhabricatorUIExample', 'PHUIListItemView' => 'AphrontTagView', 'PHUIListView' => 'AphrontTagView', 'PHUIListViewTestCase' => 'PhabricatorTestCase', 'PHUIMainMenuView' => 'AphrontView', 'PHUIObjectBoxView' => 'AphrontTagView', 'PHUIObjectItemListExample' => 'PhabricatorUIExample', 'PHUIObjectItemListView' => 'AphrontTagView', 'PHUIObjectItemView' => 'AphrontTagView', 'PHUIPagerView' => 'AphrontView', 'PHUIPinboardItemView' => 'AphrontView', 'PHUIPinboardView' => 'AphrontView', 'PHUIPropertyGroupView' => 'AphrontTagView', 'PHUIPropertyListExample' => 'PhabricatorUIExample', 'PHUIPropertyListView' => 'AphrontView', 'PHUIRemarkupPreviewPanel' => 'AphrontTagView', 'PHUIRemarkupView' => 'AphrontView', 'PHUISegmentBarSegmentView' => 'AphrontTagView', 'PHUISegmentBarView' => 'AphrontTagView', 'PHUISpacesNamespaceContextView' => 'AphrontView', 'PHUIStatusItemView' => 'AphrontTagView', 'PHUIStatusListView' => 'AphrontTagView', 'PHUITabGroupView' => 'AphrontTagView', 'PHUITabView' => 'AphrontTagView', 'PHUITagExample' => 'PhabricatorUIExample', 'PHUITagView' => 'AphrontTagView', 'PHUITimelineEventView' => 'AphrontView', 'PHUITimelineExample' => 'PhabricatorUIExample', 'PHUITimelineView' => 'AphrontView', 'PHUITwoColumnView' => 'AphrontTagView', 'PHUITypeaheadExample' => 'PhabricatorUIExample', 'PHUIWorkboardView' => 'AphrontTagView', 'PHUIWorkpanelView' => 'AphrontTagView', 'PassphraseAbstractKey' => 'Phobject', 'PassphraseConduitAPIMethod' => 'ConduitAPIMethod', 'PassphraseController' => 'PhabricatorController', 'PassphraseCredential' => array( 'PassphraseDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorSubscribableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSpacesInterface', 'PhabricatorFulltextInterface', ), 'PassphraseCredentialAuthorPolicyRule' => 'PhabricatorPolicyRule', 'PassphraseCredentialConduitController' => 'PassphraseController', 'PassphraseCredentialControl' => 'AphrontFormControl', 'PassphraseCredentialCreateController' => 'PassphraseController', 'PassphraseCredentialDestroyController' => 'PassphraseController', 'PassphraseCredentialEditController' => 'PassphraseController', 'PassphraseCredentialFulltextEngine' => 'PhabricatorFulltextEngine', 'PassphraseCredentialListController' => 'PassphraseController', 'PassphraseCredentialLockController' => 'PassphraseController', 'PassphraseCredentialPHIDType' => 'PhabricatorPHIDType', 'PassphraseCredentialPublicController' => 'PassphraseController', 'PassphraseCredentialQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PassphraseCredentialRevealController' => 'PassphraseController', 'PassphraseCredentialSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PassphraseCredentialTransaction' => 'PhabricatorApplicationTransaction', 'PassphraseCredentialTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PassphraseCredentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PassphraseCredentialType' => 'Phobject', 'PassphraseCredentialTypeTestCase' => 'PhabricatorTestCase', 'PassphraseCredentialViewController' => 'PassphraseController', 'PassphraseDAO' => 'PhabricatorLiskDAO', 'PassphraseDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PassphraseDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PassphraseNoteCredentialType' => 'PassphraseCredentialType', 'PassphrasePasswordCredentialType' => 'PassphraseCredentialType', 'PassphrasePasswordKey' => 'PassphraseAbstractKey', 'PassphraseQueryConduitAPIMethod' => 'PassphraseConduitAPIMethod', 'PassphraseRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PassphraseSSHGeneratedKeyCredentialType' => 'PassphraseSSHPrivateKeyCredentialType', 'PassphraseSSHKey' => 'PassphraseAbstractKey', 'PassphraseSSHPrivateKeyCredentialType' => 'PassphraseCredentialType', 'PassphraseSSHPrivateKeyFileCredentialType' => 'PassphraseSSHPrivateKeyCredentialType', 'PassphraseSSHPrivateKeyTextCredentialType' => 'PassphraseSSHPrivateKeyCredentialType', 'PassphraseSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PassphraseSecret' => 'PassphraseDAO', 'PassphraseTokenCredentialType' => 'PassphraseCredentialType', 'PasteConduitAPIMethod' => 'ConduitAPIMethod', 'PasteCreateConduitAPIMethod' => 'PasteConduitAPIMethod', 'PasteCreateMailReceiver' => 'PhabricatorMailReceiver', 'PasteDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PasteDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PasteEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PasteEmbedView' => 'AphrontView', 'PasteInfoConduitAPIMethod' => 'PasteConduitAPIMethod', 'PasteLanguageSelectDatasource' => 'PhabricatorTypeaheadDatasource', 'PasteMailReceiver' => 'PhabricatorObjectMailReceiver', 'PasteQueryConduitAPIMethod' => 'PasteConduitAPIMethod', 'PasteReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PasteSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PeopleBrowseUserDirectoryCapability' => 'PhabricatorPolicyCapability', 'PeopleCreateUsersCapability' => 'PhabricatorPolicyCapability', 'PeopleHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', 'PeopleUserLogGarbageCollector' => 'PhabricatorGarbageCollector', 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAWSConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAccessControlTestCase' => 'PhabricatorTestCase', 'PhabricatorAccessLog' => 'Phobject', 'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAccessibilitySetting' => 'PhabricatorSelectSetting', 'PhabricatorAccountSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorActionListView' => 'AphrontView', 'PhabricatorActionView' => 'AphrontView', 'PhabricatorActivitySettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorAdministratorsPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorAjaxRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorAlmanacApplication' => 'PhabricatorApplication', 'PhabricatorAmazonAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorAnchorView' => 'AphrontView', 'PhabricatorAphlictManagementDebugWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementRestartWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementStartWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementStatusWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementStopWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorAphlictSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorAphrontBarUIExample' => 'PhabricatorUIExample', 'PhabricatorAphrontViewTestCase' => 'PhabricatorTestCase', 'PhabricatorAppSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorApplication' => array( 'Phobject', 'PhabricatorPolicyInterface', ), 'PhabricatorApplicationApplicationPHIDType' => 'PhabricatorPHIDType', 'PhabricatorApplicationConfigOptions' => 'Phobject', 'PhabricatorApplicationConfigurationPanel' => 'Phobject', 'PhabricatorApplicationConfigurationPanelTestCase' => 'PhabricatorTestCase', 'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationEditHTTPParameterHelpView' => 'AphrontView', 'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationLaunchView' => 'AphrontTagView', 'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorApplicationSearchEngine' => 'Phobject', 'PhabricatorApplicationSearchEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorApplicationSearchResultView' => 'Phobject', 'PhabricatorApplicationStatusView' => 'AphrontView', 'PhabricatorApplicationTestCase' => 'PhabricatorTestCase', 'PhabricatorApplicationTransaction' => array( 'PhabricatorLiskDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorApplicationTransactionComment' => array( 'PhabricatorLiskDAO', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorApplicationTransactionCommentEditController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionCommentHistoryController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationTransactionCommentQuoteController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentRawController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentRemoveController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentView' => 'AphrontView', 'PhabricatorApplicationTransactionController' => 'PhabricatorController', 'PhabricatorApplicationTransactionDetailController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory', 'PhabricatorApplicationTransactionNoEffectException' => 'Exception', 'PhabricatorApplicationTransactionNoEffectResponse' => 'AphrontProxyResponse', 'PhabricatorApplicationTransactionPublishWorker' => 'PhabricatorWorker', 'PhabricatorApplicationTransactionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationTransactionRemarkupPreviewController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorApplicationTransactionResponse' => 'AphrontProxyResponse', 'PhabricatorApplicationTransactionShowOlderController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionStructureException' => 'Exception', 'PhabricatorApplicationTransactionTemplatedCommentQuery' => 'PhabricatorApplicationTransactionCommentQuery', 'PhabricatorApplicationTransactionTextDiffDetailView' => 'AphrontView', 'PhabricatorApplicationTransactionTransactionPHIDType' => 'PhabricatorPHIDType', 'PhabricatorApplicationTransactionValidationError' => 'Phobject', 'PhabricatorApplicationTransactionValidationException' => 'Exception', 'PhabricatorApplicationTransactionValidationResponse' => 'AphrontProxyResponse', 'PhabricatorApplicationTransactionValueController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionView' => 'AphrontView', 'PhabricatorApplicationUninstallController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationsApplication' => 'PhabricatorApplication', 'PhabricatorApplicationsController' => 'PhabricatorController', 'PhabricatorApplicationsListController' => 'PhabricatorApplicationsController', 'PhabricatorAsanaAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorAsanaConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAsanaSubtaskHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorAsanaTaskHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorAuditActionConstants' => 'Phobject', 'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController', 'PhabricatorAuditApplication' => 'PhabricatorApplication', 'PhabricatorAuditCommentEditor' => 'PhabricatorEditor', 'PhabricatorAuditCommitStatusConstants' => 'Phobject', 'PhabricatorAuditController' => 'PhabricatorController', 'PhabricatorAuditEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorAuditInlineComment' => array( 'Phobject', 'PhabricatorInlineCommentInterface', ), 'PhabricatorAuditListController' => 'PhabricatorAuditController', 'PhabricatorAuditListView' => 'AphrontView', 'PhabricatorAuditMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorAuditManagementDeleteWorkflow' => 'PhabricatorAuditManagementWorkflow', 'PhabricatorAuditManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorAuditPreviewController' => 'PhabricatorAuditController', 'PhabricatorAuditReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorAuditStatusConstants' => 'Phobject', 'PhabricatorAuditTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorAuditTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorAuditTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorAuditTransactionView' => 'PhabricatorApplicationTransactionView', 'PhabricatorAuthAccountView' => 'AphrontView', 'PhabricatorAuthApplication' => 'PhabricatorApplication', 'PhabricatorAuthAuthFactorPHIDType' => 'PhabricatorPHIDType', 'PhabricatorAuthAuthProviderPHIDType' => 'PhabricatorPHIDType', 'PhabricatorAuthConduitAPIMethod' => 'ConduitAPIMethod', 'PhabricatorAuthConfirmLinkController' => 'PhabricatorAuthController', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorAuthDAO' => 'PhabricatorLiskDAO', 'PhabricatorAuthDisableController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthDowngradeSessionController' => 'PhabricatorAuthController', 'PhabricatorAuthEditController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthFactor' => 'Phobject', 'PhabricatorAuthFactorConfig' => 'PhabricatorAuthDAO', 'PhabricatorAuthFactorTestCase' => 'PhabricatorTestCase', 'PhabricatorAuthFinishController' => 'PhabricatorAuthController', 'PhabricatorAuthHighSecurityRequiredException' => 'Exception', 'PhabricatorAuthHighSecurityToken' => 'Phobject', 'PhabricatorAuthInvite' => array( 'PhabricatorUserDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorAuthInviteAccountException' => 'PhabricatorAuthInviteDialogException', 'PhabricatorAuthInviteAction' => 'Phobject', 'PhabricatorAuthInviteActionTableView' => 'AphrontView', 'PhabricatorAuthInviteController' => 'PhabricatorAuthController', 'PhabricatorAuthInviteDialogException' => 'PhabricatorAuthInviteException', 'PhabricatorAuthInviteEngine' => 'Phobject', 'PhabricatorAuthInviteException' => 'Exception', 'PhabricatorAuthInviteInvalidException' => 'PhabricatorAuthInviteDialogException', 'PhabricatorAuthInviteLoginException' => 'PhabricatorAuthInviteDialogException', 'PhabricatorAuthInvitePHIDType' => 'PhabricatorPHIDType', 'PhabricatorAuthInviteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthInviteRegisteredException' => 'PhabricatorAuthInviteException', 'PhabricatorAuthInviteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorAuthInviteTestCase' => 'PhabricatorTestCase', 'PhabricatorAuthInviteVerifyException' => 'PhabricatorAuthInviteDialogException', 'PhabricatorAuthInviteWorker' => 'PhabricatorWorker', 'PhabricatorAuthLinkController' => 'PhabricatorAuthController', 'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthLoginController' => 'PhabricatorAuthController', 'PhabricatorAuthLoginHandler' => 'Phobject', 'PhabricatorAuthLogoutConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod', 'PhabricatorAuthMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorAuthManagementCachePKCS8Workflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementStripWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementTrustOAuthClientWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementUnlimitWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementUntrustOAuthClientWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementVerifyWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorAuthNeedsApprovalController' => 'PhabricatorAuthController', 'PhabricatorAuthNeedsMultiFactorController' => 'PhabricatorAuthController', 'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController', 'PhabricatorAuthOneTimeLoginController' => 'PhabricatorAuthController', 'PhabricatorAuthOneTimeLoginTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType', 'PhabricatorAuthPasswordResetTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType', 'PhabricatorAuthProvider' => 'Phobject', 'PhabricatorAuthProviderConfig' => array( 'PhabricatorAuthDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), 'PhabricatorAuthProviderConfigController' => 'PhabricatorAuthController', 'PhabricatorAuthProviderConfigEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorAuthProviderConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthProviderConfigTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorAuthProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorAuthQueryPublicKeysConduitAPIMethod' => 'PhabricatorAuthConduitAPIMethod', 'PhabricatorAuthRegisterController' => 'PhabricatorAuthController', 'PhabricatorAuthRevokeTokenController' => 'PhabricatorAuthController', 'PhabricatorAuthSSHKey' => array( 'PhabricatorAuthDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', ), 'PhabricatorAuthSSHKeyController' => 'PhabricatorAuthController', 'PhabricatorAuthSSHKeyDeactivateController' => 'PhabricatorAuthSSHKeyController', 'PhabricatorAuthSSHKeyEditController' => 'PhabricatorAuthSSHKeyController', 'PhabricatorAuthSSHKeyEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorAuthSSHKeyGenerateController' => 'PhabricatorAuthSSHKeyController', 'PhabricatorAuthSSHKeyListController' => 'PhabricatorAuthSSHKeyController', 'PhabricatorAuthSSHKeyPHIDType' => 'PhabricatorPHIDType', 'PhabricatorAuthSSHKeyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthSSHKeyReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorAuthSSHKeySearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorAuthSSHKeyTableView' => 'AphrontView', 'PhabricatorAuthSSHKeyTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorAuthSSHKeyTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorAuthSSHKeyViewController' => 'PhabricatorAuthSSHKeyController', 'PhabricatorAuthSSHPublicKey' => 'Phobject', 'PhabricatorAuthSession' => array( 'PhabricatorAuthDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorAuthSessionEngine' => 'Phobject', 'PhabricatorAuthSessionEngineExtension' => 'Phobject', 'PhabricatorAuthSessionEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorAuthSessionGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorAuthStartController' => 'PhabricatorAuthController', 'PhabricatorAuthTOTPKeyTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType', 'PhabricatorAuthTemporaryToken' => array( 'PhabricatorAuthDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorAuthTemporaryTokenGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorAuthTemporaryTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthTemporaryTokenType' => 'Phobject', 'PhabricatorAuthTemporaryTokenTypeModule' => 'PhabricatorConfigModule', 'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController', 'PhabricatorAuthTryFactorAction' => 'PhabricatorSystemAction', 'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController', 'PhabricatorAuthValidateController' => 'PhabricatorAuthController', 'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAutoEventListener' => 'PhabricatorEventListener', 'PhabricatorBadgeHasRecipientEdgeType' => 'PhabricatorEdgeType', 'PhabricatorBadgesApplication' => 'PhabricatorApplication', 'PhabricatorBadgesArchiveController' => 'PhabricatorBadgesController', 'PhabricatorBadgesAward' => array( 'PhabricatorBadgesDAO', 'PhabricatorDestructibleInterface', 'PhabricatorPolicyInterface', ), 'PhabricatorBadgesAwardController' => 'PhabricatorBadgesController', 'PhabricatorBadgesAwardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorBadgesBadge' => array( 'PhabricatorBadgesDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorConduitResultInterface', 'PhabricatorNgramsInterface', ), 'PhabricatorBadgesBadgeNameNgrams' => 'PhabricatorSearchNgrams', 'PhabricatorBadgesCommentController' => 'PhabricatorBadgesController', 'PhabricatorBadgesController' => 'PhabricatorController', 'PhabricatorBadgesCreateCapability' => 'PhabricatorPolicyCapability', 'PhabricatorBadgesDAO' => 'PhabricatorLiskDAO', 'PhabricatorBadgesDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorBadgesDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PhabricatorBadgesEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorBadgesEditController' => 'PhabricatorBadgesController', 'PhabricatorBadgesEditEngine' => 'PhabricatorEditEngine', 'PhabricatorBadgesEditRecipientsController' => 'PhabricatorBadgesController', 'PhabricatorBadgesEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorBadgesIconSet' => 'PhabricatorIconSet', 'PhabricatorBadgesListController' => 'PhabricatorBadgesController', 'PhabricatorBadgesMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorBadgesPHIDType' => 'PhabricatorPHIDType', 'PhabricatorBadgesQuality' => 'Phobject', 'PhabricatorBadgesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorBadgesRecipientsListView' => 'AphrontView', 'PhabricatorBadgesRemoveRecipientsController' => 'PhabricatorBadgesController', 'PhabricatorBadgesReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorBadgesSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorBadgesSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorBadgesSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorBadgesTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorBadgesTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorBadgesTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorBadgesViewController' => 'PhabricatorBadgesController', 'PhabricatorBarePageUIExample' => 'PhabricatorUIExample', 'PhabricatorBarePageView' => 'AphrontPageView', 'PhabricatorBaseURISetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorBcryptPasswordHasher' => 'PhabricatorPasswordHasher', 'PhabricatorBinariesSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorBitbucketAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorBoardLayoutEngine' => 'Phobject', 'PhabricatorBoardRenderingEngine' => 'Phobject', 'PhabricatorBoardResponseEngine' => 'Phobject', 'PhabricatorBoolEditField' => 'PhabricatorEditField', 'PhabricatorBot' => 'PhabricatorDaemon', 'PhabricatorBotChannel' => 'PhabricatorBotTarget', 'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFeedNotificationHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFlowdockProtocolAdapter' => 'PhabricatorStreamingProtocolAdapter', 'PhabricatorBotHandler' => 'Phobject', 'PhabricatorBotLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotMacroHandler' => 'PhabricatorBotHandler', 'PhabricatorBotMessage' => 'Phobject', 'PhabricatorBotObjectNameHandler' => 'PhabricatorBotHandler', 'PhabricatorBotSymbolHandler' => 'PhabricatorBotHandler', 'PhabricatorBotTarget' => 'Phobject', 'PhabricatorBotUser' => 'PhabricatorBotTarget', 'PhabricatorBotWhatsNewHandler' => 'PhabricatorBotHandler', 'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation', 'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList', 'PhabricatorBulkContentSource' => 'PhabricatorContentSource', 'PhabricatorBusyUIExample' => 'PhabricatorUIExample', 'PhabricatorCacheDAO' => 'PhabricatorLiskDAO', 'PhabricatorCacheGeneralGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorCacheManagementPurgeWorkflow' => 'PhabricatorCacheManagementWorkflow', 'PhabricatorCacheManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorCacheMarkupGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorCacheSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorCacheSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorCacheSpec' => 'Phobject', 'PhabricatorCacheTTLGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorCaches' => 'Phobject', 'PhabricatorCachesTestCase' => 'PhabricatorTestCase', 'PhabricatorCalendarApplication' => 'PhabricatorApplication', 'PhabricatorCalendarController' => 'PhabricatorController', 'PhabricatorCalendarDAO' => 'PhabricatorLiskDAO', 'PhabricatorCalendarEvent' => array( 'PhabricatorCalendarDAO', 'PhabricatorPolicyInterface', + 'PhabricatorExtendedPolicyInterface', 'PhabricatorProjectInterface', 'PhabricatorMarkupInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorDestructibleInterface', 'PhabricatorMentionableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorSpacesInterface', 'PhabricatorFulltextInterface', 'PhabricatorConduitResultInterface', ), 'PhabricatorCalendarEventAcceptTransaction' => 'PhabricatorCalendarEventReplyTransaction', 'PhabricatorCalendarEventAllDayTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventCancelTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventDateTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventDeclineTransaction' => 'PhabricatorCalendarEventReplyTransaction', 'PhabricatorCalendarEventDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PhabricatorCalendarEventDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PhabricatorCalendarEventDescriptionTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventDragController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditEngine' => 'PhabricatorEditEngine', 'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand', 'PhabricatorCalendarEventEndDateTransaction' => 'PhabricatorCalendarEventDateTransaction', 'PhabricatorCalendarEventExportController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventFrequencyTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorCalendarEventHeraldAdapter' => 'HeraldAdapter', 'PhabricatorCalendarEventHeraldField' => 'HeraldField', 'PhabricatorCalendarEventHeraldFieldGroup' => 'HeraldFieldGroup', 'PhabricatorCalendarEventHostPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorCalendarEventHostTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventIconTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventInviteTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventInvitee' => array( 'PhabricatorCalendarDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorCalendarEventInviteeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCalendarEventInviteesPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorCalendarEventJoinController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorCalendarEventNameHeraldField' => 'PhabricatorCalendarEventHeraldField', 'PhabricatorCalendarEventNameTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCalendarEventRSVPEmailCommand' => 'PhabricatorCalendarEventEmailCommand', 'PhabricatorCalendarEventRecurringTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventReplyTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCalendarEventStartDateTransaction' => 'PhabricatorCalendarEventDateTransaction', 'PhabricatorCalendarEventTransaction' => 'PhabricatorModularTransaction', 'PhabricatorCalendarEventTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorCalendarEventTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorCalendarEventTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorCalendarEventUntilDateTransaction' => 'PhabricatorCalendarEventDateTransaction', 'PhabricatorCalendarEventViewController' => 'PhabricatorCalendarController', 'PhabricatorCalendarExport' => array( 'PhabricatorCalendarDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorCalendarExportDisableController' => 'PhabricatorCalendarController', 'PhabricatorCalendarExportDisableTransaction' => 'PhabricatorCalendarExportTransactionType', 'PhabricatorCalendarExportEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarExportEditEngine' => 'PhabricatorEditEngine', 'PhabricatorCalendarExportEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorCalendarExportICSController' => 'PhabricatorCalendarController', 'PhabricatorCalendarExportListController' => 'PhabricatorCalendarController', 'PhabricatorCalendarExportModeTransaction' => 'PhabricatorCalendarExportTransactionType', 'PhabricatorCalendarExportNameTransaction' => 'PhabricatorCalendarExportTransactionType', 'PhabricatorCalendarExportPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCalendarExportQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCalendarExportQueryKeyTransaction' => 'PhabricatorCalendarExportTransactionType', 'PhabricatorCalendarExportSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCalendarExportTransaction' => 'PhabricatorModularTransaction', 'PhabricatorCalendarExportTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorCalendarExportTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorCalendarExportViewController' => 'PhabricatorCalendarController', 'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO', 'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase', + 'PhabricatorCalendarICSFileImportEngine' => 'PhabricatorCalendarICSImportEngine', + 'PhabricatorCalendarICSImportEngine' => 'PhabricatorCalendarImportEngine', + 'PhabricatorCalendarICSURIImportEngine' => 'PhabricatorCalendarICSImportEngine', 'PhabricatorCalendarICSWriter' => 'Phobject', 'PhabricatorCalendarIconSet' => 'PhabricatorIconSet', + 'PhabricatorCalendarImport' => array( + 'PhabricatorCalendarDAO', + 'PhabricatorPolicyInterface', + 'PhabricatorApplicationTransactionInterface', + 'PhabricatorDestructibleInterface', + ), + 'PhabricatorCalendarImportDefaultLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportDeleteController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarImportDeleteTransaction' => 'PhabricatorCalendarImportTransactionType', + 'PhabricatorCalendarImportDisableController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarImportDisableTransaction' => 'PhabricatorCalendarImportTransactionType', + 'PhabricatorCalendarImportDropController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarImportDuplicateLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportEditController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarImportEditEngine' => 'PhabricatorEditEngine', + 'PhabricatorCalendarImportEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorCalendarImportEmptyLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportEngine' => 'Phobject', + 'PhabricatorCalendarImportEpochLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportFetchLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportFrequencyLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportICSFileTransaction' => 'PhabricatorCalendarImportTransactionType', + 'PhabricatorCalendarImportICSLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportICSURITransaction' => 'PhabricatorCalendarImportTransactionType', + 'PhabricatorCalendarImportIgnoredNodeLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportListController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarImportLog' => array( + 'PhabricatorCalendarDAO', + 'PhabricatorPolicyInterface', + 'PhabricatorDestructibleInterface', + ), + 'PhabricatorCalendarImportLogListController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarImportLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorCalendarImportLogSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'PhabricatorCalendarImportLogType' => 'Phobject', + 'PhabricatorCalendarImportLogView' => 'AphrontView', + 'PhabricatorCalendarImportNameTransaction' => 'PhabricatorCalendarImportTransactionType', + 'PhabricatorCalendarImportOriginalLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportOrphanLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportPHIDType' => 'PhabricatorPHIDType', + 'PhabricatorCalendarImportQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorCalendarImportSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'PhabricatorCalendarImportTransaction' => 'PhabricatorModularTransaction', + 'PhabricatorCalendarImportTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorCalendarImportTransactionType' => 'PhabricatorModularTransactionType', + 'PhabricatorCalendarImportUpdateLogType' => 'PhabricatorCalendarImportLogType', + 'PhabricatorCalendarImportViewController' => 'PhabricatorCalendarController', 'PhabricatorCalendarRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorCalendarReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorCalendarSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorCampfireProtocolAdapter' => 'PhabricatorStreamingProtocolAdapter', 'PhabricatorCelerityApplication' => 'PhabricatorApplication', 'PhabricatorCelerityTestCase' => 'PhabricatorTestCase', 'PhabricatorChangeParserTestCase' => 'PhabricatorWorkingCopyTestCase', 'PhabricatorChangesetResponse' => 'AphrontProxyResponse', 'PhabricatorChatLogApplication' => 'PhabricatorApplication', 'PhabricatorChatLogChannel' => array( 'PhabricatorChatLogDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorChatLogChannelListController' => 'PhabricatorChatLogController', 'PhabricatorChatLogChannelLogController' => 'PhabricatorChatLogController', 'PhabricatorChatLogChannelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorChatLogController' => 'PhabricatorController', 'PhabricatorChatLogDAO' => 'PhabricatorLiskDAO', 'PhabricatorChatLogEvent' => array( 'PhabricatorChatLogDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorChunkedFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorClusterConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorClusterDatabasesConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorClusterException' => 'Exception', 'PhabricatorClusterExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorClusterImpossibleWriteException' => 'PhabricatorClusterException', 'PhabricatorClusterImproperWriteException' => 'PhabricatorClusterException', 'PhabricatorClusterStrandedException' => 'PhabricatorClusterException', 'PhabricatorColumnsEditField' => 'PhabricatorPHIDListEditField', 'PhabricatorCommentEditEngineExtension' => 'PhabricatorEditEngineExtension', 'PhabricatorCommentEditField' => 'PhabricatorEditField', 'PhabricatorCommentEditType' => 'PhabricatorEditType', 'PhabricatorCommitBranchesField' => 'PhabricatorCommitCustomField', 'PhabricatorCommitCustomField' => 'PhabricatorCustomField', 'PhabricatorCommitMergedCommitsField' => 'PhabricatorCommitCustomField', 'PhabricatorCommitRepositoryField' => 'PhabricatorCommitCustomField', 'PhabricatorCommitSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCommitTagsField' => 'PhabricatorCommitCustomField', 'PhabricatorCommonPasswords' => 'Phobject', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitApplication' => 'PhabricatorApplication', 'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitContentSource' => 'PhabricatorContentSource', 'PhabricatorConduitController' => 'PhabricatorController', 'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', 'PhabricatorConduitEditField' => 'PhabricatorEditField', 'PhabricatorConduitListController' => 'PhabricatorConduitController', 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConduitLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorConduitMethodCallLog' => array( 'PhabricatorConduitDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorConduitMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConduitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorConduitResultInterface' => 'PhabricatorPHIDInterface', 'PhabricatorConduitSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorConduitSearchFieldSpecification' => 'Phobject', 'PhabricatorConduitTestCase' => 'PhabricatorTestCase', 'PhabricatorConduitToken' => array( 'PhabricatorConduitDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorConduitTokenController' => 'PhabricatorConduitController', 'PhabricatorConduitTokenEditController' => 'PhabricatorConduitController', 'PhabricatorConduitTokenHandshakeController' => 'PhabricatorConduitController', 'PhabricatorConduitTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConduitTokenTerminateController' => 'PhabricatorConduitController', 'PhabricatorConduitTokensSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorConfigAllController' => 'PhabricatorConfigController', 'PhabricatorConfigApplication' => 'PhabricatorApplication', 'PhabricatorConfigApplicationController' => 'PhabricatorConfigController', 'PhabricatorConfigCacheController' => 'PhabricatorConfigController', 'PhabricatorConfigClusterDatabasesController' => 'PhabricatorConfigController', 'PhabricatorConfigClusterNotificationsController' => 'PhabricatorConfigController', 'PhabricatorConfigClusterRepositoriesController' => 'PhabricatorConfigController', 'PhabricatorConfigCollectorsModule' => 'PhabricatorConfigModule', 'PhabricatorConfigColumnSchema' => 'PhabricatorConfigStorageSchema', 'PhabricatorConfigConfigPHIDType' => 'PhabricatorPHIDType', 'PhabricatorConfigConstants' => 'Phobject', 'PhabricatorConfigController' => 'PhabricatorController', 'PhabricatorConfigCoreSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorConfigDatabaseController' => 'PhabricatorConfigController', 'PhabricatorConfigDatabaseIssueController' => 'PhabricatorConfigDatabaseController', 'PhabricatorConfigDatabaseSchema' => 'PhabricatorConfigStorageSchema', 'PhabricatorConfigDatabaseSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigDatabaseStatusController' => 'PhabricatorConfigDatabaseController', 'PhabricatorConfigDefaultSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigDictionarySource' => 'PhabricatorConfigSource', 'PhabricatorConfigEdgeModule' => 'PhabricatorConfigModule', 'PhabricatorConfigEditController' => 'PhabricatorConfigController', 'PhabricatorConfigEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorConfigEntry' => array( 'PhabricatorConfigEntryDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), 'PhabricatorConfigEntryDAO' => 'PhabricatorLiskDAO', 'PhabricatorConfigEntryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigGroupConstants' => 'PhabricatorConfigConstants', 'PhabricatorConfigGroupController' => 'PhabricatorConfigController', 'PhabricatorConfigHTTPParameterTypesModule' => 'PhabricatorConfigModule', 'PhabricatorConfigHistoryController' => 'PhabricatorConfigController', 'PhabricatorConfigIgnoreController' => 'PhabricatorConfigController', 'PhabricatorConfigIssueListController' => 'PhabricatorConfigController', 'PhabricatorConfigIssuePanelController' => 'PhabricatorConfigController', 'PhabricatorConfigIssueViewController' => 'PhabricatorConfigController', 'PhabricatorConfigJSON' => 'Phobject', 'PhabricatorConfigJSONOptionType' => 'PhabricatorConfigOptionType', 'PhabricatorConfigKeySchema' => 'PhabricatorConfigStorageSchema', 'PhabricatorConfigListController' => 'PhabricatorConfigController', 'PhabricatorConfigLocalSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigManagementDeleteWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementGetWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementListWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementMigrateWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorConfigModule' => 'Phobject', 'PhabricatorConfigModuleController' => 'PhabricatorConfigController', 'PhabricatorConfigOption' => array( 'Phobject', 'PhabricatorMarkupInterface', ), 'PhabricatorConfigOptionType' => 'Phobject', 'PhabricatorConfigPHIDModule' => 'PhabricatorConfigModule', 'PhabricatorConfigPageView' => 'AphrontTagView', 'PhabricatorConfigProxySource' => 'PhabricatorConfigSource', 'PhabricatorConfigPurgeCacheController' => 'PhabricatorConfigController', 'PhabricatorConfigRequestExceptionHandlerModule' => 'PhabricatorConfigModule', 'PhabricatorConfigResponse' => 'AphrontStandaloneHTMLResponse', 'PhabricatorConfigSchemaQuery' => 'Phobject', 'PhabricatorConfigSchemaSpec' => 'Phobject', 'PhabricatorConfigServerSchema' => 'PhabricatorConfigStorageSchema', 'PhabricatorConfigSetupCheckModule' => 'PhabricatorConfigModule', 'PhabricatorConfigSiteModule' => 'PhabricatorConfigModule', 'PhabricatorConfigSiteSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigSource' => 'Phobject', 'PhabricatorConfigStackSource' => 'PhabricatorConfigSource', 'PhabricatorConfigStorageSchema' => 'Phobject', 'PhabricatorConfigTableSchema' => 'PhabricatorConfigStorageSchema', 'PhabricatorConfigTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorConfigValidationException' => 'Exception', 'PhabricatorConfigVersionController' => 'PhabricatorConfigController', 'PhabricatorConpherenceApplication' => 'PhabricatorApplication', 'PhabricatorConpherenceColumnMinimizeSetting' => 'PhabricatorInternalSetting', 'PhabricatorConpherenceColumnVisibleSetting' => 'PhabricatorInternalSetting', 'PhabricatorConpherenceNotificationsSetting' => 'PhabricatorSelectSetting', 'PhabricatorConpherencePreferencesSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorConpherenceThreadPHIDType' => 'PhabricatorPHIDType', 'PhabricatorConpherenceWidgetVisibleSetting' => 'PhabricatorInternalSetting', 'PhabricatorConsoleApplication' => 'PhabricatorApplication', 'PhabricatorConsoleContentSource' => 'PhabricatorContentSource', 'PhabricatorContentSource' => 'Phobject', 'PhabricatorContentSourceModule' => 'PhabricatorConfigModule', 'PhabricatorContentSourceView' => 'AphrontView', 'PhabricatorContributedToObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorController' => 'AphrontController', 'PhabricatorCookies' => 'Phobject', 'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorCoreCreateTransaction' => 'PhabricatorCoreTransactionType', 'PhabricatorCoreTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorCoreVoidTransaction' => 'PhabricatorModularTransactionType', 'PhabricatorCountdown' => array( 'PhabricatorCountdownDAO', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorSubscribableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorSpacesInterface', 'PhabricatorProjectInterface', ), 'PhabricatorCountdownApplication' => 'PhabricatorApplication', 'PhabricatorCountdownController' => 'PhabricatorController', 'PhabricatorCountdownCountdownPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', 'PhabricatorCountdownDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PhabricatorCountdownDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController', 'PhabricatorCountdownEditController' => 'PhabricatorCountdownController', 'PhabricatorCountdownEditEngine' => 'PhabricatorEditEngine', 'PhabricatorCountdownEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorCountdownListController' => 'PhabricatorCountdownController', 'PhabricatorCountdownMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorCountdownQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCountdownRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorCountdownReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorCountdownSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorCountdownSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCountdownTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorCountdownTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorCountdownTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorCountdownView' => 'AphrontView', 'PhabricatorCountdownViewController' => 'PhabricatorCountdownController', 'PhabricatorCursorPagedPolicyAwareQuery' => 'PhabricatorPolicyAwareQuery', 'PhabricatorCustomField' => 'Phobject', 'PhabricatorCustomFieldAttachment' => 'Phobject', 'PhabricatorCustomFieldConfigOptionType' => 'PhabricatorConfigOptionType', 'PhabricatorCustomFieldDataNotAvailableException' => 'Exception', 'PhabricatorCustomFieldEditEngineExtension' => 'PhabricatorEditEngineExtension', 'PhabricatorCustomFieldEditField' => 'PhabricatorEditField', 'PhabricatorCustomFieldEditType' => 'PhabricatorEditType', 'PhabricatorCustomFieldFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorCustomFieldHeraldField' => 'HeraldField', 'PhabricatorCustomFieldHeraldFieldGroup' => 'HeraldFieldGroup', 'PhabricatorCustomFieldImplementationIncompleteException' => 'Exception', 'PhabricatorCustomFieldIndexStorage' => 'PhabricatorLiskDAO', 'PhabricatorCustomFieldList' => 'Phobject', 'PhabricatorCustomFieldMonogramParser' => 'Phobject', 'PhabricatorCustomFieldNotAttachedException' => 'Exception', 'PhabricatorCustomFieldNotProxyException' => 'Exception', 'PhabricatorCustomFieldNumericIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 'PhabricatorCustomFieldSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO', 'PhabricatorCustomFieldStorageQuery' => 'Phobject', 'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 'PhabricatorCustomLogoConfigType' => 'PhabricatorConfigOptionType', 'PhabricatorDaemon' => 'PhutilDaemon', 'PhabricatorDaemonBulkJobController' => 'PhabricatorDaemonController', 'PhabricatorDaemonBulkJobListController' => 'PhabricatorDaemonBulkJobController', 'PhabricatorDaemonBulkJobMonitorController' => 'PhabricatorDaemonBulkJobController', 'PhabricatorDaemonBulkJobViewController' => 'PhabricatorDaemonBulkJobController', 'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController', 'PhabricatorDaemonContentSource' => 'PhabricatorContentSource', 'PhabricatorDaemonController' => 'PhabricatorController', 'PhabricatorDaemonDAO' => 'PhabricatorLiskDAO', 'PhabricatorDaemonEventListener' => 'PhabricatorEventListener', 'PhabricatorDaemonLog' => array( 'PhabricatorDaemonDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorDaemonLogEvent' => 'PhabricatorDaemonDAO', 'PhabricatorDaemonLogEventGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorDaemonLogEventViewController' => 'PhabricatorDaemonController', 'PhabricatorDaemonLogEventsView' => 'AphrontView', 'PhabricatorDaemonLogGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorDaemonLogListController' => 'PhabricatorDaemonController', 'PhabricatorDaemonLogListView' => 'AphrontView', 'PhabricatorDaemonLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController', 'PhabricatorDaemonManagementDebugWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementLaunchWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementListWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementLogWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementReloadWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementRestartWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementStartWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementStatusWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementStopWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorDaemonOverseerModule' => 'PhutilDaemonOverseerModule', 'PhabricatorDaemonReference' => 'Phobject', 'PhabricatorDaemonTaskGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorDaemonTasksTableView' => 'AphrontView', 'PhabricatorDaemonsApplication' => 'PhabricatorApplication', 'PhabricatorDaemonsSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorDailyRoutineTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorDarkConsoleSetting' => 'PhabricatorSelectSetting', 'PhabricatorDarkConsoleTabSetting' => 'PhabricatorInternalSetting', 'PhabricatorDarkConsoleVisibleSetting' => 'PhabricatorInternalSetting', 'PhabricatorDashboard' => array( 'PhabricatorDashboardDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorProjectInterface', ), 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardApplication' => 'PhabricatorApplication', 'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController', 'PhabricatorDashboardController' => 'PhabricatorController', 'PhabricatorDashboardCopyController' => 'PhabricatorDashboardController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', 'PhabricatorDashboardDashboardHasPanelEdgeType' => 'PhabricatorEdgeType', 'PhabricatorDashboardDashboardPHIDType' => 'PhabricatorPHIDType', 'PhabricatorDashboardEditController' => 'PhabricatorDashboardController', 'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO', 'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardLayoutConfig' => 'Phobject', 'PhabricatorDashboardListController' => 'PhabricatorDashboardController', 'PhabricatorDashboardManageController' => 'PhabricatorDashboardController', 'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanel' => array( 'PhabricatorDashboardDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorDashboardPanelArchiveController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelCoreCustomField' => array( 'PhabricatorDashboardPanelCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorDashboardPanelCustomField' => 'PhabricatorCustomField', 'PhabricatorDashboardPanelEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorDashboardPanelEditController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelEditEngine' => 'PhabricatorEditEngine', 'PhabricatorDashboardPanelEditproController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelHasDashboardEdgeType' => 'PhabricatorEdgeType', 'PhabricatorDashboardPanelListController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelPHIDType' => 'PhabricatorPHIDType', 'PhabricatorDashboardPanelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardPanelRenderController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelRenderingEngine' => 'Phobject', 'PhabricatorDashboardPanelSearchApplicationCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorDashboardPanelSearchQueryCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelTabsCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardPanelType' => 'Phobject', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorDashboardRemovePanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardRenderingEngine' => 'Phobject', 'PhabricatorDashboardSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorDashboardTabsPanelType' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardTextPanelType' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardUninstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardViewController' => 'PhabricatorDashboardController', 'PhabricatorDataCacheSpec' => 'PhabricatorCacheSpec', 'PhabricatorDataNotAttachedException' => 'Exception', 'PhabricatorDatabaseHealthRecord' => 'Phobject', 'PhabricatorDatabaseRef' => 'Phobject', 'PhabricatorDatabaseSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorDatasourceEditField' => 'PhabricatorTokenizerEditField', 'PhabricatorDatasourceEditType' => 'PhabricatorPHIDListEditType', 'PhabricatorDateFormatSetting' => 'PhabricatorSelectSetting', 'PhabricatorDateTimeSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorDebugController' => 'PhabricatorController', 'PhabricatorDefaultRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorDefaultSyntaxStyle' => 'PhabricatorSyntaxStyle', 'PhabricatorDesktopNotificationsSetting' => 'PhabricatorInternalSetting', 'PhabricatorDesktopNotificationsSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorDestructionEngine' => 'Phobject', 'PhabricatorDestructionEngineExtension' => 'Phobject', 'PhabricatorDestructionEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorDeveloperConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDeveloperPreferencesSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorDiffInlineCommentQuery' => 'PhabricatorApplicationTransactionCommentQuery', 'PhabricatorDiffPreferencesSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorDifferenceEngine' => 'Phobject', 'PhabricatorDifferentialApplication' => 'PhabricatorApplication', 'PhabricatorDifferentialAttachCommitWorkflow' => 'PhabricatorDifferentialManagementWorkflow', 'PhabricatorDifferentialConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDifferentialExtractWorkflow' => 'PhabricatorDifferentialManagementWorkflow', 'PhabricatorDifferentialManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorDifferentialRevisionTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorDiffusionApplication' => 'PhabricatorApplication', 'PhabricatorDiffusionBlameSetting' => 'PhabricatorInternalSetting', 'PhabricatorDiffusionColorSetting' => 'PhabricatorInternalSetting', 'PhabricatorDiffusionConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDisabledUserController' => 'PhabricatorAuthController', 'PhabricatorDisplayPreferencesSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorDisqusAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorDividerProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorDivinerApplication' => 'PhabricatorApplication', 'PhabricatorDoorkeeperApplication' => 'PhabricatorApplication', 'PhabricatorDraft' => 'PhabricatorDraftDAO', 'PhabricatorDraftDAO' => 'PhabricatorLiskDAO', 'PhabricatorDrydockApplication' => 'PhabricatorApplication', 'PhabricatorEdgeConfig' => 'PhabricatorEdgeConstants', 'PhabricatorEdgeConstants' => 'Phobject', 'PhabricatorEdgeCycleException' => 'Exception', 'PhabricatorEdgeEditType' => 'PhabricatorPHIDListEditType', 'PhabricatorEdgeEditor' => 'Phobject', 'PhabricatorEdgeGraph' => 'AbstractDirectedGraph', 'PhabricatorEdgeQuery' => 'PhabricatorQuery', 'PhabricatorEdgeTestCase' => 'PhabricatorTestCase', 'PhabricatorEdgeType' => 'Phobject', 'PhabricatorEdgeTypeTestCase' => 'PhabricatorTestCase', 'PhabricatorEdgesDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorEditEngine' => array( 'Phobject', 'PhabricatorPolicyInterface', ), 'PhabricatorEditEngineAPIMethod' => 'ConduitAPIMethod', 'PhabricatorEditEngineColumnsCommentAction' => 'PhabricatorEditEngineCommentAction', 'PhabricatorEditEngineCommentAction' => 'Phobject', 'PhabricatorEditEngineConfiguration' => array( 'PhabricatorSearchDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), 'PhabricatorEditEngineConfigurationDefaultCreateController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationDefaultsController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationDisableController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationEditController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationEditEngine' => 'PhabricatorEditEngine', 'PhabricatorEditEngineConfigurationEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorEditEngineConfigurationIsEditController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationListController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationLockController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationPHIDType' => 'PhabricatorPHIDType', 'PhabricatorEditEngineConfigurationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorEditEngineConfigurationReorderController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationSaveController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorEditEngineConfigurationSortController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineController' => 'PhabricatorApplicationTransactionController', 'PhabricatorEditEngineCreateQuickActions' => 'PhabricatorQuickActions', 'PhabricatorEditEngineExtension' => 'Phobject', 'PhabricatorEditEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorEditEngineListController' => 'PhabricatorEditEngineController', 'PhabricatorEditEnginePointsCommentAction' => 'PhabricatorEditEngineCommentAction', 'PhabricatorEditEngineQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorEditEngineSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorEditEngineSelectCommentAction' => 'PhabricatorEditEngineCommentAction', 'PhabricatorEditEngineSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorEditEngineTokenizerCommentAction' => 'PhabricatorEditEngineCommentAction', 'PhabricatorEditField' => 'Phobject', 'PhabricatorEditPage' => 'Phobject', 'PhabricatorEditType' => 'Phobject', 'PhabricatorEditor' => 'Phobject', 'PhabricatorEditorMultipleSetting' => 'PhabricatorSelectSetting', 'PhabricatorEditorSetting' => 'PhabricatorStringSetting', 'PhabricatorElasticFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine', 'PhabricatorElasticSearchSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorEmailAddressesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorEmailContentSource' => 'PhabricatorContentSource', 'PhabricatorEmailDeliverySettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorEmailFormatSetting' => 'PhabricatorSelectSetting', 'PhabricatorEmailFormatSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 'PhabricatorEmailNotificationsSetting' => 'PhabricatorSelectSetting', 'PhabricatorEmailPreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorEmailRePrefixSetting' => 'PhabricatorSelectSetting', 'PhabricatorEmailSelfActionsSetting' => 'PhabricatorSelectSetting', 'PhabricatorEmailTagsSetting' => 'PhabricatorInternalSetting', 'PhabricatorEmailVarySubjectsSetting' => 'PhabricatorSelectSetting', 'PhabricatorEmailVerificationController' => 'PhabricatorAuthController', 'PhabricatorEmbedFileRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorEmojiRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorEmojiTranslation' => 'PhutilTranslation', 'PhabricatorEmptyQueryException' => 'Exception', 'PhabricatorEnv' => 'Phobject', 'PhabricatorEnvTestCase' => 'PhabricatorTestCase', 'PhabricatorEpochEditField' => 'PhabricatorEditField', 'PhabricatorEvent' => 'PhutilEvent', 'PhabricatorEventEngine' => 'Phobject', 'PhabricatorEventListener' => 'PhutilEventListener', 'PhabricatorEventType' => 'PhutilEventType', 'PhabricatorExampleEventListener' => 'PhabricatorEventListener', 'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource', 'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorExtensionsSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorExternalAccount' => array( 'PhabricatorUserDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorExternalAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorExternalAccountsSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorExtraConfigSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorFacebookAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorFactAggregate' => 'PhabricatorFactDAO', 'PhabricatorFactApplication' => 'PhabricatorApplication', 'PhabricatorFactChartController' => 'PhabricatorFactController', 'PhabricatorFactController' => 'PhabricatorController', 'PhabricatorFactCountEngine' => 'PhabricatorFactEngine', 'PhabricatorFactCursor' => 'PhabricatorFactDAO', 'PhabricatorFactDAO' => 'PhabricatorLiskDAO', 'PhabricatorFactDaemon' => 'PhabricatorDaemon', 'PhabricatorFactEngine' => 'Phobject', 'PhabricatorFactEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorFactHomeController' => 'PhabricatorFactController', 'PhabricatorFactLastUpdatedEngine' => 'PhabricatorFactEngine', 'PhabricatorFactManagementAnalyzeWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementCursorsWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementDestroyWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementListWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementStatusWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorFactRaw' => 'PhabricatorFactDAO', 'PhabricatorFactSimpleSpec' => 'PhabricatorFactSpec', 'PhabricatorFactSpec' => 'Phobject', 'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator', 'PhabricatorFaxContentSource' => 'PhabricatorContentSource', 'PhabricatorFeedApplication' => 'PhabricatorApplication', 'PhabricatorFeedBuilder' => 'Phobject', 'PhabricatorFeedConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFeedController' => 'PhabricatorController', 'PhabricatorFeedDAO' => 'PhabricatorLiskDAO', 'PhabricatorFeedDetailController' => 'PhabricatorFeedController', 'PhabricatorFeedListController' => 'PhabricatorFeedController', 'PhabricatorFeedManagementRepublishWorkflow' => 'PhabricatorFeedManagementWorkflow', 'PhabricatorFeedManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorFeedQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFeedSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFeedStory' => array( 'Phobject', 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', ), 'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryPublisher' => 'Phobject', 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', 'PhabricatorFile' => array( 'PhabricatorFileDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorFileAES256StorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileBundleLoader' => 'Phobject', 'PhabricatorFileChunk' => array( 'PhabricatorFileDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorFileChunkIterator' => array( 'Phobject', 'Iterator', ), 'PhabricatorFileChunkQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFileCommentController' => 'PhabricatorFileController', 'PhabricatorFileComposeController' => 'PhabricatorFileController', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileDataController' => 'PhabricatorFileController', 'PhabricatorFileDeleteController' => 'PhabricatorFileController', 'PhabricatorFileDropUploadController' => 'PhabricatorFileController', 'PhabricatorFileEditController' => 'PhabricatorFileController', + 'PhabricatorFileEditField' => 'PhabricatorEditField', 'PhabricatorFileEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorFileExternalRequest' => array( 'PhabricatorFileDAO', 'PhabricatorDestructibleInterface', ), 'PhabricatorFileExternalRequestGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorFileFilePHIDType' => 'PhabricatorPHIDType', 'PhabricatorFileHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorFileIconSetSelectController' => 'PhabricatorFileController', 'PhabricatorFileImageMacro' => array( 'PhabricatorFileDAO', 'PhabricatorSubscribableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFlaggableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorPolicyInterface', ), 'PhabricatorFileImageProxyController' => 'PhabricatorFileController', 'PhabricatorFileImageTransform' => 'PhabricatorFileTransform', 'PhabricatorFileInfoController' => 'PhabricatorFileController', 'PhabricatorFileLinkView' => 'AphrontView', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFileROT13StorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileRawStorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileStorageConfigurationException' => 'Exception', 'PhabricatorFileStorageEngine' => 'Phobject', 'PhabricatorFileStorageEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorFileStorageFormat' => 'Phobject', 'PhabricatorFileStorageFormatTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTemporaryGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorFileTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorFileThumbnailTransform' => 'PhabricatorFileImageTransform', 'PhabricatorFileTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorFileTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorFileTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorFileTransform' => 'Phobject', 'PhabricatorFileTransformController' => 'PhabricatorFileController', 'PhabricatorFileTransformListController' => 'PhabricatorFileController', 'PhabricatorFileTransformTestCase' => 'PhabricatorTestCase', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileUploadDialogController' => 'PhabricatorFileController', 'PhabricatorFileUploadException' => 'Exception', 'PhabricatorFileUploadSource' => 'Phobject', 'PhabricatorFileinfoSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorFilesApplication' => 'PhabricatorApplication', 'PhabricatorFilesApplicationStorageEnginePanel' => 'PhabricatorApplicationConfigurationPanel', 'PhabricatorFilesBuiltinFile' => 'Phobject', 'PhabricatorFilesComposeIconBuiltinFile' => 'PhabricatorFilesBuiltinFile', 'PhabricatorFilesConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFilesManagementCatWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementCompactWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementCycleWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementEncodeWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementEnginesWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementGenerateKeyWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementMigrateWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementPurgeWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementRebuildWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorFilesOnDiskBuiltinFile' => 'PhabricatorFilesBuiltinFile', 'PhabricatorFilesOutboundRequestAction' => 'PhabricatorSystemAction', 'PhabricatorFiletreeVisibleSetting' => 'PhabricatorInternalSetting', 'PhabricatorFlag' => array( 'PhabricatorFlagDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorFlagAddFlagHeraldAction' => 'HeraldAction', 'PhabricatorFlagColor' => 'PhabricatorFlagConstants', 'PhabricatorFlagConstants' => 'Phobject', 'PhabricatorFlagController' => 'PhabricatorController', 'PhabricatorFlagDAO' => 'PhabricatorLiskDAO', 'PhabricatorFlagDeleteController' => 'PhabricatorFlagController', 'PhabricatorFlagDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorFlagEditController' => 'PhabricatorFlagController', 'PhabricatorFlagListController' => 'PhabricatorFlagController', 'PhabricatorFlagQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFlagSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFlagSelectControl' => 'AphrontFormControl', 'PhabricatorFlaggableInterface' => 'PhabricatorPHIDInterface', 'PhabricatorFlagsApplication' => 'PhabricatorApplication', 'PhabricatorFlagsUIEventListener' => 'PhabricatorEventListener', 'PhabricatorFulltextEngine' => 'Phobject', 'PhabricatorFulltextEngineExtension' => 'Phobject', 'PhabricatorFulltextEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorFulltextIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 'PhabricatorFulltextStorageEngine' => 'Phobject', 'PhabricatorFundApplication' => 'PhabricatorApplication', 'PhabricatorGDSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorGarbageCollector' => 'Phobject', 'PhabricatorGarbageCollectorManagementCollectWorkflow' => 'PhabricatorGarbageCollectorManagementWorkflow', 'PhabricatorGarbageCollectorManagementSetPolicyWorkflow' => 'PhabricatorGarbageCollectorManagementWorkflow', 'PhabricatorGarbageCollectorManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorGestureUIExample' => 'PhabricatorUIExample', 'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorGlobalLock' => 'PhutilLock', 'PhabricatorGlobalUploadTargetView' => 'AphrontView', 'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorGuideApplication' => 'PhabricatorApplication', 'PhabricatorGuideController' => 'PhabricatorController', 'PhabricatorGuideInstallModule' => 'PhabricatorGuideModule', 'PhabricatorGuideItemView' => 'Phobject', 'PhabricatorGuideListView' => 'AphrontView', 'PhabricatorGuideModule' => 'Phobject', 'PhabricatorGuideModuleController' => 'PhabricatorGuideController', 'PhabricatorGuideQuickStartModule' => 'PhabricatorGuideModule', 'PhabricatorHTTPParameterTypeTableView' => 'AphrontView', 'PhabricatorHandleList' => array( 'Phobject', 'Iterator', 'ArrayAccess', 'Countable', ), 'PhabricatorHandleObjectSelectorDataView' => 'Phobject', 'PhabricatorHandlePool' => 'Phobject', 'PhabricatorHandlePoolTestCase' => 'PhabricatorTestCase', 'PhabricatorHandleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorHandleRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorHandlesEditField' => 'PhabricatorPHIDListEditField', 'PhabricatorHarbormasterApplication' => 'PhabricatorApplication', 'PhabricatorHash' => 'Phobject', 'PhabricatorHashTestCase' => 'PhabricatorTestCase', 'PhabricatorHelpApplication' => 'PhabricatorApplication', 'PhabricatorHelpController' => 'PhabricatorController', 'PhabricatorHelpDocumentationController' => 'PhabricatorHelpController', 'PhabricatorHelpEditorProtocolController' => 'PhabricatorHelpController', 'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController', 'PhabricatorHelpMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorHeraldApplication' => 'PhabricatorApplication', 'PhabricatorHeraldContentSource' => 'PhabricatorContentSource', 'PhabricatorHighSecurityRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorHomeApplication' => 'PhabricatorApplication', 'PhabricatorHomeController' => 'PhabricatorController', 'PhabricatorHomeMainController' => 'PhabricatorHomeController', 'PhabricatorHomePreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorHomeQuickCreateController' => 'PhabricatorHomeController', 'PhabricatorHovercardEngineExtension' => 'Phobject', 'PhabricatorHovercardEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorHunksManagementMigrateWorkflow' => 'PhabricatorHunksManagementWorkflow', 'PhabricatorHunksManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorIDsSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorIDsSearchField' => 'PhabricatorSearchField', 'PhabricatorIRCProtocolAdapter' => 'PhabricatorProtocolAdapter', 'PhabricatorIconRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorIconSet' => 'Phobject', 'PhabricatorIconSetEditField' => 'PhabricatorEditField', 'PhabricatorIconSetIcon' => 'Phobject', 'PhabricatorImageMacroRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorImageRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorImageTransformer' => 'Phobject', 'PhabricatorImagemagickSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorInFlightErrorView' => 'AphrontView', 'PhabricatorIndexEngine' => 'Phobject', 'PhabricatorIndexEngineExtension' => 'Phobject', 'PhabricatorIndexEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase', 'PhabricatorInlineCommentController' => 'PhabricatorController', 'PhabricatorInlineCommentInterface' => 'PhabricatorMarkupInterface', 'PhabricatorInlineCommentPreviewController' => 'PhabricatorController', 'PhabricatorInlineSummaryView' => 'AphrontView', 'PhabricatorInstructionsEditField' => 'PhabricatorEditField', 'PhabricatorInternalSetting' => 'PhabricatorSetting', 'PhabricatorInternationalizationManagementExtractWorkflow' => 'PhabricatorInternationalizationManagementWorkflow', 'PhabricatorInternationalizationManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorInvalidConfigSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher', 'PhabricatorIteratedMD5PasswordHasherTestCase' => 'PhabricatorTestCase', 'PhabricatorIteratorFileUploadSource' => 'PhabricatorFileUploadSource', 'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorJumpNavHandler' => 'Phobject', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', 'PhabricatorKeyboardRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorKeyring' => 'Phobject', 'PhabricatorKeyringConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorLDAPAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorLegalpadApplication' => 'PhabricatorApplication', 'PhabricatorLegalpadConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorLegalpadDocumentPHIDType' => 'PhabricatorPHIDType', 'PhabricatorLegalpadSignaturePolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorLibraryTestCase' => 'PhutilLibraryTestCase', 'PhabricatorLinkProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorLipsumArtist' => 'Phobject', 'PhabricatorLipsumContentSource' => 'PhabricatorContentSource', 'PhabricatorLipsumGenerateWorkflow' => 'PhabricatorLipsumManagementWorkflow', 'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorLipsumMondrianArtist' => 'PhabricatorLipsumArtist', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLiskFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorLiskSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorLiskSerializer' => 'Phobject', 'PhabricatorListFilterUIExample' => 'PhabricatorUIExample', 'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase', 'PhabricatorLocaleScopeGuard' => 'Phobject', 'PhabricatorLocaleScopeGuardTestCase' => 'PhabricatorTestCase', 'PhabricatorLogTriggerAction' => 'PhabricatorTriggerAction', 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorLunarPhasePolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorMacroApplication' => 'PhabricatorApplication', 'PhabricatorMacroAudioController' => 'PhabricatorMacroController', 'PhabricatorMacroCommentController' => 'PhabricatorMacroController', 'PhabricatorMacroConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMacroController' => 'PhabricatorController', 'PhabricatorMacroDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorMacroDisableController' => 'PhabricatorMacroController', 'PhabricatorMacroEditController' => 'PhabricatorMacroController', 'PhabricatorMacroEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorMacroListController' => 'PhabricatorMacroController', 'PhabricatorMacroMacroPHIDType' => 'PhabricatorPHIDType', 'PhabricatorMacroMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorMacroManageCapability' => 'PhabricatorPolicyCapability', 'PhabricatorMacroMemeController' => 'PhabricatorMacroController', 'PhabricatorMacroMemeDialogController' => 'PhabricatorMacroController', 'PhabricatorMacroQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMacroReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorMacroSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorMacroTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorMacroViewController' => 'PhabricatorMacroController', 'PhabricatorMailEmailHeraldField' => 'HeraldField', 'PhabricatorMailEmailHeraldFieldGroup' => 'HeraldFieldGroup', 'PhabricatorMailEmailSubjectHeraldField' => 'PhabricatorMailEmailHeraldField', 'PhabricatorMailImplementationAdapter' => 'Phobject', 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailManagementListInboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementListOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementReceiveTestWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementResendWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementSendTestWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowInboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementVolumeWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorMailOutboundMailHeraldAdapter' => 'HeraldAdapter', 'PhabricatorMailOutboundRoutingHeraldAction' => 'HeraldAction', 'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction', 'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction', 'PhabricatorMailOutboundStatus' => 'Phobject', 'PhabricatorMailReceiver' => 'Phobject', 'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase', 'PhabricatorMailReplyHandler' => 'Phobject', 'PhabricatorMailRoutingRule' => 'Phobject', 'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorMailTarget' => 'Phobject', 'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMainMenuBarExtension' => 'Phobject', 'PhabricatorMainMenuSearchView' => 'AphrontView', 'PhabricatorMainMenuView' => 'AphrontView', 'PhabricatorManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorManiphestApplication' => 'PhabricatorApplication', 'PhabricatorManiphestConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorManiphestTaskTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorMarkupCache' => 'PhabricatorCacheDAO', 'PhabricatorMarkupEngine' => 'Phobject', 'PhabricatorMarkupOneOff' => array( 'Phobject', 'PhabricatorMarkupInterface', ), 'PhabricatorMarkupPreviewController' => 'PhabricatorController', 'PhabricatorMemeRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorMentionRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorMercurialGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorMetaMTAActor' => 'Phobject', 'PhabricatorMetaMTAActorQuery' => 'PhabricatorQuery', 'PhabricatorMetaMTAApplication' => 'PhabricatorApplication', 'PhabricatorMetaMTAApplicationEmail' => array( 'PhabricatorMetaMTADAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSpacesInterface', ), 'PhabricatorMetaMTAApplicationEmailDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorMetaMTAApplicationEmailEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorMetaMTAApplicationEmailHeraldField' => 'HeraldField', 'PhabricatorMetaMTAApplicationEmailPHIDType' => 'PhabricatorPHIDType', 'PhabricatorMetaMTAApplicationEmailPanel' => 'PhabricatorApplicationConfigurationPanel', 'PhabricatorMetaMTAApplicationEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMetaMTAApplicationEmailTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorMetaMTAApplicationEmailTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorMetaMTAAttachment' => 'Phobject', 'PhabricatorMetaMTAConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTAEmailBodyParser' => 'Phobject', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAEmailHeraldAction' => 'HeraldAction', 'PhabricatorMetaMTAEmailOthersHeraldAction' => 'PhabricatorMetaMTAEmailHeraldAction', 'PhabricatorMetaMTAEmailSelfHeraldAction' => 'PhabricatorMetaMTAEmailHeraldAction', 'PhabricatorMetaMTAErrorMailAction' => 'PhabricatorSystemAction', 'PhabricatorMetaMTAMail' => array( 'PhabricatorMetaMTADAO', 'PhabricatorPolicyInterface', ), 'PhabricatorMetaMTAMailBody' => 'Phobject', 'PhabricatorMetaMTAMailBodyTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAMailHasRecipientEdgeType' => 'PhabricatorEdgeType', 'PhabricatorMetaMTAMailListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMailPHIDType' => 'PhabricatorPHIDType', 'PhabricatorMetaMTAMailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMetaMTAMailSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorMetaMTAMailSection' => 'Phobject', 'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAMailViewController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMailableDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorMetaMTAMailableFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorMetaMTAMailgunReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMemberQuery' => 'PhabricatorQuery', 'PhabricatorMetaMTAPermanentFailureException' => 'Exception', 'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAReceivedMailProcessingException' => 'Exception', 'PhabricatorMetaMTAReceivedMailTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTASchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAWorker' => 'PhabricatorWorker', 'PhabricatorMetronomicTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorModularTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorModularTransactionType' => 'Phobject', 'PhabricatorMonospacedFontSetting' => 'PhabricatorStringSetting', 'PhabricatorMonospacedTextareasSetting' => 'PhabricatorSelectSetting', 'PhabricatorMotivatorProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorMultiColumnUIExample' => 'PhabricatorUIExample', 'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorMultimeterApplication' => 'PhabricatorApplication', 'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController', 'PhabricatorMySQLConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorMySQLFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine', 'PhabricatorMySQLSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorNamedQuery' => array( 'PhabricatorSearchDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorNgramsIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 'PhabricatorNotificationBuilder' => 'Phobject', 'PhabricatorNotificationClearController' => 'PhabricatorNotificationController', 'PhabricatorNotificationClient' => 'Phobject', 'PhabricatorNotificationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorNotificationController' => 'PhabricatorController', 'PhabricatorNotificationDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorNotificationIndividualController' => 'PhabricatorNotificationController', 'PhabricatorNotificationListController' => 'PhabricatorNotificationController', 'PhabricatorNotificationPanelController' => 'PhabricatorNotificationController', 'PhabricatorNotificationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorNotificationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorNotificationServerRef' => 'Phobject', 'PhabricatorNotificationServersConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorNotificationStatusView' => 'AphrontTagView', 'PhabricatorNotificationTestController' => 'PhabricatorNotificationController', 'PhabricatorNotificationTestFeedStory' => 'PhabricatorFeedStory', 'PhabricatorNotificationUIExample' => 'PhabricatorUIExample', 'PhabricatorNotificationsApplication' => 'PhabricatorApplication', 'PhabricatorNuanceApplication' => 'PhabricatorApplication', 'PhabricatorOAuth1AuthProvider' => 'PhabricatorOAuthAuthProvider', 'PhabricatorOAuth1SecretTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType', 'PhabricatorOAuth2AuthProvider' => 'PhabricatorOAuthAuthProvider', 'PhabricatorOAuthAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorOAuthClientAuthorization' => array( 'PhabricatorOAuthServerDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorOAuthClientAuthorizationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorOAuthClientController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthClientDisableController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientEditController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientListController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientSecretController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientTestController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientViewController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthResponse' => 'AphrontResponse', 'PhabricatorOAuthServer' => 'Phobject', 'PhabricatorOAuthServerAccessToken' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthServerApplication' => 'PhabricatorApplication', 'PhabricatorOAuthServerAuthController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthServerAuthorizationCode' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthServerAuthorizationsSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorOAuthServerClient' => array( 'PhabricatorOAuthServerDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorOAuthServerClientAuthorizationPHIDType' => 'PhabricatorPHIDType', 'PhabricatorOAuthServerClientPHIDType' => 'PhabricatorPHIDType', 'PhabricatorOAuthServerClientQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorOAuthServerClientSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorOAuthServerController' => 'PhabricatorController', 'PhabricatorOAuthServerCreateClientsCapability' => 'PhabricatorPolicyCapability', 'PhabricatorOAuthServerDAO' => 'PhabricatorLiskDAO', 'PhabricatorOAuthServerEditEngine' => 'PhabricatorEditEngine', 'PhabricatorOAuthServerEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorOAuthServerSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorOAuthServerScope' => 'Phobject', 'PhabricatorOAuthServerTestCase' => 'PhabricatorTestCase', 'PhabricatorOAuthServerTokenController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthServerTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorOAuthServerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorObjectGraph' => 'AbstractDirectedGraph', 'PhabricatorObjectHandle' => array( 'Phobject', 'PhabricatorPolicyInterface', ), 'PhabricatorObjectHasAsanaSubtaskEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasAsanaTaskEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasContributorEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasFileEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasJiraIssueEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasSubscriberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasUnsubscriberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasWatcherEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectListQuery' => 'Phobject', 'PhabricatorObjectListQueryTestCase' => 'PhabricatorTestCase', 'PhabricatorObjectMailReceiver' => 'PhabricatorMailReceiver', 'PhabricatorObjectMailReceiverTestCase' => 'PhabricatorTestCase', 'PhabricatorObjectMentionedByObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectMentionsObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorObjectRelationship' => 'Phobject', 'PhabricatorObjectRelationshipList' => 'Phobject', 'PhabricatorObjectRelationshipSource' => 'Phobject', 'PhabricatorObjectRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorObjectSelectorDialog' => 'Phobject', 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', 'PhabricatorOldWorldContentSource' => 'PhabricatorContentSource', 'PhabricatorOlderInlinesSetting' => 'PhabricatorSelectSetting', 'PhabricatorOneTimeTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorOpcodeCacheSpec' => 'PhabricatorCacheSpec', 'PhabricatorOptionGroupSetting' => 'PhabricatorSetting', 'PhabricatorOwnerPathQuery' => 'Phobject', 'PhabricatorOwnersApplication' => 'PhabricatorApplication', 'PhabricatorOwnersArchiveController' => 'PhabricatorOwnersController', 'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorOwnersConfiguredCustomField' => array( 'PhabricatorOwnersCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorOwnersController' => 'PhabricatorController', 'PhabricatorOwnersCustomField' => 'PhabricatorCustomField', 'PhabricatorOwnersCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'PhabricatorOwnersCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'PhabricatorOwnersCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO', 'PhabricatorOwnersDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PhabricatorOwnersDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController', 'PhabricatorOwnersEditController' => 'PhabricatorOwnersController', 'PhabricatorOwnersListController' => 'PhabricatorOwnersController', 'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO', 'PhabricatorOwnersPackage' => array( 'PhabricatorOwnersDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', 'PhabricatorConduitResultInterface', 'PhabricatorFulltextInterface', 'PhabricatorNgramsInterface', ), + 'PhabricatorOwnersPackageAuditingTransaction' => 'PhabricatorOwnersPackageTransactionType', + 'PhabricatorOwnersPackageAutoreviewTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource', + 'PhabricatorOwnersPackageDescriptionTransaction' => 'PhabricatorOwnersPackageTransactionType', + 'PhabricatorOwnersPackageDominionTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageEditEngine' => 'PhabricatorEditEngine', 'PhabricatorOwnersPackageFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorOwnersPackageFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorOwnersPackageNameNgrams' => 'PhabricatorSearchNgrams', + 'PhabricatorOwnersPackageNameTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource', + 'PhabricatorOwnersPackageOwnersTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackagePHIDType' => 'PhabricatorPHIDType', + 'PhabricatorOwnersPackagePathsTransaction' => 'PhabricatorOwnersPackageTransactionType', + 'PhabricatorOwnersPackagePrimaryTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorOwnersPackageRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorOwnersPackageSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'PhabricatorOwnersPackageStatusTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageTestCase' => 'PhabricatorTestCase', - 'PhabricatorOwnersPackageTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorOwnersPackageTransaction' => 'PhabricatorModularTransaction', 'PhabricatorOwnersPackageTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorOwnersPackageTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorOwnersPackageTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO', 'PhabricatorOwnersPathsController' => 'PhabricatorOwnersController', 'PhabricatorOwnersPathsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'PhabricatorOwnersSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorOwnersSearchField' => 'PhabricatorSearchTokenizerField', 'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPHID' => 'Phobject', 'PhabricatorPHIDConstants' => 'Phobject', 'PhabricatorPHIDListEditField' => 'PhabricatorEditField', 'PhabricatorPHIDListEditType' => 'PhabricatorEditType', 'PhabricatorPHIDResolver' => 'Phobject', 'PhabricatorPHIDType' => 'Phobject', 'PhabricatorPHIDTypeTestCase' => 'PhutilTestCase', 'PhabricatorPHIDsSearchField' => 'PhabricatorSearchField', 'PhabricatorPHPASTApplication' => 'PhabricatorApplication', 'PhabricatorPHPConfigSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPHPPreflightSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorPackagesApplication' => 'PhabricatorApplication', 'PhabricatorPackagesController' => 'PhabricatorController', 'PhabricatorPackagesCreatePublisherCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPackagesDAO' => 'PhabricatorLiskDAO', 'PhabricatorPackagesEditEngine' => 'PhabricatorEditEngine', 'PhabricatorPackagesEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorPackagesNgrams' => 'PhabricatorSearchNgrams', 'PhabricatorPackagesPackage' => array( 'PhabricatorPackagesDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSubscribableInterface', 'PhabricatorProjectInterface', 'PhabricatorConduitResultInterface', 'PhabricatorNgramsInterface', ), 'PhabricatorPackagesPackageController' => 'PhabricatorPackagesController', 'PhabricatorPackagesPackageDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPackagesPackageDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPackagesPackageDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPackagesPackageEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorPackagesPackageEditController' => 'PhabricatorPackagesPackageController', 'PhabricatorPackagesPackageEditEngine' => 'PhabricatorPackagesEditEngine', 'PhabricatorPackagesPackageEditor' => 'PhabricatorPackagesEditor', 'PhabricatorPackagesPackageKeyTransaction' => 'PhabricatorPackagesPackageTransactionType', 'PhabricatorPackagesPackageListController' => 'PhabricatorPackagesPackageController', 'PhabricatorPackagesPackageListView' => 'PhabricatorPackagesView', 'PhabricatorPackagesPackageNameNgrams' => 'PhabricatorPackagesNgrams', 'PhabricatorPackagesPackageNameTransaction' => 'PhabricatorPackagesPackageTransactionType', 'PhabricatorPackagesPackagePHIDType' => 'PhabricatorPHIDType', 'PhabricatorPackagesPackagePublisherTransaction' => 'PhabricatorPackagesPackageTransactionType', 'PhabricatorPackagesPackageQuery' => 'PhabricatorPackagesQuery', 'PhabricatorPackagesPackageSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorPackagesPackageSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPackagesPackageTransaction' => 'PhabricatorModularTransaction', 'PhabricatorPackagesPackageTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorPackagesPackageTransactionType' => 'PhabricatorPackagesTransactionType', 'PhabricatorPackagesPackageViewController' => 'PhabricatorPackagesPackageController', 'PhabricatorPackagesPublisher' => array( 'PhabricatorPackagesDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSubscribableInterface', 'PhabricatorProjectInterface', 'PhabricatorConduitResultInterface', 'PhabricatorNgramsInterface', ), 'PhabricatorPackagesPublisherController' => 'PhabricatorPackagesController', 'PhabricatorPackagesPublisherDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPackagesPublisherDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPackagesPublisherEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorPackagesPublisherEditController' => 'PhabricatorPackagesPublisherController', 'PhabricatorPackagesPublisherEditEngine' => 'PhabricatorPackagesEditEngine', 'PhabricatorPackagesPublisherEditor' => 'PhabricatorPackagesEditor', 'PhabricatorPackagesPublisherKeyTransaction' => 'PhabricatorPackagesPublisherTransactionType', 'PhabricatorPackagesPublisherListController' => 'PhabricatorPackagesPublisherController', 'PhabricatorPackagesPublisherListView' => 'PhabricatorPackagesView', 'PhabricatorPackagesPublisherNameNgrams' => 'PhabricatorPackagesNgrams', 'PhabricatorPackagesPublisherNameTransaction' => 'PhabricatorPackagesPublisherTransactionType', 'PhabricatorPackagesPublisherPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPackagesPublisherQuery' => 'PhabricatorPackagesQuery', 'PhabricatorPackagesPublisherSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorPackagesPublisherSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPackagesPublisherTransaction' => 'PhabricatorModularTransaction', 'PhabricatorPackagesPublisherTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorPackagesPublisherTransactionType' => 'PhabricatorPackagesTransactionType', 'PhabricatorPackagesPublisherViewController' => 'PhabricatorPackagesPublisherController', 'PhabricatorPackagesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPackagesSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorPackagesTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorPackagesVersion' => array( 'PhabricatorPackagesDAO', 'PhabricatorPolicyInterface', 'PhabricatorExtendedPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSubscribableInterface', 'PhabricatorProjectInterface', 'PhabricatorConduitResultInterface', 'PhabricatorNgramsInterface', ), 'PhabricatorPackagesVersionController' => 'PhabricatorPackagesController', 'PhabricatorPackagesVersionEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorPackagesVersionEditController' => 'PhabricatorPackagesVersionController', 'PhabricatorPackagesVersionEditEngine' => 'PhabricatorPackagesEditEngine', 'PhabricatorPackagesVersionEditor' => 'PhabricatorPackagesEditor', 'PhabricatorPackagesVersionListController' => 'PhabricatorPackagesVersionController', 'PhabricatorPackagesVersionListView' => 'PhabricatorPackagesView', 'PhabricatorPackagesVersionNameNgrams' => 'PhabricatorPackagesNgrams', 'PhabricatorPackagesVersionNameTransaction' => 'PhabricatorPackagesVersionTransactionType', 'PhabricatorPackagesVersionPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPackagesVersionPackageTransaction' => 'PhabricatorPackagesVersionTransactionType', 'PhabricatorPackagesVersionQuery' => 'PhabricatorPackagesQuery', 'PhabricatorPackagesVersionSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorPackagesVersionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPackagesVersionTransaction' => 'PhabricatorModularTransaction', 'PhabricatorPackagesVersionTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorPackagesVersionTransactionType' => 'PhabricatorPackagesTransactionType', 'PhabricatorPackagesVersionViewController' => 'PhabricatorPackagesVersionController', 'PhabricatorPackagesView' => 'AphrontView', 'PhabricatorPagerUIExample' => 'PhabricatorUIExample', 'PhabricatorPassphraseApplication' => 'PhabricatorApplication', 'PhabricatorPasswordAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorPasswordHasher' => 'Phobject', 'PhabricatorPasswordHasherTestCase' => 'PhabricatorTestCase', 'PhabricatorPasswordHasherUnavailableException' => 'Exception', 'PhabricatorPasswordSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorPaste' => array( 'PhabricatorPasteDAO', 'PhabricatorSubscribableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhabricatorMentionableInterface', 'PhabricatorPolicyInterface', 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSpacesInterface', 'PhabricatorConduitResultInterface', ), 'PhabricatorPasteApplication' => 'PhabricatorApplication', 'PhabricatorPasteArchiveController' => 'PhabricatorPasteController', 'PhabricatorPasteConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPasteContentSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'PhabricatorPasteContentTransaction' => 'PhabricatorPasteTransactionType', 'PhabricatorPasteController' => 'PhabricatorController', 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 'PhabricatorPasteEditController' => 'PhabricatorPasteController', 'PhabricatorPasteEditEngine' => 'PhabricatorEditEngine', 'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorPasteFilenameContextFreeGrammar' => 'PhutilContextFreeGrammar', 'PhabricatorPasteLanguageTransaction' => 'PhabricatorPasteTransactionType', 'PhabricatorPasteListController' => 'PhabricatorPasteController', 'PhabricatorPastePastePHIDType' => 'PhabricatorPHIDType', 'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPasteRawController' => 'PhabricatorPasteController', 'PhabricatorPasteRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorPasteSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPasteSnippet' => 'Phobject', 'PhabricatorPasteStatusTransaction' => 'PhabricatorPasteTransactionType', 'PhabricatorPasteTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorPasteTitleTransaction' => 'PhabricatorPasteTransactionType', 'PhabricatorPasteTransaction' => 'PhabricatorModularTransaction', 'PhabricatorPasteTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorPasteTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorPasteTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorPasteViewController' => 'PhabricatorPasteController', 'PhabricatorPathSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorPeopleAnyOwnerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPeopleApplication' => 'PhabricatorApplication', 'PhabricatorPeopleApproveController' => 'PhabricatorPeopleController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleCreateController' => 'PhabricatorPeopleController', 'PhabricatorPeopleDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPeopleDeleteController' => 'PhabricatorPeopleController', 'PhabricatorPeopleDetailsProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController', 'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController', 'PhabricatorPeopleExternalPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPeopleIconSet' => 'PhabricatorIconSet', 'PhabricatorPeopleInviteController' => 'PhabricatorPeopleController', 'PhabricatorPeopleInviteListController' => 'PhabricatorPeopleInviteController', 'PhabricatorPeopleInviteSendController' => 'PhabricatorPeopleInviteController', 'PhabricatorPeopleLdapController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', 'PhabricatorPeopleMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorPeopleManageProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorPeopleNewController' => 'PhabricatorPeopleController', 'PhabricatorPeopleNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPeopleOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleProfileManageController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleProfilePanelEngine' => 'PhabricatorProfilePanelEngine', 'PhabricatorPeopleProfilePictureController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleProfileViewController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleRenameController' => 'PhabricatorPeopleController', 'PhabricatorPeopleSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPeopleTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorPeopleTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorPeopleUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorPeopleUserPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPeopleWelcomeController' => 'PhabricatorPeopleController', 'PhabricatorPersonaAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorPhabricatorAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorPhameApplication' => 'PhabricatorApplication', 'PhabricatorPhameBlogPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPhamePostPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPhluxApplication' => 'PhabricatorApplication', 'PhabricatorPholioApplication' => 'PhabricatorApplication', 'PhabricatorPholioConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPholioMockTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorPhortuneApplication' => 'PhabricatorApplication', 'PhabricatorPhortuneContentSource' => 'PhabricatorContentSource', 'PhabricatorPhortuneManagementInvoiceWorkflow' => 'PhabricatorPhortuneManagementWorkflow', 'PhabricatorPhortuneManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorPhragmentApplication' => 'PhabricatorApplication', 'PhabricatorPhrequentApplication' => 'PhabricatorApplication', 'PhabricatorPhrictionApplication' => 'PhabricatorApplication', 'PhabricatorPhrictionConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPhurlApplication' => 'PhabricatorApplication', 'PhabricatorPhurlConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPhurlController' => 'PhabricatorController', 'PhabricatorPhurlDAO' => 'PhabricatorLiskDAO', 'PhabricatorPhurlLinkRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorPhurlRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorPhurlSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorPhurlShortURLController' => 'PhabricatorPhurlController', 'PhabricatorPhurlShortURLDefaultController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURL' => array( 'PhabricatorPhurlDAO', 'PhabricatorPolicyInterface', 'PhabricatorProjectInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorDestructibleInterface', 'PhabricatorMentionableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorSpacesInterface', 'PhabricatorConduitResultInterface', 'PhabricatorNgramsInterface', ), 'PhabricatorPhurlURLAccessController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLCommentController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLCreateCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPhurlURLEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorPhurlURLEditController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLEditEngine' => 'PhabricatorEditEngine', 'PhabricatorPhurlURLEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorPhurlURLListController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorPhurlURLNameNgrams' => 'PhabricatorSearchNgrams', 'PhabricatorPhurlURLPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPhurlURLQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPhurlURLReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorPhurlURLSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorPhurlURLSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPhurlURLTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorPhurlURLTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorPhurlURLTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorPhurlURLViewController' => 'PhabricatorPhurlController', 'PhabricatorPinnedApplicationsSetting' => 'PhabricatorInternalSetting', 'PhabricatorPirateEnglishTranslation' => 'PhutilTranslation', 'PhabricatorPlatformSite' => 'PhabricatorSite', 'PhabricatorPointsEditField' => 'PhabricatorEditField', 'PhabricatorPolicies' => 'PhabricatorPolicyConstants', 'PhabricatorPolicy' => array( 'PhabricatorPolicyDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorPolicyApplication' => 'PhabricatorApplication', 'PhabricatorPolicyAwareQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorPolicyAwareTestQuery' => 'PhabricatorPolicyAwareQuery', 'PhabricatorPolicyCanEditCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyCanJoinCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyCanViewCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyCapability' => 'Phobject', 'PhabricatorPolicyCapabilityTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPolicyConstants' => 'Phobject', 'PhabricatorPolicyController' => 'PhabricatorController', 'PhabricatorPolicyDAO' => 'PhabricatorLiskDAO', 'PhabricatorPolicyDataTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyEditController' => 'PhabricatorPolicyController', 'PhabricatorPolicyEditEngineExtension' => 'PhabricatorEditEngineExtension', 'PhabricatorPolicyEditField' => 'PhabricatorEditField', 'PhabricatorPolicyException' => 'Exception', 'PhabricatorPolicyExplainController' => 'PhabricatorPolicyController', 'PhabricatorPolicyFavoritesSetting' => 'PhabricatorInternalSetting', 'PhabricatorPolicyFilter' => 'Phobject', 'PhabricatorPolicyInterface' => 'PhabricatorPHIDInterface', 'PhabricatorPolicyManagementShowWorkflow' => 'PhabricatorPolicyManagementWorkflow', 'PhabricatorPolicyManagementUnlockWorkflow' => 'PhabricatorPolicyManagementWorkflow', 'PhabricatorPolicyManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorPolicyPHIDTypePolicy' => 'PhabricatorPHIDType', 'PhabricatorPolicyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPolicyRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorPolicyRule' => 'Phobject', 'PhabricatorPolicySearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorPolicyTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyTestObject' => array( 'Phobject', 'PhabricatorPolicyInterface', 'PhabricatorExtendedPolicyInterface', ), 'PhabricatorPolicyType' => 'PhabricatorPolicyConstants', 'PhabricatorPonderApplication' => 'PhabricatorApplication', 'PhabricatorProfileMenuCollapsedSetting' => 'PhabricatorInternalSetting', 'PhabricatorProfilePanel' => 'Phobject', 'PhabricatorProfilePanelConfiguration' => array( 'PhabricatorSearchDAO', 'PhabricatorPolicyInterface', 'PhabricatorExtendedPolicyInterface', 'PhabricatorApplicationTransactionInterface', ), 'PhabricatorProfilePanelConfigurationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProfilePanelConfigurationTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorProfilePanelConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorProfilePanelEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProfilePanelEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProfilePanelEngine' => 'Phobject', 'PhabricatorProfilePanelIconSet' => 'PhabricatorIconSet', 'PhabricatorProfilePanelPHIDType' => 'PhabricatorPHIDType', 'PhabricatorProject' => array( 'PhabricatorProjectDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorExtendedPolicyInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFulltextInterface', 'PhabricatorConduitResultInterface', 'PhabricatorColumnProxyInterface', ), 'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction', 'PhabricatorProjectApplication' => 'PhabricatorApplication', 'PhabricatorProjectArchiveController' => 'PhabricatorProjectController', 'PhabricatorProjectBoardBackgroundController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardController' => 'PhabricatorProjectController', 'PhabricatorProjectBoardDisableController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardManageController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectCardView' => 'AphrontTagView', 'PhabricatorProjectColorsConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorProjectColumn' => array( 'PhabricatorProjectDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorExtendedPolicyInterface', ), 'PhabricatorProjectColumnDetailController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectColumnEditController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectColumnHideController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectColumnPHIDType' => 'PhabricatorPHIDType', 'PhabricatorProjectColumnPosition' => array( 'PhabricatorProjectDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorProjectColumnPositionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProjectColumnQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProjectColumnTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorProjectColumnTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProjectColumnTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorProjectConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorProjectConfiguredCustomField' => array( 'PhabricatorProjectStandardCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorProjectController' => 'PhabricatorController', 'PhabricatorProjectCoreTestCase' => 'PhabricatorTestCase', 'PhabricatorProjectCoverController' => 'PhabricatorProjectController', 'PhabricatorProjectCustomField' => 'PhabricatorCustomField', 'PhabricatorProjectCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'PhabricatorProjectCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'PhabricatorProjectCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'PhabricatorProjectDAO' => 'PhabricatorLiskDAO', 'PhabricatorProjectDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorProjectDefaultController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectDescriptionField' => 'PhabricatorProjectStandardCustomField', 'PhabricatorProjectDetailsProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorProjectEditController' => 'PhabricatorProjectController', 'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', 'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorProjectHeraldAction' => 'HeraldAction', 'PhabricatorProjectHeraldAdapter' => 'HeraldAdapter', 'PhabricatorProjectHeraldFieldGroup' => 'HeraldFieldGroup', 'PhabricatorProjectHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', 'PhabricatorProjectIconSet' => 'PhabricatorIconSet', 'PhabricatorProjectIconsConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectListView' => 'AphrontView', 'PhabricatorProjectLockController' => 'PhabricatorProjectController', 'PhabricatorProjectLogicalAncestorDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalOrNotDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalViewerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorProjectManageController' => 'PhabricatorProjectController', 'PhabricatorProjectManageProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorProjectMaterializedMemberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectMemberListView' => 'PhabricatorProjectUserListView', 'PhabricatorProjectMemberOfProjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectMembersAddController' => 'PhabricatorProjectController', 'PhabricatorProjectMembersDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectMembersPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorProjectMembersProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController', 'PhabricatorProjectMembersViewController' => 'PhabricatorProjectController', 'PhabricatorProjectMoveController' => 'PhabricatorProjectController', 'PhabricatorProjectNameContextFreeGrammar' => 'PhutilContextFreeGrammar', 'PhabricatorProjectNoProjectsDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectOrUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectPHIDResolver' => 'PhabricatorPHIDResolver', 'PhabricatorProjectPanelController' => 'PhabricatorProjectController', 'PhabricatorProjectPointsProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', 'PhabricatorProjectProfilePanelEngine' => 'PhabricatorProfilePanelEngine', 'PhabricatorProjectProjectHasMemberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectProjectPHIDType' => 'PhabricatorPHIDType', 'PhabricatorProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProjectRemoveHeraldAction' => 'PhabricatorProjectHeraldAction', 'PhabricatorProjectSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorProjectSearchField' => 'PhabricatorSearchTokenizerField', 'PhabricatorProjectSilenceController' => 'PhabricatorProjectController', 'PhabricatorProjectSilencedEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectSlug' => 'PhabricatorProjectDAO', 'PhabricatorProjectStandardCustomField' => array( 'PhabricatorProjectCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorProjectStatus' => 'Phobject', 'PhabricatorProjectSubprojectWarningController' => 'PhabricatorProjectController', 'PhabricatorProjectSubprojectsController' => 'PhabricatorProjectController', 'PhabricatorProjectSubprojectsProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorProjectTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener', 'PhabricatorProjectUpdateController' => 'PhabricatorProjectController', 'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectUserListView' => 'AphrontView', 'PhabricatorProjectViewController' => 'PhabricatorProjectController', 'PhabricatorProjectWatchController' => 'PhabricatorProjectController', 'PhabricatorProjectWatcherListView' => 'PhabricatorProjectUserListView', 'PhabricatorProjectWorkboardBackgroundColor' => 'Phobject', 'PhabricatorProjectWorkboardProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension', 'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension', 'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField', 'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorProjectsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'PhabricatorProjectsSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorProjectsWatchersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'PhabricatorPronounSetting' => 'PhabricatorSelectSetting', 'PhabricatorProtocolAdapter' => 'Phobject', 'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorQuery' => 'Phobject', 'PhabricatorQueryConstraint' => 'Phobject', 'PhabricatorQueryOrderItem' => 'Phobject', 'PhabricatorQueryOrderTestCase' => 'PhabricatorTestCase', 'PhabricatorQueryOrderVector' => array( 'Phobject', 'Iterator', ), 'PhabricatorQuickActions' => 'Phobject', 'PhabricatorRateLimitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRecipientHasBadgeEdgeType' => 'PhabricatorEdgeType', 'PhabricatorRedirectController' => 'PhabricatorController', 'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController', 'PhabricatorRegistrationProfile' => 'Phobject', 'PhabricatorReleephApplication' => 'PhabricatorApplication', 'PhabricatorReleephApplicationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl', 'PhabricatorRemarkupCowsayBlockInterpreter' => 'PhutilRemarkupBlockInterpreter', 'PhabricatorRemarkupCustomBlockRule' => 'PhutilRemarkupBlockRule', 'PhabricatorRemarkupCustomInlineRule' => 'PhutilRemarkupRule', 'PhabricatorRemarkupEditField' => 'PhabricatorEditField', 'PhabricatorRemarkupFigletBlockInterpreter' => 'PhutilRemarkupBlockInterpreter', 'PhabricatorRemarkupUIExample' => 'PhabricatorUIExample', 'PhabricatorRepositoriesSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorRepository' => array( 'PhabricatorRepositoryDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorMarkupInterface', 'PhabricatorDestructibleInterface', 'PhabricatorProjectInterface', 'PhabricatorSpacesInterface', 'PhabricatorConduitResultInterface', ), 'PhabricatorRepositoryAuditRequest' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryBranch' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommit' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorProjectInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorSubscribableInterface', 'PhabricatorMentionableInterface', 'HarbormasterBuildableInterface', 'HarbormasterCircleCIBuildableInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFulltextInterface', ), 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitHint' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitOwnersWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker', 'PhabricatorRepositoryCommitRef' => 'Phobject', 'PhabricatorRepositoryCommitTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorRepositoryDiscoveryEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorRepositoryEngine' => 'Phobject', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryGitLFSRef' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorRepositoryGitLFSRefQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryGraphCache' => 'Phobject', 'PhabricatorRepositoryGraphStream' => 'Phobject', 'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementClusterizeWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementHintWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementListPathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMirrorWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMovePathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementParentsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementPullWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementRefsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementReparseWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementThawWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementUpdateWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryMirror' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryMirrorEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryOldRef' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryParsedChange' => 'Phobject', 'PhabricatorRepositoryPullEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryPullEvent' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryPullEventPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryPullEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryPullLocalDaemon' => 'PhabricatorDaemon', 'PhabricatorRepositoryPushEvent' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryPushEventPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryPushEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryPushLog' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryPushLogPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryPushLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryPushLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorRepositoryPushMailWorker' => 'PhabricatorWorker', 'PhabricatorRepositoryPushReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorRepositoryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryRefCursor' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryRefCursorPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryRefCursorQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryRefEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryRepositoryPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositorySchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorRepositorySearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorRepositoryStatusMessage' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositorySymbol' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorRepositoryType' => 'Phobject', 'PhabricatorRepositoryURI' => array( 'PhabricatorRepositoryDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorExtendedPolicyInterface', 'PhabricatorConduitResultInterface', ), 'PhabricatorRepositoryURIIndex' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryURINormalizer' => 'Phobject', 'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryURIPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryURIQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryURITransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorRepositoryURITransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryVersion' => 'Phobject', 'PhabricatorRepositoryWorkingCopyVersion' => 'PhabricatorRepositoryDAO', 'PhabricatorRequestExceptionHandler' => 'AphrontRequestExceptionHandler', 'PhabricatorResourceSite' => 'PhabricatorSite', 'PhabricatorRobotsController' => 'PhabricatorController', 'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorSMS' => 'PhabricatorSMSDAO', 'PhabricatorSMSConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSMSDAO' => 'PhabricatorLiskDAO', 'PhabricatorSMSDemultiplexWorker' => 'PhabricatorSMSWorker', 'PhabricatorSMSImplementationAdapter' => 'Phobject', 'PhabricatorSMSImplementationTestBlackholeAdapter' => 'PhabricatorSMSImplementationAdapter', 'PhabricatorSMSImplementationTwilioAdapter' => 'PhabricatorSMSImplementationAdapter', 'PhabricatorSMSManagementListOutboundWorkflow' => 'PhabricatorSMSManagementWorkflow', 'PhabricatorSMSManagementSendTestWorkflow' => 'PhabricatorSMSManagementWorkflow', 'PhabricatorSMSManagementShowOutboundWorkflow' => 'PhabricatorSMSManagementWorkflow', 'PhabricatorSMSManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSMSSendWorker' => 'PhabricatorSMSWorker', 'PhabricatorSMSWorker' => 'PhabricatorWorker', 'PhabricatorSQLPatchList' => 'Phobject', 'PhabricatorSSHKeyGenerator' => 'Phobject', 'PhabricatorSSHKeysSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorSSHLog' => 'Phobject', 'PhabricatorSSHPassthruCommand' => 'Phobject', 'PhabricatorSSHWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSavedQuery' => array( 'PhabricatorSearchDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorSavedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorScheduleTaskTriggerAction' => 'PhabricatorTriggerAction', 'PhabricatorScopedEnv' => 'Phobject', 'PhabricatorSearchAbstractDocument' => 'Phobject', 'PhabricatorSearchApplication' => 'PhabricatorApplication', 'PhabricatorSearchApplicationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorSearchApplicationStorageEnginePanel' => 'PhabricatorApplicationConfigurationPanel', 'PhabricatorSearchBaseController' => 'PhabricatorController', 'PhabricatorSearchCheckboxesField' => 'PhabricatorSearchField', 'PhabricatorSearchConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchCustomFieldProxyField' => 'PhabricatorSearchField', 'PhabricatorSearchDAO' => 'PhabricatorLiskDAO', 'PhabricatorSearchDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorSearchDatasourceField' => 'PhabricatorSearchTokenizerField', 'PhabricatorSearchDateControlField' => 'PhabricatorSearchField', 'PhabricatorSearchDateField' => 'PhabricatorSearchField', 'PhabricatorSearchDeleteController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchDocument' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentFieldType' => 'Phobject', 'PhabricatorSearchDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentTypeDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorSearchEditController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchEngineAPIMethod' => 'ConduitAPIMethod', 'PhabricatorSearchEngineAttachment' => 'Phobject', 'PhabricatorSearchEngineExtension' => 'Phobject', 'PhabricatorSearchEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorSearchEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorSearchField' => 'Phobject', 'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchIndexVersion' => 'PhabricatorSearchDAO', 'PhabricatorSearchIndexVersionDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorSearchManagementIndexWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementInitWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSearchNgrams' => 'PhabricatorSearchDAO', 'PhabricatorSearchNgramsDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorSearchOrderController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchOrderField' => 'PhabricatorSearchField', 'PhabricatorSearchRelationship' => 'Phobject', 'PhabricatorSearchRelationshipController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchRelationshipSourceController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchResultBucket' => 'Phobject', 'PhabricatorSearchResultBucketGroup' => 'Phobject', 'PhabricatorSearchResultView' => 'AphrontView', 'PhabricatorSearchSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorSearchScopeSetting' => 'PhabricatorInternalSetting', 'PhabricatorSearchSelectField' => 'PhabricatorSearchField', 'PhabricatorSearchStringListField' => 'PhabricatorSearchField', 'PhabricatorSearchSubscribersField' => 'PhabricatorSearchTokenizerField', 'PhabricatorSearchTextField' => 'PhabricatorSearchField', 'PhabricatorSearchThreeStateField' => 'PhabricatorSearchField', 'PhabricatorSearchTokenizerField' => 'PhabricatorSearchField', 'PhabricatorSearchWorker' => 'PhabricatorWorker', 'PhabricatorSecurityConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSecuritySetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorSelectEditField' => 'PhabricatorEditField', 'PhabricatorSelectSetting' => 'PhabricatorSetting', 'PhabricatorSendGridConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSessionsSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorSetting' => 'Phobject', 'PhabricatorSettingsAccountPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsAddEmailAction' => 'PhabricatorSystemAction', 'PhabricatorSettingsAdjustController' => 'PhabricatorController', 'PhabricatorSettingsApplication' => 'PhabricatorApplication', 'PhabricatorSettingsApplicationsPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsAuthenticationPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsDeveloperPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsEditEngine' => 'PhabricatorEditEngine', 'PhabricatorSettingsEmailPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsListController' => 'PhabricatorController', 'PhabricatorSettingsLogsPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsMainController' => 'PhabricatorController', 'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorSettingsPanel' => 'Phobject', 'PhabricatorSettingsPanelGroup' => 'Phobject', 'PhabricatorSettingsTimezoneController' => 'PhabricatorController', 'PhabricatorSetupCheck' => 'Phobject', 'PhabricatorSetupCheckTestCase' => 'PhabricatorTestCase', 'PhabricatorSetupIssue' => 'Phobject', 'PhabricatorSetupIssueUIExample' => 'PhabricatorUIExample', 'PhabricatorSetupIssueView' => 'AphrontView', 'PhabricatorShortSite' => 'PhabricatorSite', 'PhabricatorShowFiletreeSetting' => 'PhabricatorSelectSetting', 'PhabricatorSimpleEditType' => 'PhabricatorEditType', 'PhabricatorSite' => 'AphrontSite', 'PhabricatorSlackAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorSlowvoteApplication' => 'PhabricatorApplication', 'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvoteCloseController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteCommentController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteController' => 'PhabricatorController', 'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO', 'PhabricatorSlowvoteDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PhabricatorSlowvoteEditController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvotePoll' => array( 'PhabricatorSlowvoteDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSpacesInterface', ), 'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvotePollPHIDType' => 'PhabricatorPHIDType', 'PhabricatorSlowvoteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorSlowvoteReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorSlowvoteSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorSlowvoteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorSlowvoteTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorSlowvoteTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorSlowvoteTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorSlowvoteVoteController' => 'PhabricatorSlowvoteController', 'PhabricatorSlug' => 'Phobject', 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', 'PhabricatorSortTableUIExample' => 'PhabricatorUIExample', 'PhabricatorSourceCodeView' => 'AphrontView', 'PhabricatorSpaceEditField' => 'PhabricatorEditField', 'PhabricatorSpacesApplication' => 'PhabricatorApplication', 'PhabricatorSpacesArchiveController' => 'PhabricatorSpacesController', 'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesController' => 'PhabricatorController', 'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO', 'PhabricatorSpacesEditController' => 'PhabricatorSpacesController', 'PhabricatorSpacesInterface' => 'PhabricatorPHIDInterface', 'PhabricatorSpacesListController' => 'PhabricatorSpacesController', 'PhabricatorSpacesNamespace' => array( 'PhabricatorSpacesDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorSpacesNamespaceDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorSpacesNamespaceEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorSpacesNamespacePHIDType' => 'PhabricatorPHIDType', 'PhabricatorSpacesNamespaceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorSpacesNamespaceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorSpacesNamespaceTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorSpacesNamespaceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorSpacesNoAccessController' => 'PhabricatorSpacesController', 'PhabricatorSpacesRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorSpacesSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorSpacesSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorSpacesSearchField' => 'PhabricatorSearchTokenizerField', 'PhabricatorSpacesTestCase' => 'PhabricatorTestCase', 'PhabricatorSpacesViewController' => 'PhabricatorSpacesController', 'PhabricatorStandardCustomField' => 'PhabricatorCustomField', 'PhabricatorStandardCustomFieldBlueprints' => 'PhabricatorStandardCustomFieldTokenizer', 'PhabricatorStandardCustomFieldBool' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldCredential' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldDatasource' => 'PhabricatorStandardCustomFieldTokenizer', 'PhabricatorStandardCustomFieldDate' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldHeader' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldInt' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldLink' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldPHIDs' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldRemarkup' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldSelect' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldText' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldTokenizer' => 'PhabricatorStandardCustomFieldPHIDs', 'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldTokenizer', 'PhabricatorStandardPageView' => array( 'PhabricatorBarePageView', 'AphrontResponseProducerInterface', ), 'PhabricatorStandardSelectCustomFieldDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorStaticEditField' => 'PhabricatorEditField', 'PhabricatorStatusController' => 'PhabricatorController', 'PhabricatorStatusUIExample' => 'PhabricatorUIExample', 'PhabricatorStorageFixtureScopeGuard' => 'Phobject', 'PhabricatorStorageManagementAPI' => 'Phobject', 'PhabricatorStorageManagementAdjustWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDatabasesWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDestroyWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDumpWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementProbeWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementQuickstartWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementRenamespaceWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementShellWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementStatusWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementUpgradeWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorStoragePatch' => 'Phobject', 'PhabricatorStorageSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorStreamingProtocolAdapter' => 'PhabricatorProtocolAdapter', 'PhabricatorStringListEditField' => 'PhabricatorEditField', 'PhabricatorStringSetting' => 'PhabricatorSetting', 'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorSubscribersEditField' => 'PhabricatorTokenizerEditField', 'PhabricatorSubscribersQuery' => 'PhabricatorQuery', 'PhabricatorSubscriptionTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorSubscriptionsAddSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction', 'PhabricatorSubscriptionsAddSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction', 'PhabricatorSubscriptionsApplication' => 'PhabricatorApplication', 'PhabricatorSubscriptionsCurtainExtension' => 'PHUICurtainExtension', 'PhabricatorSubscriptionsEditController' => 'PhabricatorController', 'PhabricatorSubscriptionsEditEngineExtension' => 'PhabricatorEditEngineExtension', 'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor', 'PhabricatorSubscriptionsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction', 'PhabricatorSubscriptionsListController' => 'PhabricatorController', 'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction', 'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction', 'PhabricatorSubscriptionsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'PhabricatorSubscriptionsSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 'PhabricatorSubscriptionsSubscribeEmailCommand' => 'MetaMTAEmailTransactionCommand', 'PhabricatorSubscriptionsSubscribersPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorSubscriptionsTransactionController' => 'PhabricatorController', 'PhabricatorSubscriptionsUIEventListener' => 'PhabricatorEventListener', 'PhabricatorSubscriptionsUnsubscribeEmailCommand' => 'MetaMTAEmailTransactionCommand', 'PhabricatorSupportApplication' => 'PhabricatorApplication', 'PhabricatorSyntaxHighlighter' => 'Phobject', 'PhabricatorSyntaxHighlightingConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSyntaxStyle' => 'Phobject', 'PhabricatorSystemAction' => 'Phobject', 'PhabricatorSystemActionEngine' => 'Phobject', 'PhabricatorSystemActionGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorSystemActionLog' => 'PhabricatorSystemDAO', 'PhabricatorSystemActionRateLimitException' => 'Exception', 'PhabricatorSystemApplication' => 'PhabricatorApplication', 'PhabricatorSystemDAO' => 'PhabricatorLiskDAO', 'PhabricatorSystemDestructionGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorSystemDestructionLog' => 'PhabricatorSystemDAO', + 'PhabricatorSystemFaviconController' => 'PhabricatorController', 'PhabricatorSystemReadOnlyController' => 'PhabricatorController', 'PhabricatorSystemRemoveDestroyWorkflow' => 'PhabricatorSystemRemoveWorkflow', 'PhabricatorSystemRemoveLogWorkflow' => 'PhabricatorSystemRemoveWorkflow', 'PhabricatorSystemRemoveWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSystemSelectEncodingController' => 'PhabricatorController', 'PhabricatorSystemSelectHighlightController' => 'PhabricatorController', 'PhabricatorTOTPAuthFactor' => 'PhabricatorAuthFactor', 'PhabricatorTOTPAuthFactorTestCase' => 'PhabricatorTestCase', 'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon', 'PhabricatorTestApplication' => 'PhabricatorApplication', 'PhabricatorTestCase' => 'PhutilTestCase', 'PhabricatorTestController' => 'PhabricatorController', 'PhabricatorTestDataGenerator' => 'Phobject', 'PhabricatorTestNoCycleEdgeType' => 'PhabricatorEdgeType', 'PhabricatorTestStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorTestWorker' => 'PhabricatorWorker', 'PhabricatorTextAreaEditField' => 'PhabricatorEditField', 'PhabricatorTextEditField' => 'PhabricatorEditField', 'PhabricatorTime' => 'Phobject', 'PhabricatorTimeFormatSetting' => 'PhabricatorSelectSetting', 'PhabricatorTimeGuard' => 'Phobject', 'PhabricatorTimeTestCase' => 'PhabricatorTestCase', 'PhabricatorTimezoneIgnoreOffsetSetting' => 'PhabricatorInternalSetting', 'PhabricatorTimezoneSetting' => 'PhabricatorOptionGroupSetting', 'PhabricatorTimezoneSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorTitleGlyphsSetting' => 'PhabricatorSelectSetting', 'PhabricatorToken' => array( 'PhabricatorTokenDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorTokenController' => 'PhabricatorController', 'PhabricatorTokenCount' => 'PhabricatorTokenDAO', 'PhabricatorTokenCountQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorTokenDAO' => 'PhabricatorLiskDAO', 'PhabricatorTokenDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorTokenGiveController' => 'PhabricatorTokenController', 'PhabricatorTokenGiven' => array( 'PhabricatorTokenDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorTokenGivenController' => 'PhabricatorTokenController', 'PhabricatorTokenGivenEditor' => 'PhabricatorEditor', 'PhabricatorTokenGivenFeedStory' => 'PhabricatorFeedStory', 'PhabricatorTokenGivenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorTokenLeaderController' => 'PhabricatorTokenController', 'PhabricatorTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorTokenReceiverQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorTokenTokenPHIDType' => 'PhabricatorPHIDType', 'PhabricatorTokenUIEventListener' => 'PhabricatorEventListener', 'PhabricatorTokenizerEditField' => 'PhabricatorPHIDListEditField', 'PhabricatorTokensApplication' => 'PhabricatorApplication', 'PhabricatorTokensCurtainExtension' => 'PHUICurtainExtension', 'PhabricatorTokensSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorTokensToken' => array( 'PhabricatorTokenDAO', 'PhabricatorDestructibleInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorConduitResultInterface', ), 'PhabricatorTooltipUIExample' => 'PhabricatorUIExample', 'PhabricatorTransactionChange' => 'Phobject', 'PhabricatorTransactionRemarkupChange' => 'PhabricatorTransactionChange', 'PhabricatorTransactions' => 'Phobject', 'PhabricatorTransactionsApplication' => 'PhabricatorApplication', 'PhabricatorTransactionsDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorTransactionsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 'PhabricatorTransformedFile' => 'PhabricatorFileDAO', 'PhabricatorTranslationSetting' => 'PhabricatorOptionGroupSetting', 'PhabricatorTranslationsConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorTriggerAction' => 'Phobject', 'PhabricatorTriggerClock' => 'Phobject', 'PhabricatorTriggerClockTestCase' => 'PhabricatorTestCase', 'PhabricatorTriggerDaemon' => 'PhabricatorDaemon', 'PhabricatorTrivialTestCase' => 'PhabricatorTestCase', 'PhabricatorTwitchAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorTwitterAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorTypeaheadApplication' => 'PhabricatorApplication', 'PhabricatorTypeaheadCompositeDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorTypeaheadDatasource' => 'Phobject', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 'PhabricatorTypeaheadFunctionHelpController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadInvalidTokenException' => 'Exception', 'PhabricatorTypeaheadModularDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadMonogramDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorTypeaheadResult' => 'Phobject', 'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorTypeaheadTokenView' => 'AphrontTagView', 'PhabricatorUIConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorUIExample' => 'Phobject', 'PhabricatorUIExampleRenderController' => 'PhabricatorController', 'PhabricatorUIExamplesApplication' => 'PhabricatorApplication', 'PhabricatorUSEnglishTranslation' => 'PhutilTranslation', 'PhabricatorUnifiedDiffsSetting' => 'PhabricatorSelectSetting', 'PhabricatorUnitTestContentSource' => 'PhabricatorContentSource', 'PhabricatorUnitsTestCase' => 'PhabricatorTestCase', 'PhabricatorUnknownContentSource' => 'PhabricatorContentSource', 'PhabricatorUnsubscribedFromObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorUser' => array( 'PhabricatorUserDAO', 'PhutilPerson', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSSHPublicKeyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFulltextInterface', 'PhabricatorConduitResultInterface', ), 'PhabricatorUserBlurbField' => 'PhabricatorUserCustomField', 'PhabricatorUserCache' => 'PhabricatorUserDAO', 'PhabricatorUserCacheType' => 'Phobject', 'PhabricatorUserCardView' => 'AphrontTagView', 'PhabricatorUserConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorUserConfiguredCustomField' => array( 'PhabricatorUserCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorUserConfiguredCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'PhabricatorUserCustomField' => 'PhabricatorCustomField', 'PhabricatorUserCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'PhabricatorUserCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', 'PhabricatorUserEditor' => 'PhabricatorEditor', 'PhabricatorUserEditorTestCase' => 'PhabricatorTestCase', 'PhabricatorUserEmail' => 'PhabricatorUserDAO', 'PhabricatorUserEmailTestCase' => 'PhabricatorTestCase', 'PhabricatorUserFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorUserIconField' => 'PhabricatorUserCustomField', 'PhabricatorUserLog' => array( 'PhabricatorUserDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorUserLogView' => 'AphrontView', 'PhabricatorUserMessageCountCacheType' => 'PhabricatorUserCacheType', 'PhabricatorUserNotificationCountCacheType' => 'PhabricatorUserCacheType', 'PhabricatorUserPHIDResolver' => 'PhabricatorPHIDResolver', 'PhabricatorUserPreferences' => array( 'PhabricatorUserDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', ), 'PhabricatorUserPreferencesCacheType' => 'PhabricatorUserCacheType', 'PhabricatorUserPreferencesEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorUserPreferencesPHIDType' => 'PhabricatorPHIDType', 'PhabricatorUserPreferencesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorUserPreferencesSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorUserPreferencesTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorUserPreferencesTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorUserProfileImageCacheType' => 'PhabricatorUserCacheType', 'PhabricatorUserRealNameField' => 'PhabricatorUserCustomField', 'PhabricatorUserRolesField' => 'PhabricatorUserCustomField', 'PhabricatorUserSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorUserSinceField' => 'PhabricatorUserCustomField', 'PhabricatorUserStatusField' => 'PhabricatorUserCustomField', 'PhabricatorUserTestCase' => 'PhabricatorTestCase', 'PhabricatorUserTitleField' => 'PhabricatorUserCustomField', 'PhabricatorUserTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorUsersEditField' => 'PhabricatorTokenizerEditField', 'PhabricatorUsersPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorUsersSearchField' => 'PhabricatorSearchTokenizerField', 'PhabricatorVCSResponse' => 'AphrontResponse', 'PhabricatorVersionedDraft' => 'PhabricatorDraftDAO', 'PhabricatorVeryWowEnglishTranslation' => 'PhutilTranslation', 'PhabricatorViewerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorWatcherHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorWebContentSource' => 'PhabricatorContentSource', 'PhabricatorWeekStartDaySetting' => 'PhabricatorSelectSetting', 'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorWorker' => 'Phobject', 'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerArchiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerArchiveTaskQuery' => 'PhabricatorQuery', 'PhabricatorWorkerBulkJob' => array( 'PhabricatorWorkerDAO', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorWorkerBulkJobCreateWorker' => 'PhabricatorWorkerBulkJobWorker', 'PhabricatorWorkerBulkJobEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorWorkerBulkJobPHIDType' => 'PhabricatorPHIDType', 'PhabricatorWorkerBulkJobQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorWorkerBulkJobSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorWorkerBulkJobTaskWorker' => 'PhabricatorWorkerBulkJobWorker', 'PhabricatorWorkerBulkJobTestCase' => 'PhabricatorTestCase', 'PhabricatorWorkerBulkJobTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorWorkerBulkJobTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorWorkerBulkJobType' => 'Phobject', 'PhabricatorWorkerBulkJobWorker' => 'PhabricatorWorker', 'PhabricatorWorkerBulkTask' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO', 'PhabricatorWorkerDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorWorkerLeaseQuery' => 'PhabricatorQuery', 'PhabricatorWorkerManagementCancelWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementExecuteWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementFloodWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementFreeWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementRetryWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorWorkerPermanentFailureException' => 'Exception', 'PhabricatorWorkerSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController', 'PhabricatorWorkerTestCase' => 'PhabricatorTestCase', 'PhabricatorWorkerTrigger' => array( 'PhabricatorWorkerDAO', 'PhabricatorDestructibleInterface', 'PhabricatorPolicyInterface', ), 'PhabricatorWorkerTriggerEvent' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTriggerManagementFireWorkflow' => 'PhabricatorWorkerTriggerManagementWorkflow', 'PhabricatorWorkerTriggerManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorWorkerTriggerPHIDType' => 'PhabricatorPHIDType', 'PhabricatorWorkerTriggerQuery' => 'PhabricatorPolicyAwareQuery', 'PhabricatorWorkerYieldException' => 'Exception', 'PhabricatorWorkingCopyDiscoveryTestCase' => 'PhabricatorWorkingCopyTestCase', 'PhabricatorWorkingCopyPullTestCase' => 'PhabricatorWorkingCopyTestCase', 'PhabricatorWorkingCopyTestCase' => 'PhabricatorTestCase', 'PhabricatorXHPASTDAO' => 'PhabricatorLiskDAO', 'PhabricatorXHPASTParseTree' => 'PhabricatorXHPASTDAO', 'PhabricatorXHPASTViewController' => 'PhabricatorController', 'PhabricatorXHPASTViewFrameController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewFramesetController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewInputController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHPASTViewPanelController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewRunController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewStreamController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHPASTViewTreeController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHProfApplication' => 'PhabricatorApplication', 'PhabricatorXHProfController' => 'PhabricatorController', 'PhabricatorXHProfDAO' => 'PhabricatorLiskDAO', 'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController', 'PhabricatorXHProfProfileSymbolView' => 'PhabricatorXHProfProfileView', 'PhabricatorXHProfProfileTopLevelView' => 'PhabricatorXHProfProfileView', 'PhabricatorXHProfProfileView' => 'AphrontView', 'PhabricatorXHProfSample' => 'PhabricatorXHProfDAO', 'PhabricatorXHProfSampleListController' => 'PhabricatorXHProfController', 'PhabricatorYoutubeRemarkupRule' => 'PhutilRemarkupRule', 'Phame404Response' => 'AphrontHTMLResponse', 'PhameBlog' => array( 'PhameDAO', 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorConduitResultInterface', 'PhabricatorFulltextInterface', ), 'PhameBlog404Controller' => 'PhameLiveController', 'PhameBlogArchiveController' => 'PhameBlogController', 'PhameBlogController' => 'PhameController', 'PhameBlogCreateCapability' => 'PhabricatorPolicyCapability', 'PhameBlogDatasource' => 'PhabricatorTypeaheadDatasource', 'PhameBlogEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhameBlogEditController' => 'PhameBlogController', 'PhameBlogEditEngine' => 'PhabricatorEditEngine', 'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor', 'PhameBlogFeedController' => 'PhameBlogController', 'PhameBlogFulltextEngine' => 'PhabricatorFulltextEngine', 'PhameBlogHeaderPictureController' => 'PhameBlogController', 'PhameBlogListController' => 'PhameBlogController', 'PhameBlogListView' => 'AphrontTagView', 'PhameBlogManageController' => 'PhameBlogController', 'PhameBlogProfilePictureController' => 'PhameBlogController', 'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhameBlogReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhameBlogSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhameBlogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhameBlogSite' => 'PhameSite', 'PhameBlogTransaction' => 'PhabricatorApplicationTransaction', 'PhameBlogTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhameBlogViewController' => 'PhameLiveController', 'PhameConstants' => 'Phobject', 'PhameController' => 'PhabricatorController', 'PhameDAO' => 'PhabricatorLiskDAO', 'PhameDescriptionView' => 'AphrontTagView', 'PhameDraftListView' => 'AphrontTagView', 'PhameHomeController' => 'PhamePostController', 'PhameLiveController' => 'PhameController', 'PhameNextPostView' => 'AphrontTagView', 'PhamePost' => array( 'PhameDAO', 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', 'PhabricatorFlaggableInterface', 'PhabricatorProjectInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorConduitResultInterface', 'PhabricatorFulltextInterface', ), 'PhamePostArchiveController' => 'PhamePostController', 'PhamePostController' => 'PhameController', 'PhamePostEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhamePostEditController' => 'PhamePostController', 'PhamePostEditEngine' => 'PhabricatorEditEngine', 'PhamePostEditor' => 'PhabricatorApplicationTransactionEditor', 'PhamePostFulltextEngine' => 'PhabricatorFulltextEngine', 'PhamePostHistoryController' => 'PhamePostController', 'PhamePostListController' => 'PhamePostController', 'PhamePostListView' => 'AphrontTagView', 'PhamePostMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhamePostMoveController' => 'PhamePostController', 'PhamePostPublishController' => 'PhamePostController', 'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhamePostRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhamePostReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhamePostSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhamePostSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhamePostTransaction' => 'PhabricatorApplicationTransaction', 'PhamePostTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhamePostTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhamePostViewController' => 'PhameLiveController', 'PhameSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhameSite' => 'PhabricatorSite', 'PhluxController' => 'PhabricatorController', 'PhluxDAO' => 'PhabricatorLiskDAO', 'PhluxEditController' => 'PhluxController', 'PhluxListController' => 'PhluxController', 'PhluxTransaction' => 'PhabricatorApplicationTransaction', 'PhluxTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhluxVariable' => array( 'PhluxDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', ), 'PhluxVariableEditor' => 'PhabricatorApplicationTransactionEditor', 'PhluxVariablePHIDType' => 'PhabricatorPHIDType', 'PhluxVariableQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhluxViewController' => 'PhluxController', 'PholioController' => 'PhabricatorController', 'PholioDAO' => 'PhabricatorLiskDAO', 'PholioDefaultEditCapability' => 'PhabricatorPolicyCapability', 'PholioDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PholioImage' => array( 'PholioDAO', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', ), 'PholioImagePHIDType' => 'PhabricatorPHIDType', 'PholioImageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PholioImageUploadController' => 'PholioController', 'PholioInlineController' => 'PholioController', 'PholioInlineListController' => 'PholioController', 'PholioMock' => array( 'PholioDAO', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSpacesInterface', 'PhabricatorMentionableInterface', 'PhabricatorFulltextInterface', ), 'PholioMockArchiveController' => 'PholioController', 'PholioMockAuthorHeraldField' => 'PholioMockHeraldField', 'PholioMockCommentController' => 'PholioController', 'PholioMockDescriptionHeraldField' => 'PholioMockHeraldField', 'PholioMockEditController' => 'PholioController', 'PholioMockEditor' => 'PhabricatorApplicationTransactionEditor', 'PholioMockEmbedView' => 'AphrontView', 'PholioMockFulltextEngine' => 'PhabricatorFulltextEngine', 'PholioMockHasTaskEdgeType' => 'PhabricatorEdgeType', 'PholioMockHasTaskRelationship' => 'PholioMockRelationship', 'PholioMockHeraldField' => 'HeraldField', 'PholioMockHeraldFieldGroup' => 'HeraldFieldGroup', 'PholioMockImagesView' => 'AphrontView', 'PholioMockListController' => 'PholioController', 'PholioMockMailReceiver' => 'PhabricatorObjectMailReceiver', 'PholioMockNameHeraldField' => 'PholioMockHeraldField', 'PholioMockPHIDType' => 'PhabricatorPHIDType', 'PholioMockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PholioMockRelationship' => 'PhabricatorObjectRelationship', 'PholioMockRelationshipSource' => 'PhabricatorObjectRelationshipSource', 'PholioMockSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PholioMockThumbGridView' => 'AphrontView', 'PholioMockViewController' => 'PholioController', 'PholioRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PholioReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PholioSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PholioTransaction' => 'PhabricatorApplicationTransaction', 'PholioTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PholioTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PholioTransactionView' => 'PhabricatorApplicationTransactionView', 'PholioUploadedImageView' => 'AphrontView', 'PhortuneAccount' => array( 'PhortuneDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), 'PhortuneAccountEditController' => 'PhortuneController', 'PhortuneAccountEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortuneAccountHasMemberEdgeType' => 'PhabricatorEdgeType', 'PhortuneAccountListController' => 'PhortuneController', 'PhortuneAccountPHIDType' => 'PhabricatorPHIDType', 'PhortuneAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneAccountTransaction' => 'PhabricatorApplicationTransaction', 'PhortuneAccountTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhortuneAccountViewController' => 'PhortuneController', 'PhortuneAdHocCart' => 'PhortuneCartImplementation', 'PhortuneAdHocProduct' => 'PhortuneProductImplementation', 'PhortuneCart' => array( 'PhortuneDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), 'PhortuneCartAcceptController' => 'PhortuneCartController', 'PhortuneCartCancelController' => 'PhortuneCartController', 'PhortuneCartCheckoutController' => 'PhortuneCartController', 'PhortuneCartController' => 'PhortuneController', 'PhortuneCartEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortuneCartImplementation' => 'Phobject', 'PhortuneCartListController' => 'PhortuneController', 'PhortuneCartPHIDType' => 'PhabricatorPHIDType', 'PhortuneCartQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneCartReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhortuneCartSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhortuneCartTransaction' => 'PhabricatorApplicationTransaction', 'PhortuneCartTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhortuneCartUpdateController' => 'PhortuneCartController', 'PhortuneCartViewController' => 'PhortuneCartController', 'PhortuneCharge' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortuneChargeListController' => 'PhortuneController', 'PhortuneChargePHIDType' => 'PhabricatorPHIDType', 'PhortuneChargeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneChargeSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhortuneChargeTableView' => 'AphrontView', 'PhortuneConstants' => 'Phobject', 'PhortuneController' => 'PhabricatorController', 'PhortuneCreditCardForm' => 'Phobject', 'PhortuneCurrency' => 'Phobject', 'PhortuneCurrencySerializer' => 'PhabricatorLiskSerializer', 'PhortuneCurrencyTestCase' => 'PhabricatorTestCase', 'PhortuneDAO' => 'PhabricatorLiskDAO', 'PhortuneErrCode' => 'PhortuneConstants', 'PhortuneLandingController' => 'PhortuneController', 'PhortuneMemberHasAccountEdgeType' => 'PhabricatorEdgeType', 'PhortuneMemberHasMerchantEdgeType' => 'PhabricatorEdgeType', 'PhortuneMerchant' => array( 'PhortuneDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), 'PhortuneMerchantCapability' => 'PhabricatorPolicyCapability', 'PhortuneMerchantController' => 'PhortuneController', 'PhortuneMerchantEditController' => 'PhortuneMerchantController', 'PhortuneMerchantEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortuneMerchantHasMemberEdgeType' => 'PhabricatorEdgeType', 'PhortuneMerchantInvoiceCreateController' => 'PhortuneMerchantController', 'PhortuneMerchantListController' => 'PhortuneMerchantController', 'PhortuneMerchantPHIDType' => 'PhabricatorPHIDType', 'PhortuneMerchantQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneMerchantSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhortuneMerchantTransaction' => 'PhabricatorApplicationTransaction', 'PhortuneMerchantTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhortuneMerchantViewController' => 'PhortuneMerchantController', 'PhortuneMonthYearExpiryControl' => 'AphrontFormControl', 'PhortuneOrderTableView' => 'AphrontView', 'PhortunePayPalPaymentProvider' => 'PhortunePaymentProvider', 'PhortunePaymentMethod' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortunePaymentMethodCreateController' => 'PhortuneController', 'PhortunePaymentMethodDisableController' => 'PhortuneController', 'PhortunePaymentMethodEditController' => 'PhortuneController', 'PhortunePaymentMethodPHIDType' => 'PhabricatorPHIDType', 'PhortunePaymentMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortunePaymentProvider' => 'Phobject', 'PhortunePaymentProviderConfig' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', ), 'PhortunePaymentProviderConfigEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortunePaymentProviderConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortunePaymentProviderConfigTransaction' => 'PhabricatorApplicationTransaction', 'PhortunePaymentProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhortunePaymentProviderPHIDType' => 'PhabricatorPHIDType', 'PhortunePaymentProviderTestCase' => 'PhabricatorTestCase', 'PhortuneProduct' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortuneProductImplementation' => 'Phobject', 'PhortuneProductListController' => 'PhabricatorController', 'PhortuneProductPHIDType' => 'PhabricatorPHIDType', 'PhortuneProductQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneProductViewController' => 'PhortuneController', 'PhortuneProviderActionController' => 'PhortuneController', 'PhortuneProviderDisableController' => 'PhortuneMerchantController', 'PhortuneProviderEditController' => 'PhortuneMerchantController', 'PhortunePurchase' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortunePurchasePHIDType' => 'PhabricatorPHIDType', 'PhortunePurchaseQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhortuneStripePaymentProvider' => 'PhortunePaymentProvider', 'PhortuneSubscription' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortuneSubscriptionCart' => 'PhortuneCartImplementation', 'PhortuneSubscriptionEditController' => 'PhortuneController', 'PhortuneSubscriptionImplementation' => 'Phobject', 'PhortuneSubscriptionListController' => 'PhortuneController', 'PhortuneSubscriptionPHIDType' => 'PhabricatorPHIDType', 'PhortuneSubscriptionProduct' => 'PhortuneProductImplementation', 'PhortuneSubscriptionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneSubscriptionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhortuneSubscriptionTableView' => 'AphrontView', 'PhortuneSubscriptionViewController' => 'PhortuneController', 'PhortuneSubscriptionWorker' => 'PhabricatorWorker', 'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider', 'PhortuneWePayPaymentProvider' => 'PhortunePaymentProvider', 'PhragmentBrowseController' => 'PhragmentController', 'PhragmentCanCreateCapability' => 'PhabricatorPolicyCapability', 'PhragmentConduitAPIMethod' => 'ConduitAPIMethod', 'PhragmentController' => 'PhabricatorController', 'PhragmentCreateController' => 'PhragmentController', 'PhragmentDAO' => 'PhabricatorLiskDAO', 'PhragmentFragment' => array( 'PhragmentDAO', 'PhabricatorPolicyInterface', ), 'PhragmentFragmentPHIDType' => 'PhabricatorPHIDType', 'PhragmentFragmentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhragmentFragmentVersion' => array( 'PhragmentDAO', 'PhabricatorPolicyInterface', ), 'PhragmentFragmentVersionPHIDType' => 'PhabricatorPHIDType', 'PhragmentFragmentVersionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhragmentGetPatchConduitAPIMethod' => 'PhragmentConduitAPIMethod', 'PhragmentHistoryController' => 'PhragmentController', 'PhragmentPatchController' => 'PhragmentController', 'PhragmentPatchUtil' => 'Phobject', 'PhragmentPolicyController' => 'PhragmentController', 'PhragmentQueryFragmentsConduitAPIMethod' => 'PhragmentConduitAPIMethod', 'PhragmentRevertController' => 'PhragmentController', 'PhragmentSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhragmentSnapshot' => array( 'PhragmentDAO', 'PhabricatorPolicyInterface', ), 'PhragmentSnapshotChild' => array( 'PhragmentDAO', 'PhabricatorPolicyInterface', ), 'PhragmentSnapshotChildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhragmentSnapshotCreateController' => 'PhragmentController', 'PhragmentSnapshotDeleteController' => 'PhragmentController', 'PhragmentSnapshotPHIDType' => 'PhabricatorPHIDType', 'PhragmentSnapshotPromoteController' => 'PhragmentController', 'PhragmentSnapshotQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhragmentSnapshotViewController' => 'PhragmentController', 'PhragmentUpdateController' => 'PhragmentController', 'PhragmentVersionController' => 'PhragmentController', 'PhragmentZIPController' => 'PhragmentController', 'PhrequentConduitAPIMethod' => 'ConduitAPIMethod', 'PhrequentController' => 'PhabricatorController', 'PhrequentCurtainExtension' => 'PHUICurtainExtension', 'PhrequentDAO' => 'PhabricatorLiskDAO', 'PhrequentListController' => 'PhrequentController', 'PhrequentPopConduitAPIMethod' => 'PhrequentConduitAPIMethod', 'PhrequentPushConduitAPIMethod' => 'PhrequentConduitAPIMethod', 'PhrequentSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhrequentTimeBlock' => 'Phobject', 'PhrequentTimeBlockTestCase' => 'PhabricatorTestCase', 'PhrequentTimeSlices' => 'Phobject', 'PhrequentTrackController' => 'PhrequentController', 'PhrequentTrackingConduitAPIMethod' => 'PhrequentConduitAPIMethod', 'PhrequentTrackingEditor' => 'PhabricatorEditor', 'PhrequentUIEventListener' => 'PhabricatorEventListener', 'PhrequentUserTime' => array( 'PhrequentDAO', 'PhabricatorPolicyInterface', ), 'PhrequentUserTimeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhrictionChangeType' => 'PhrictionConstants', 'PhrictionConduitAPIMethod' => 'ConduitAPIMethod', 'PhrictionConstants' => 'Phobject', 'PhrictionContent' => array( 'PhrictionDAO', 'PhabricatorMarkupInterface', ), 'PhrictionController' => 'PhabricatorController', 'PhrictionCreateConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionDAO' => 'PhabricatorLiskDAO', 'PhrictionDeleteController' => 'PhrictionController', 'PhrictionDiffController' => 'PhrictionController', 'PhrictionDocument' => array( 'PhrictionDAO', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFulltextInterface', 'PhabricatorProjectInterface', 'PhabricatorApplicationTransactionInterface', ), 'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentController' => 'PhrictionController', 'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine', 'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter', 'PhrictionDocumentHeraldField' => 'HeraldField', 'PhrictionDocumentHeraldFieldGroup' => 'HeraldFieldGroup', 'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType', 'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhrictionDocumentStatus' => 'PhrictionConstants', 'PhrictionDocumentTitleHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionEditConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionEditController' => 'PhrictionController', 'PhrictionHistoryConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionHistoryController' => 'PhrictionController', 'PhrictionInfoConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionListController' => 'PhrictionController', 'PhrictionMarkupPreviewController' => 'PhabricatorController', 'PhrictionMoveController' => 'PhrictionController', 'PhrictionNewController' => 'PhrictionController', 'PhrictionRemarkupRule' => 'PhutilRemarkupRule', 'PhrictionReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhrictionSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhrictionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhrictionTransaction' => 'PhabricatorApplicationTransaction', 'PhrictionTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhrictionTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhrictionTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PolicyLockOptionType' => 'PhabricatorConfigJSONOptionType', 'PonderAddAnswerView' => 'AphrontView', 'PonderAnswer' => array( 'PonderDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorSubscribableInterface', 'PhabricatorDestructibleInterface', ), 'PonderAnswerCommentController' => 'PonderController', 'PonderAnswerEditController' => 'PonderController', 'PonderAnswerEditor' => 'PonderEditor', 'PonderAnswerHistoryController' => 'PonderController', 'PonderAnswerMailReceiver' => 'PhabricatorObjectMailReceiver', 'PonderAnswerPHIDType' => 'PhabricatorPHIDType', 'PonderAnswerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PonderAnswerReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PonderAnswerSaveController' => 'PonderController', 'PonderAnswerStatus' => 'PonderConstants', 'PonderAnswerTransaction' => 'PhabricatorApplicationTransaction', 'PonderAnswerTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PonderAnswerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PonderAnswerView' => 'AphrontTagView', 'PonderConstants' => 'Phobject', 'PonderController' => 'PhabricatorController', 'PonderDAO' => 'PhabricatorLiskDAO', 'PonderDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PonderEditor' => 'PhabricatorApplicationTransactionEditor', 'PonderFooterView' => 'AphrontTagView', 'PonderModerateCapability' => 'PhabricatorPolicyCapability', 'PonderQuestion' => array( 'PonderDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorMarkupInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', 'PhabricatorSpacesInterface', 'PhabricatorFulltextInterface', ), 'PonderQuestionCommentController' => 'PonderController', 'PonderQuestionCreateMailReceiver' => 'PhabricatorMailReceiver', 'PonderQuestionEditController' => 'PonderController', 'PonderQuestionEditor' => 'PonderEditor', 'PonderQuestionFulltextEngine' => 'PhabricatorFulltextEngine', 'PonderQuestionHistoryController' => 'PonderController', 'PonderQuestionListController' => 'PonderController', 'PonderQuestionMailReceiver' => 'PhabricatorObjectMailReceiver', 'PonderQuestionPHIDType' => 'PhabricatorPHIDType', 'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PonderQuestionReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PonderQuestionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PonderQuestionStatus' => 'PonderConstants', 'PonderQuestionStatusController' => 'PonderController', 'PonderQuestionTransaction' => 'PhabricatorApplicationTransaction', 'PonderQuestionTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PonderQuestionTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PonderQuestionViewController' => 'PonderController', 'PonderRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PonderSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'ProjectAddProjectsEmailCommand' => 'MetaMTAEmailTransactionCommand', 'ProjectBoardTaskCard' => 'Phobject', 'ProjectCanLockProjectsCapability' => 'PhabricatorPolicyCapability', 'ProjectConduitAPIMethod' => 'ConduitAPIMethod', 'ProjectCreateConduitAPIMethod' => 'ProjectConduitAPIMethod', 'ProjectCreateProjectsCapability' => 'PhabricatorPolicyCapability', 'ProjectDefaultEditCapability' => 'PhabricatorPolicyCapability', 'ProjectDefaultJoinCapability' => 'PhabricatorPolicyCapability', 'ProjectDefaultViewCapability' => 'PhabricatorPolicyCapability', 'ProjectEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod', 'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'ProjectRemarkupRuleTestCase' => 'PhabricatorTestCase', 'ProjectReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'ProjectSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'QueryFormattingTestCase' => 'PhabricatorTestCase', 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', 'ReleephBranch' => array( 'ReleephDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), 'ReleephBranchAccessController' => 'ReleephBranchController', 'ReleephBranchCommitFieldSpecification' => 'ReleephFieldSpecification', 'ReleephBranchController' => 'ReleephController', 'ReleephBranchCreateController' => 'ReleephProductController', 'ReleephBranchEditController' => 'ReleephBranchController', 'ReleephBranchEditor' => 'PhabricatorEditor', 'ReleephBranchHistoryController' => 'ReleephBranchController', 'ReleephBranchNamePreviewController' => 'ReleephController', 'ReleephBranchPHIDType' => 'PhabricatorPHIDType', 'ReleephBranchPreviewView' => 'AphrontFormControl', 'ReleephBranchQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephBranchSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ReleephBranchTemplate' => 'Phobject', 'ReleephBranchTransaction' => 'PhabricatorApplicationTransaction', 'ReleephBranchTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ReleephBranchViewController' => 'ReleephBranchController', 'ReleephCommitFinder' => 'Phobject', 'ReleephCommitFinderException' => 'Exception', 'ReleephCommitMessageFieldSpecification' => 'ReleephFieldSpecification', 'ReleephConduitAPIMethod' => 'ConduitAPIMethod', 'ReleephController' => 'PhabricatorController', 'ReleephDAO' => 'PhabricatorLiskDAO', 'ReleephDefaultFieldSelector' => 'ReleephFieldSelector', 'ReleephDependsOnFieldSpecification' => 'ReleephFieldSpecification', 'ReleephDiffChurnFieldSpecification' => 'ReleephFieldSpecification', 'ReleephDiffMessageFieldSpecification' => 'ReleephFieldSpecification', 'ReleephDiffSizeFieldSpecification' => 'ReleephFieldSpecification', 'ReleephFieldParseException' => 'Exception', 'ReleephFieldSelector' => 'Phobject', 'ReleephFieldSpecification' => array( 'PhabricatorCustomField', 'PhabricatorMarkupInterface', ), 'ReleephGetBranchesConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephIntentFieldSpecification' => 'ReleephFieldSpecification', 'ReleephLevelFieldSpecification' => 'ReleephFieldSpecification', 'ReleephOriginalCommitFieldSpecification' => 'ReleephFieldSpecification', 'ReleephProductActionController' => 'ReleephProductController', 'ReleephProductController' => 'ReleephController', 'ReleephProductCreateController' => 'ReleephProductController', 'ReleephProductEditController' => 'ReleephProductController', 'ReleephProductEditor' => 'PhabricatorApplicationTransactionEditor', 'ReleephProductHistoryController' => 'ReleephProductController', 'ReleephProductListController' => 'ReleephController', 'ReleephProductPHIDType' => 'PhabricatorPHIDType', 'ReleephProductQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephProductSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ReleephProductTransaction' => 'PhabricatorApplicationTransaction', 'ReleephProductTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ReleephProductViewController' => 'ReleephProductController', 'ReleephProject' => array( 'ReleephDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), 'ReleephQueryBranchesConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephQueryProductsConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephQueryRequestsConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephReasonFieldSpecification' => 'ReleephFieldSpecification', 'ReleephRequest' => array( 'ReleephDAO', 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', ), 'ReleephRequestActionController' => 'ReleephRequestController', 'ReleephRequestCommentController' => 'ReleephRequestController', 'ReleephRequestConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephRequestController' => 'ReleephController', 'ReleephRequestDifferentialCreateController' => 'ReleephController', 'ReleephRequestEditController' => 'ReleephBranchController', 'ReleephRequestMailReceiver' => 'PhabricatorObjectMailReceiver', 'ReleephRequestPHIDType' => 'PhabricatorPHIDType', 'ReleephRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephRequestReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'ReleephRequestSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ReleephRequestStatus' => 'Phobject', 'ReleephRequestTransaction' => 'PhabricatorApplicationTransaction', 'ReleephRequestTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ReleephRequestTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ReleephRequestTransactionalEditor' => 'PhabricatorApplicationTransactionEditor', 'ReleephRequestTypeaheadControl' => 'AphrontFormControl', 'ReleephRequestTypeaheadController' => 'PhabricatorTypeaheadDatasourceController', 'ReleephRequestView' => 'AphrontView', 'ReleephRequestViewController' => 'ReleephBranchController', 'ReleephRequestorFieldSpecification' => 'ReleephFieldSpecification', 'ReleephRevisionFieldSpecification' => 'ReleephFieldSpecification', 'ReleephSeverityFieldSpecification' => 'ReleephLevelFieldSpecification', 'ReleephSummaryFieldSpecification' => 'ReleephFieldSpecification', 'ReleephWorkCanPushConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephWorkGetAuthorInfoConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephWorkGetBranchCommitMessageConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephWorkGetBranchConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephWorkGetCommitMessageConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephWorkNextRequestConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephWorkRecordConduitAPIMethod' => 'ReleephConduitAPIMethod', 'ReleephWorkRecordPickStatusConduitAPIMethod' => 'ReleephConduitAPIMethod', 'RemarkupProcessConduitAPIMethod' => 'ConduitAPIMethod', 'RepositoryConduitAPIMethod' => 'ConduitAPIMethod', 'RepositoryQueryConduitAPIMethod' => 'RepositoryConduitAPIMethod', 'ShellLogView' => 'AphrontView', 'SlowvoteConduitAPIMethod' => 'ConduitAPIMethod', 'SlowvoteEmbedView' => 'AphrontView', 'SlowvoteInfoConduitAPIMethod' => 'SlowvoteConduitAPIMethod', 'SlowvoteRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'SubscriptionListDialogBuilder' => 'Phobject', 'SubscriptionListStringBuilder' => 'Phobject', 'TokenConduitAPIMethod' => 'ConduitAPIMethod', 'TokenGiveConduitAPIMethod' => 'TokenConduitAPIMethod', 'TokenGivenConduitAPIMethod' => 'TokenConduitAPIMethod', 'TokenQueryConduitAPIMethod' => 'TokenConduitAPIMethod', 'UserConduitAPIMethod' => 'ConduitAPIMethod', 'UserDisableConduitAPIMethod' => 'UserConduitAPIMethod', 'UserEnableConduitAPIMethod' => 'UserConduitAPIMethod', 'UserFindConduitAPIMethod' => 'UserConduitAPIMethod', 'UserQueryConduitAPIMethod' => 'UserConduitAPIMethod', 'UserSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'UserWhoAmIConduitAPIMethod' => 'UserConduitAPIMethod', ), )); diff --git a/src/aphront/httpparametertype/AphrontFileHTTPParameterType.php b/src/aphront/httpparametertype/AphrontFileHTTPParameterType.php new file mode 100644 index 0000000000..ceff8c1ddb --- /dev/null +++ b/src/aphront/httpparametertype/AphrontFileHTTPParameterType.php @@ -0,0 +1,60 @@ +getFileKey($key); + return $request->getExists($key) || + $request->getFileExists($file_key); + } + + protected function getParameterValue(AphrontRequest $request, $key) { + $value = $request->getStrList($key); + if ($value) { + return head($value); + } + + // NOTE: At least for now, we'll attempt to read a direct upload if we + // miss on a PHID. Currently, PHUIFormFileControl does a client-side + // upload on workflow forms (which is good) but doesn't have a hook for + // non-workflow forms (which isn't as good). Giving it a hook is desirable, + // but complicated. Even if we do hook it, it may be reasonable to keep + // this code around as a fallback if the client-side JS goes awry. + + $file_key = $this->getFileKey($key); + if (!$request->getFileExists($file_key)) { + return null; + } + + $viewer = $this->getViewer(); + $file = PhabricatorFile::newFromPHPUpload( + idx($_FILES, $file_key), + array( + 'authorPHID' => $viewer->getPHID(), + 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, + )); + return $file->getPHID(); + } + + protected function getParameterTypeName() { + return 'file'; + } + + protected function getParameterFormatDescriptions() { + return array( + pht('A file PHID.'), + ); + } + + protected function getParameterExamples() { + return array( + 'v=PHID-FILE-wxyz', + ); + } + +} diff --git a/src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php b/src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php index 1fc61ffb2c..4d04707598 100644 --- a/src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php +++ b/src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php @@ -1,244 +1,258 @@ getTransactionType()) { case PhabricatorAuthSSHKeyTransaction::TYPE_NAME: return $object->getName(); case PhabricatorAuthSSHKeyTransaction::TYPE_KEY: return $object->getEntireKey(); case PhabricatorAuthSSHKeyTransaction::TYPE_DEACTIVATE: return !$object->getIsActive(); } } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorAuthSSHKeyTransaction::TYPE_NAME: case PhabricatorAuthSSHKeyTransaction::TYPE_KEY: return $xaction->getNewValue(); case PhabricatorAuthSSHKeyTransaction::TYPE_DEACTIVATE: return (bool)$xaction->getNewValue(); } } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $value = $xaction->getNewValue(); switch ($xaction->getTransactionType()) { case PhabricatorAuthSSHKeyTransaction::TYPE_NAME: $object->setName($value); return; case PhabricatorAuthSSHKeyTransaction::TYPE_KEY: $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($value); $type = $public_key->getType(); $body = $public_key->getBody(); $comment = $public_key->getComment(); $object->setKeyType($type); $object->setKeyBody($body); $object->setKeyComment($comment); return; case PhabricatorAuthSSHKeyTransaction::TYPE_DEACTIVATE: if ($value) { $new = null; } else { $new = 1; } $object->setIsActive($new); return; } } protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { return; } protected function validateTransaction( PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); switch ($type) { case PhabricatorAuthSSHKeyTransaction::TYPE_NAME: $missing = $this->validateIsEmptyTextField( $object->getName(), $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), pht('SSH key name is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } break; case PhabricatorAuthSSHKeyTransaction::TYPE_KEY; $missing = $this->validateIsEmptyTextField( $object->getName(), $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), pht('SSH key material is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } else { foreach ($xactions as $xaction) { $new = $xaction->getNewValue(); try { $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($new); } catch (Exception $ex) { $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), $ex->getMessage(), $xaction); } } } break; case PhabricatorAuthSSHKeyTransaction::TYPE_DEACTIVATE: foreach ($xactions as $xaction) { if (!$xaction->getNewValue()) { $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), pht('SSH keys can not be reactivated.'), $xaction); } } break; } return $errors; } protected function didCatchDuplicateKeyException( PhabricatorLiskDAO $object, array $xactions, Exception $ex) { $errors = array(); $errors[] = new PhabricatorApplicationTransactionValidationError( PhabricatorAuthSSHKeyTransaction::TYPE_KEY, pht('Duplicate'), pht( 'This public key is already associated with another user or device. '. 'Each key must unambiguously identify a single unique owner.'), null); throw new PhabricatorApplicationTransactionValidationException($errors); } protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function getMailSubjectPrefix() { return pht('[SSH Key]'); } protected function getMailThreadID(PhabricatorLiskDAO $object) { return 'ssh-key-'.$object->getPHID(); } + protected function applyFinalEffects( + PhabricatorLiskDAO $object, + array $xactions) { + + // After making any change to an SSH key, drop the authfile cache so it + // is regenerated the next time anyone authenticates. + $cache = PhabricatorCaches::getMutableCache(); + $authfile_key = PhabricatorAuthSSHKeyQuery::AUTHFILE_CACHEKEY; + $cache->deleteKey($authfile_key); + + return $xactions; + } + + protected function getMailTo(PhabricatorLiskDAO $object) { return $object->getObject()->getSSHKeyNotifyPHIDs(); } protected function getMailCC(PhabricatorLiskDAO $object) { return array(); } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new PhabricatorAuthSSHKeyReplyHandler()) ->setMailReceiver($object); } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $id = $object->getID(); $name = $object->getName(); $phid = $object->getPHID(); $mail = id(new PhabricatorMetaMTAMail()) ->setSubject(pht('SSH Key %d: %s', $id, $name)) ->addHeader('Thread-Topic', $phid); // The primary value of this mail is alerting users to account compromises, // so force delivery. In particular, this mail should still be delievered // even if "self mail" is disabled. $mail->setForceDelivery(true); return $mail; } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $body = parent::buildMailBody($object, $xactions); $body->addTextSection( pht('SECURITY WARNING'), pht( 'If you do not recognize this change, it may indicate your account '. 'has been compromised.')); $detail_uri = $object->getURI(); $detail_uri = PhabricatorEnv::getProductionURI($detail_uri); $body->addLinkSection(pht('SSH KEY DETAIL'), $detail_uri); return $body; } } diff --git a/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php b/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php index 4592d794fa..6ba047d100 100644 --- a/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php +++ b/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php @@ -1,130 +1,132 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withObjectPHIDs(array $object_phids) { $this->objectPHIDs = $object_phids; return $this; } public function withKeys(array $keys) { assert_instances_of($keys, 'PhabricatorAuthSSHPublicKey'); $this->keys = $keys; return $this; } public function withIsActive($active) { $this->isActive = $active; return $this; } public function newResultObject() { return new PhabricatorAuthSSHKey(); } protected function loadPage() { return $this->loadStandardPage($this->newResultObject()); } protected function willFilterPage(array $keys) { $object_phids = mpull($keys, 'getObjectPHID'); $objects = id(new PhabricatorObjectQuery()) ->setViewer($this->getViewer()) ->setParentQuery($this) ->withPHIDs($object_phids) ->execute(); $objects = mpull($objects, null, 'getPHID'); foreach ($keys as $key => $ssh_key) { $object = idx($objects, $ssh_key->getObjectPHID()); // We must have an object, and that object must be a valid object for // SSH keys. if (!$object || !($object instanceof PhabricatorSSHPublicKeyInterface)) { $this->didRejectResult($ssh_key); unset($keys[$key]); continue; } $ssh_key->attachObject($object); } return $keys; } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, 'phid IN (%Ls)', $this->phids); } if ($this->objectPHIDs !== null) { $where[] = qsprintf( $conn, 'objectPHID IN (%Ls)', $this->objectPHIDs); } if ($this->keys !== null) { $sql = array(); foreach ($this->keys as $key) { $sql[] = qsprintf( $conn, '(keyType = %s AND keyIndex = %s)', $key->getType(), $key->getHash()); } $where[] = implode(' OR ', $sql); } if ($this->isActive !== null) { if ($this->isActive) { $where[] = qsprintf( $conn, 'isActive = %d', 1); } else { $where[] = qsprintf( $conn, 'isActive IS NULL'); } } return $where; } public function getQueryApplicationClass() { return 'PhabricatorAuthApplication'; } } diff --git a/src/applications/cache/PhabricatorCaches.php b/src/applications/cache/PhabricatorCaches.php index c9bd304ccf..a725238150 100644 --- a/src/applications/cache/PhabricatorCaches.php +++ b/src/applications/cache/PhabricatorCaches.php @@ -1,394 +1,411 @@ setCaches($caches); } /* -( Request Cache )------------------------------------------------------ */ /** * Get a request cache stack. * * This cache stack is destroyed after each logical request. In particular, * it is destroyed periodically by the daemons, while `static` caches are * not. * * @return PhutilKeyValueCacheStack Request cache stack. */ public static function getRequestCache() { if (!self::$requestCache) { self::$requestCache = new PhutilInRequestKeyValueCache(); } return self::$requestCache; } /** * Destroy the request cache. * * This is called at the beginning of each logical request. * * @return void */ public static function destroyRequestCache() { self::$requestCache = null; } /* -( Immutable Cache )---------------------------------------------------- */ /** * Gets an immutable cache stack. * * This stack trades mutability away for improved performance. Normally, it is * APC + DB. * * In the general case with multiple web frontends, this stack can not be * cleared, so it is only appropriate for use if the value of a given key is * permanent and immutable. * * @return PhutilKeyValueCacheStack Best immutable stack available. * @task immutable */ public static function getImmutableCache() { static $cache; if (!$cache) { $caches = self::buildImmutableCaches(); $cache = self::newStackFromCaches($caches); } return $cache; } /** * Build the immutable cache stack. * * @return list List of caches. * @task immutable */ private static function buildImmutableCaches() { $caches = array(); $apc = new PhutilAPCKeyValueCache(); if ($apc->isAvailable()) { $caches[] = $apc; } $caches[] = new PhabricatorKeyValueDatabaseCache(); return $caches; } + public static function getMutableCache() { + static $cache; + if (!$cache) { + $caches = self::buildMutableCaches(); + $cache = self::newStackFromCaches($caches); + } + return $cache; + } + + private static function buildMutableCaches() { + $caches = array(); + + $caches[] = new PhabricatorKeyValueDatabaseCache(); + + return $caches; + } + /* -( Repository Graph Cache )--------------------------------------------- */ public static function getRepositoryGraphL1Cache() { static $cache; if (!$cache) { $caches = self::buildRepositoryGraphL1Caches(); $cache = self::newStackFromCaches($caches); } return $cache; } private static function buildRepositoryGraphL1Caches() { $caches = array(); $request = new PhutilInRequestKeyValueCache(); $request->setLimit(32); $caches[] = $request; $apc = new PhutilAPCKeyValueCache(); if ($apc->isAvailable()) { $caches[] = $apc; } return $caches; } public static function getRepositoryGraphL2Cache() { static $cache; if (!$cache) { $caches = self::buildRepositoryGraphL2Caches(); $cache = self::newStackFromCaches($caches); } return $cache; } private static function buildRepositoryGraphL2Caches() { $caches = array(); $caches[] = new PhabricatorKeyValueDatabaseCache(); return $caches; } /* -( Server State Cache )------------------------------------------------- */ /** * Highly specialized cache for storing server process state. * * We use this cache to track initial steps in the setup phase, before * configuration is loaded. * * This cache does NOT use the cache namespace (it must be accessed before * we build configuration), and is global across all instances on the host. * * @return PhutilKeyValueCacheStack Best available server state cache stack. * @task setup */ public static function getServerStateCache() { static $cache; if (!$cache) { $caches = self::buildSetupCaches('phabricator-server'); // NOTE: We are NOT adding a cache namespace here! This cache is shared // across all instances on the host. $caches = self::addProfilerToCaches($caches); $cache = id(new PhutilKeyValueCacheStack()) ->setCaches($caches); } return $cache; } /* -( Setup Cache )-------------------------------------------------------- */ /** * Highly specialized cache for performing setup checks. We use this cache * to determine if we need to run expensive setup checks when the page * loads. Without it, we would need to run these checks every time. * * Normally, this cache is just APC. In the absence of APC, this cache * degrades into a slow, quirky on-disk cache. * * NOTE: Do not use this cache for anything else! It is not a general-purpose * cache! * * @return PhutilKeyValueCacheStack Most qualified available cache stack. * @task setup */ public static function getSetupCache() { static $cache; if (!$cache) { $caches = self::buildSetupCaches('phabricator-setup'); $cache = self::newStackFromCaches($caches); } return $cache; } /** * @task setup */ private static function buildSetupCaches($cache_name) { // If this is the CLI, just build a setup cache. if (php_sapi_name() == 'cli') { return array(); } // In most cases, we should have APC. This is an ideal cache for our // purposes -- it's fast and empties on server restart. $apc = new PhutilAPCKeyValueCache(); if ($apc->isAvailable()) { return array($apc); } // If we don't have APC, build a poor approximation on disk. This is still // much better than nothing; some setup steps are quite slow. $disk_path = self::getSetupCacheDiskCachePath($cache_name); if ($disk_path) { $disk = new PhutilOnDiskKeyValueCache(); $disk->setCacheFile($disk_path); $disk->setWait(0.1); if ($disk->isAvailable()) { return array($disk); } } return array(); } /** * @task setup */ private static function getSetupCacheDiskCachePath($name) { // The difficulty here is in choosing a path which will change on server // restart (we MUST have this property), but as rarely as possible // otherwise (we desire this property to give the cache the best hit rate // we can). // Unfortunately, we don't have a very good strategy for minimizing the // churn rate of the cache. We previously tried to use the parent process // PID in some cases, but this was not reliable. See T9599 for one case of // this. $pid_basis = getmypid(); // If possible, we also want to know when the process launched, so we can // drop the cache if a process restarts but gets the same PID an earlier // process had. "/proc" is not available everywhere (e.g., not on OSX), but // check if we have it. $epoch_basis = null; $stat = @stat("/proc/{$pid_basis}"); if ($stat !== false) { $epoch_basis = $stat['ctime']; } $tmp_dir = sys_get_temp_dir(); $tmp_path = $tmp_dir.DIRECTORY_SEPARATOR.$name; if (!file_exists($tmp_path)) { @mkdir($tmp_path); } $is_ok = self::testTemporaryDirectory($tmp_path); if (!$is_ok) { $tmp_path = $tmp_dir; $is_ok = self::testTemporaryDirectory($tmp_path); if (!$is_ok) { // We can't find anywhere to write the cache, so just bail. return null; } } $tmp_name = 'setup-'.$pid_basis; if ($epoch_basis) { $tmp_name .= '.'.$epoch_basis; } $tmp_name .= '.cache'; return $tmp_path.DIRECTORY_SEPARATOR.$tmp_name; } /** * @task setup */ private static function testTemporaryDirectory($dir) { if (!@file_exists($dir)) { return false; } if (!@is_dir($dir)) { return false; } if (!@is_writable($dir)) { return false; } return true; } private static function addProfilerToCaches(array $caches) { foreach ($caches as $key => $cache) { $pcache = new PhutilKeyValueCacheProfiler($cache); $pcache->setProfiler(PhutilServiceProfiler::getInstance()); $caches[$key] = $pcache; } return $caches; } private static function addNamespaceToCaches(array $caches) { $namespace = self::getNamespace(); if (!$namespace) { return $caches; } foreach ($caches as $key => $cache) { $ncache = new PhutilKeyValueCacheNamespace($cache); $ncache->setNamespace($namespace); $caches[$key] = $ncache; } return $caches; } /** * Deflate a value, if deflation is available and has an impact. * * If the value is larger than 1KB, we have `gzdeflate()`, we successfully * can deflate it, and it benefits from deflation, we deflate it. Otherwise * we leave it as-is. * * Data can later be inflated with @{method:inflateData}. * * @param string String to attempt to deflate. * @return string|null Deflated string, or null if it was not deflated. * @task compress */ public static function maybeDeflateData($value) { $len = strlen($value); if ($len <= 1024) { return null; } if (!function_exists('gzdeflate')) { return null; } $deflated = gzdeflate($value); if ($deflated === false) { return null; } $deflated_len = strlen($deflated); if ($deflated_len >= ($len / 2)) { return null; } return $deflated; } /** * Inflate data previously deflated by @{method:maybeDeflateData}. * * @param string Deflated data, from @{method:maybeDeflateData}. * @return string Original, uncompressed data. * @task compress */ public static function inflateData($value) { if (!function_exists('gzinflate')) { throw new Exception( pht( '%s is not available; unable to read deflated data!', 'gzinflate()')); } $value = gzinflate($value); if ($value === false) { throw new Exception(pht('Failed to inflate data!')); } return $value; } } diff --git a/src/applications/cache/PhabricatorKeyValueDatabaseCache.php b/src/applications/cache/PhabricatorKeyValueDatabaseCache.php index 99060478c0..c6a52024fe 100644 --- a/src/applications/cache/PhabricatorKeyValueDatabaseCache.php +++ b/src/applications/cache/PhabricatorKeyValueDatabaseCache.php @@ -1,174 +1,174 @@ digestKeys(array_keys($keys)); $conn_w = $this->establishConnection('w'); $sql = array(); foreach ($map as $key => $hash) { $value = $keys[$key]; list($format, $storage_value) = $this->willWriteValue($key, $value); $sql[] = qsprintf( $conn_w, '(%s, %s, %s, %B, %d, %nd)', $hash, $key, $format, $storage_value, time(), $ttl ? (time() + $ttl) : null); } $guard = AphrontWriteGuard::beginScopedUnguardedWrites(); foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { queryfx( $conn_w, 'INSERT INTO %T (cacheKeyHash, cacheKey, cacheFormat, cacheData, cacheCreated, cacheExpires) VALUES %Q ON DUPLICATE KEY UPDATE cacheKey = VALUES(cacheKey), cacheFormat = VALUES(cacheFormat), cacheData = VALUES(cacheData), cacheCreated = VALUES(cacheCreated), cacheExpires = VALUES(cacheExpires)', $this->getTableName(), $chunk); } unset($guard); } return $this; } public function getKeys(array $keys) { $results = array(); if ($keys) { $map = $this->digestKeys($keys); $rows = queryfx_all( $this->establishConnection('r'), 'SELECT * FROM %T WHERE cacheKeyHash IN (%Ls)', $this->getTableName(), $map); $rows = ipull($rows, null, 'cacheKey'); foreach ($keys as $key) { if (empty($rows[$key])) { continue; } $row = $rows[$key]; if ($row['cacheExpires'] && ($row['cacheExpires'] < time())) { continue; } try { $results[$key] = $this->didReadValue( $row['cacheFormat'], $row['cacheData']); } catch (Exception $ex) { // Treat this as a cache miss. phlog($ex); } } } return $results; } public function deleteKeys(array $keys) { if ($keys) { $map = $this->digestKeys($keys); queryfx( $this->establishConnection('w'), 'DELETE FROM %T WHERE cacheKeyHash IN (%Ls)', $this->getTableName(), - $keys); + $map); } return $this; } public function destroyCache() { queryfx( $this->establishConnection('w'), 'DELETE FROM %T', $this->getTableName()); return $this; } /* -( Raw Cache Access )--------------------------------------------------- */ public function establishConnection($mode) { // TODO: This is the only concrete table we have on the database right // now. return id(new PhabricatorMarkupCache())->establishConnection($mode); } public function getTableName() { return 'cache_general'; } /* -( Implementation )----------------------------------------------------- */ private function digestKeys(array $keys) { $map = array(); foreach ($keys as $key) { $map[$key] = PhabricatorHash::digestForIndex($key); } return $map; } private function willWriteValue($key, $value) { if (!is_string($value)) { throw new Exception(pht('Only strings may be written to the DB cache!')); } static $can_deflate; if ($can_deflate === null) { $can_deflate = function_exists('gzdeflate') && PhabricatorEnv::getEnvConfig('cache.enable-deflate'); } if ($can_deflate) { $deflated = PhabricatorCaches::maybeDeflateData($value); if ($deflated !== null) { return array(self::CACHE_FORMAT_DEFLATE, $deflated); } } return array(self::CACHE_FORMAT_RAW, $value); } private function didReadValue($format, $value) { switch ($format) { case self::CACHE_FORMAT_RAW: return $value; case self::CACHE_FORMAT_DEFLATE: return PhabricatorCaches::inflateData($value); default: throw new Exception(pht('Unknown cache format.')); } } } diff --git a/src/applications/calendar/application/PhabricatorCalendarApplication.php b/src/applications/calendar/application/PhabricatorCalendarApplication.php index 208fc83ae9..fa95f6951b 100644 --- a/src/applications/calendar/application/PhabricatorCalendarApplication.php +++ b/src/applications/calendar/application/PhabricatorCalendarApplication.php @@ -1,120 +1,137 @@ [1-9]\d*)(?:/(?P\d+)/)?' => 'PhabricatorCalendarEventViewController', '/calendar/' => array( '(?:query/(?P[^/]+)/(?:(?P\d+)/'. '(?P\d+)/)?(?:(?P\d+)/)?)?' => 'PhabricatorCalendarEventListController', 'event/' => array( $this->getEditRoutePattern('edit/') => 'PhabricatorCalendarEventEditController', 'drag/(?P[1-9]\d*)/' => 'PhabricatorCalendarEventDragController', 'cancel/(?P[1-9]\d*)/' => 'PhabricatorCalendarEventCancelController', '(?Pjoin|decline|accept)/(?P[1-9]\d*)/' => 'PhabricatorCalendarEventJoinController', 'export/(?P[1-9]\d*)/(?P[^/]*)' => 'PhabricatorCalendarEventExportController', ), 'export/' => array( $this->getQueryRoutePattern() => 'PhabricatorCalendarExportListController', $this->getEditRoutePattern('edit/') => 'PhabricatorCalendarExportEditController', '(?P[1-9]\d*)/' => 'PhabricatorCalendarExportViewController', 'ics/(?P[^/]+)/(?P[^/]*)' => 'PhabricatorCalendarExportICSController', 'disable/(?P[1-9]\d*)/' => 'PhabricatorCalendarExportDisableController', - + ), + 'import/' => array( + $this->getQueryRoutePattern() + => 'PhabricatorCalendarImportListController', + $this->getEditRoutePattern('edit/') + => 'PhabricatorCalendarImportEditController', + '(?P[1-9]\d*)/' + => 'PhabricatorCalendarImportViewController', + 'disable/(?P[1-9]\d*)/' + => 'PhabricatorCalendarImportDisableController', + 'delete/(?P[1-9]\d*)/' + => 'PhabricatorCalendarImportDeleteController', + 'drop/' + => 'PhabricatorCalendarImportDropController', + 'log/' => array( + $this->getQueryRoutePattern() + => 'PhabricatorCalendarImportLogListController', + ), ), ), ); } public function getHelpDocumentationArticles(PhabricatorUser $viewer) { return array( array( 'name' => pht('Calendar User Guide'), 'href' => PhabricatorEnv::getDoclink('Calendar User Guide'), ), ); } public function getMailCommandObjects() { return array( 'event' => array( 'name' => pht('Email Commands: Events'), 'header' => pht('Interacting with Calendar Events'), 'object' => new PhabricatorCalendarEvent(), 'summary' => pht( 'This page documents the commands you can use to interact with '. 'events in Calendar. These commands work when creating new tasks '. 'via email and when replying to existing tasks.'), ), ); } protected function getCustomCapabilities() { return array( PhabricatorCalendarEventDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created events.'), 'template' => PhabricatorCalendarEventPHIDType::TYPECONST, 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), PhabricatorCalendarEventDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created events.'), 'template' => PhabricatorCalendarEventPHIDType::TYPECONST, 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), ); } } diff --git a/src/applications/calendar/controller/PhabricatorCalendarController.php b/src/applications/calendar/controller/PhabricatorCalendarController.php index 36a9bfbbe9..88ffba9380 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarController.php @@ -1,21 +1,40 @@ setViewer($viewer) ->setEvents($events) ->writeICSDocument(); return id(new AphrontFileResponse()) ->setDownload($file_name) ->setMimeType('text/calendar') ->setContent($ics_data); } + protected function newImportedEventResponse(PhabricatorCalendarEvent $event) { + if (!$event->isImportedEvent()) { + return null; + } + + // Give the user a specific, detailed message if they try to edit an + // imported event via common web paths. Other edits (including those via + // the API) are blocked by the normal policy system, but this makes it more + // clear exactly why the event can't be edited. + + return $this->newDialog() + ->setTitle(pht('Can Not Edit Imported Event')) + ->appendParagraph( + pht( + 'This event has been imported from an external source and '. + 'can not be edited.')) + ->addCancelButton($event->getURI(), pht('Done')); + } + } diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php index 63ce289970..fbf7f9d45e 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php @@ -1,111 +1,119 @@ getViewer(); $id = $request->getURIData('id'); + // Just check CAN_VIEW first. Then we'll check if this is an import so + // we can raise a better error. $event = id(new PhabricatorCalendarEventQuery()) ->setViewer($viewer) ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) ->executeOne(); if (!$event) { return new Aphront404Response(); } + $response = $this->newImportedEventResponse($event); + if ($response) { + return $response; + } + + // Now that we've done the import check, check for CAN_EDIT. + PhabricatorPolicyFilter::requireCapability( + $viewer, + $event, + PhabricatorPolicyCapability::CAN_EDIT); + $cancel_uri = $event->getURI(); $is_parent = $event->isParentEvent(); $is_child = $event->isChildEvent(); $is_cancelled = $event->getIsCancelled(); if ($is_child) { $is_parent_cancelled = $event->getParentEvent()->getIsCancelled(); } else { $is_parent_cancelled = false; } $validation_exception = null; if ($request->isFormPost()) { $xactions = array(); $xaction = id(new PhabricatorCalendarEventTransaction()) ->setTransactionType( PhabricatorCalendarEventCancelTransaction::TRANSACTIONTYPE) ->setNewValue(!$is_cancelled); $editor = id(new PhabricatorCalendarEventEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true); try { $editor->applyTransactions($event, array($xaction)); return id(new AphrontRedirectResponse())->setURI($cancel_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; } } if ($is_cancelled) { if ($is_parent_cancelled) { $title = pht('Cannot Reinstate Instance'); $paragraph = pht( 'You cannot reinstate an instance of a cancelled recurring event.'); $cancel = pht('Back'); $submit = null; } else if ($is_child) { $title = pht('Reinstate Instance'); $paragraph = pht( 'Reinstate this instance of this recurring event?'); $cancel = pht('Back'); $submit = pht('Reinstate Instance'); } else if ($is_parent) { $title = pht('Reinstate Recurring Event'); $paragraph = pht( 'Reinstate all instances of this recurring event which have not '. 'been individually cancelled?'); $cancel = pht('Back'); $submit = pht('Reinstate Recurring Event'); } else { $title = pht('Reinstate Event'); $paragraph = pht('Reinstate this event?'); $cancel = pht('Back'); $submit = pht('Reinstate Event'); } } else { if ($is_child) { $title = pht('Cancel Instance'); $paragraph = pht('Cancel this instance of this recurring event?'); $cancel = pht('Back'); $submit = pht('Cancel Instance'); } else if ($is_parent) { $title = pht('Cancel Recurrin Event'); $paragraph = pht('Cancel this entire series of recurring events?'); $cancel = pht('Back'); $submit = pht('Cancel Recurring Event'); } else { $title = pht('Cancel Event'); $paragraph = pht( 'Cancel this event? You can always reinstate the event later.'); $cancel = pht('Back'); $submit = pht('Cancel Event'); } } return $this->newDialog() ->setTitle($title) ->setValidationException($validation_exception) ->appendParagraph($paragraph) ->addCancelButton($cancel_uri, $cancel) ->addSubmitButton($submit); } } diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php index b5beea9019..7c01e795b7 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php @@ -1,12 +1,26 @@ getViewer(); + + $id = $request->getURIData('id'); + if ($id) { + $event = id(new PhabricatorCalendarEventQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->executeOne(); + $response = $this->newImportedEventResponse($event); + if ($response) { + return $response; + } + } + return id(new PhabricatorCalendarEventEditEngine()) ->setController($this) ->buildResponse(); } } diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php b/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php index 9b58d39dec..52ad8cb133 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php @@ -1,78 +1,83 @@ getViewer(); $id = $request->getURIData('id'); $event = id(new PhabricatorCalendarEventQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$event) { return new Aphront404Response(); } + $response = $this->newImportedEventResponse($event); + if ($response) { + return $response; + } + $cancel_uri = $event->getURI(); $action = $request->getURIData('action'); switch ($action) { case 'accept': $is_join = true; break; case 'decline': $is_join = false; break; default: $is_join = !$event->getIsUserAttending($viewer->getPHID()); break; } $validation_exception = null; if ($request->isFormPost()) { if ($is_join) { $xaction_type = PhabricatorCalendarEventAcceptTransaction::TRANSACTIONTYPE; } else { $xaction_type = PhabricatorCalendarEventDeclineTransaction::TRANSACTIONTYPE; } $xaction = id(new PhabricatorCalendarEventTransaction()) ->setTransactionType($xaction_type) ->setNewValue(true); $editor = id(new PhabricatorCalendarEventEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true); try { $editor->applyTransactions($event, array($xaction)); return id(new AphrontRedirectResponse())->setURI($cancel_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; } } if ($is_join) { $title = pht('Join Event'); $paragraph = pht('Would you like to join this event?'); $submit = pht('Join'); } else { $title = pht('Decline Event'); $paragraph = pht('Would you like to decline this event?'); $submit = pht('Decline'); } return $this->newDialog() ->setTitle($title) ->setValidationException($validation_exception) ->appendParagraph($paragraph) ->addCancelButton($cancel_uri) ->addSubmitButton($submit); } } diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventListController.php b/src/applications/calendar/controller/PhabricatorCalendarEventListController.php index ac9015fbcf..711b2eeb3e 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventListController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventListController.php @@ -1,53 +1,61 @@ getURIData('year'); $month = $request->getURIData('month'); $day = $request->getURIData('day'); $engine = new PhabricatorCalendarEventSearchEngine(); if ($month && $year) { $engine->setCalendarYearAndMonthAndDay($year, $month, $day); } $nav_items = $this->buildNavigationItems(); return $engine ->setNavigationItems($nav_items) ->setController($this) ->buildResponse(); } protected function buildApplicationCrumbs() { $crumbs = parent::buildApplicationCrumbs(); id(new PhabricatorCalendarEventEditEngine()) ->setViewer($this->getViewer()) ->addActionToCrumbs($crumbs); return $crumbs; } protected function buildNavigationItems() { $items = array(); $items[] = id(new PHUIListItemView()) ->setType(PHUIListItemView::TYPE_LABEL) ->setName(pht('Import/Export')); + $items[] = id(new PHUIListItemView()) + ->setName('Imports') + ->setHref('/calendar/import/'); + $items[] = id(new PHUIListItemView()) ->setName('Exports') ->setHref('/calendar/export/'); return $items; } } diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php index 89e8109a4c..c8bc9b5593 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php @@ -1,537 +1,573 @@ getViewer(); $event = $this->loadEvent(); if (!$event) { return new Aphront404Response(); } // If we looked up or generated a stub event, redirect to that event's // canonical URI. $id = $request->getURIData('id'); if ($event->getID() != $id) { $uri = $event->getURI(); return id(new AphrontRedirectResponse())->setURI($uri); } $monogram = $event->getMonogram(); $page_title = $monogram.' '.$event->getName(); $crumbs = $this->buildApplicationCrumbs(); $start = $event->newStartDateTime() ->newPHPDateTime(); $crumbs->addTextCrumb( $start->format('F Y'), '/calendar/query/month/'.$start->format('Y/m/')); $crumbs->addTextCrumb( $start->format('D jS'), '/calendar/query/month/'.$start->format('Y/m/d/')); $crumbs->addTextCrumb($monogram); $crumbs->setBorder(true); $timeline = $this->buildTransactionTimeline( $event, new PhabricatorCalendarEventTransactionQuery()); $header = $this->buildHeaderView($event); $subheader = $this->buildSubheaderView($event); $curtain = $this->buildCurtain($event); $details = $this->buildPropertySection($event); $recurring = $this->buildRecurringSection($event); $description = $this->buildDescriptionView($event); $comment_view = id(new PhabricatorCalendarEventEditEngine()) ->setViewer($viewer) ->buildEditEngineCommentView($event); $timeline->setQuoteRef($monogram); $comment_view->setTransactionTimeline($timeline); $details_header = id(new PHUIHeaderView()) ->setHeader(pht('Details')); $recurring_header = $this->buildRecurringHeader($event); + // NOTE: This is a bit hacky: for imported events, we're just hiding the + // comment form without actually preventing comments. Users could still + // submit a request to add comments to these events. This isn't really a + // major problem since they can't do anything truly bad and there isn't an + // easy way to selectively disable this or some other similar behaviors + // today, but it would probably be nice to fully disable these + // "pseudo-edits" (like commenting and probably subscribing and awarding + // tokens) at some point. + if ($event->isImportedEvent()) { + $comment_view = null; + $timeline->setShouldTerminate(true); + } + $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setSubheader($subheader) ->setMainColumn( array( $timeline, $comment_view, )) ->setCurtain($curtain) ->addPropertySection(pht('Description'), $description) ->addPropertySection($recurring_header, $recurring) ->addPropertySection($details_header, $details); return $this->newPage() ->setTitle($page_title) ->setCrumbs($crumbs) ->setPageObjectPHIDs(array($event->getPHID())) ->appendChild($view); } private function buildHeaderView( PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); $id = $event->getID(); if ($event->isCancelledEvent()) { $icon = 'fa-ban'; $color = 'red'; $status = pht('Cancelled'); } else { $icon = 'fa-check'; $color = 'bluegrey'; $status = pht('Active'); } $header = id(new PHUIHeaderView()) ->setUser($viewer) ->setHeader($event->getName()) ->setStatus($icon, $color, $status) ->setPolicyObject($event) ->setHeaderIcon($event->getIcon()); + if ($event->isImportedEvent()) { + $header->addTag( + id(new PHUITagView()) + ->setType(PHUITagView::TYPE_SHADE) + ->setName(pht('Imported')) + ->setIcon('fa-download') + ->setHref($event->getImportSource()->getURI()) + ->setShade('orange')); + } + foreach ($this->buildRSVPActions($event) as $action) { $header->addActionLink($action); } return $header; } private function buildCurtain(PhabricatorCalendarEvent $event) { $viewer = $this->getRequest()->getUser(); $id = $event->getID(); $is_attending = $event->getIsUserAttending($viewer->getPHID()); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $event, PhabricatorPolicyCapability::CAN_EDIT); $edit_uri = "event/edit/{$id}/"; if ($event->isChildEvent()) { $edit_label = pht('Edit This Instance'); } else { $edit_label = pht('Edit Event'); } $curtain = $this->newCurtainView($event); if ($edit_label && $edit_uri) { $curtain->addAction( id(new PhabricatorActionView()) ->setName($edit_label) ->setIcon('fa-pencil') ->setHref($this->getApplicationURI($edit_uri)) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); } + $can_attend = !$event->isImportedEvent(); + if ($is_attending) { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Decline Event')) ->setIcon('fa-user-times') ->setHref($this->getApplicationURI("event/join/{$id}/")) + ->setDisabled(!$can_attend) ->setWorkflow(true)); } else { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Join Event')) ->setIcon('fa-user-plus') ->setHref($this->getApplicationURI("event/join/{$id}/")) + ->setDisabled(!$can_attend) ->setWorkflow(true)); } $cancel_uri = $this->getApplicationURI("event/cancel/{$id}/"); $cancel_disabled = !$can_edit; if ($event->isChildEvent()) { $cancel_label = pht('Cancel This Instance'); $reinstate_label = pht('Reinstate This Instance'); if ($event->getParentEvent()->getIsCancelled()) { $cancel_disabled = true; } } else if ($event->isParentEvent()) { $cancel_label = pht('Cancel All'); $reinstate_label = pht('Reinstate All'); } else { $cancel_label = pht('Cancel Event'); $reinstate_label = pht('Reinstate Event'); } if ($event->isCancelledEvent()) { $curtain->addAction( id(new PhabricatorActionView()) ->setName($reinstate_label) ->setIcon('fa-plus') ->setHref($cancel_uri) ->setDisabled($cancel_disabled) ->setWorkflow(true)); } else { $curtain->addAction( id(new PhabricatorActionView()) ->setName($cancel_label) ->setIcon('fa-times') ->setHref($cancel_uri) ->setDisabled($cancel_disabled) ->setWorkflow(true)); } $ics_name = $event->getICSFilename(); $export_uri = $this->getApplicationURI("event/export/{$id}/{$ics_name}"); $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Export as .ics')) ->setIcon('fa-download') ->setHref($export_uri)); return $curtain; } private function buildPropertySection( PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); $properties = id(new PHUIPropertyListView()) ->setUser($viewer); $invitees = $event->getInvitees(); foreach ($invitees as $key => $invitee) { if ($invitee->isUninvited()) { unset($invitees[$key]); } } if ($invitees) { $invitee_list = new PHUIStatusListView(); $icon_invited = PHUIStatusItemView::ICON_OPEN; $icon_attending = PHUIStatusItemView::ICON_ACCEPT; $icon_declined = PHUIStatusItemView::ICON_REJECT; $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED; $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING; $status_declined = PhabricatorCalendarEventInvitee::STATUS_DECLINED; $icon_map = array( $status_invited => $icon_invited, $status_attending => $icon_attending, $status_declined => $icon_declined, ); $icon_color_map = array( $status_invited => null, $status_attending => 'green', $status_declined => 'red', ); foreach ($invitees as $invitee) { $item = new PHUIStatusItemView(); $invitee_phid = $invitee->getInviteePHID(); $status = $invitee->getStatus(); $target = $viewer->renderHandle($invitee_phid); $icon = $icon_map[$status]; $icon_color = $icon_color_map[$status]; $item->setIcon($icon, $icon_color) ->setTarget($target); $invitee_list->addItem($item); } } else { $invitee_list = phutil_tag( 'em', array(), pht('None')); } + if ($event->isImportedEvent()) { + $properties->addProperty( + pht('Imported By'), + pht( + '%s from %s', + $viewer->renderHandle($event->getImportAuthorPHID()), + $viewer->renderHandle($event->getImportSourcePHID()))); + } + $properties->addProperty( pht('Invitees'), $invitee_list); $properties->invokeWillRenderEvent(); return $properties; } private function buildRecurringHeader(PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); if (!$event->getIsRecurring()) { return null; } $header = id(new PHUIHeaderView()) ->setHeader(pht('Recurring Event')); $sequence = $event->getSequenceIndex(); if ($event->isParentEvent()) { $parent = $event; } else { $parent = $event->getParentEvent(); } if ($parent->isValidSequenceIndex($viewer, $sequence + 1)) { $next_uri = $parent->getURI().'/'.($sequence + 1); $has_next = true; } else { $next_uri = null; $has_next = false; } if ($sequence) { if ($sequence > 1) { $previous_uri = $parent->getURI().'/'.($sequence - 1); } else { $previous_uri = $parent->getURI(); } $has_previous = true; } else { $has_previous = false; $previous_uri = null; } $prev_button = id(new PHUIButtonView()) ->setTag('a') ->setIcon('fa-chevron-left') ->setHref($previous_uri) ->setDisabled(!$has_previous) ->setText(pht('Previous')); $next_button = id(new PHUIButtonView()) ->setTag('a') ->setIcon('fa-chevron-right') ->setHref($next_uri) ->setDisabled(!$has_next) ->setText(pht('Next')); $header ->addActionLink($next_button) ->addActionLink($prev_button); return $header; } private function buildRecurringSection(PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); if (!$event->getIsRecurring()) { return null; } $properties = id(new PHUIPropertyListView()) ->setUser($viewer); $is_parent = $event->isParentEvent(); if ($is_parent) { $parent_link = null; } else { $parent = $event->getParentEvent(); $parent_link = $viewer ->renderHandle($parent->getPHID()) ->render(); } $rrule = $event->newRecurrenceRule(); if ($rrule) { $frequency = $rrule->getFrequency(); } else { $frequency = null; } switch ($frequency) { case PhutilCalendarRecurrenceRule::FREQUENCY_DAILY: if ($is_parent) { $message = pht('This event repeats every day.'); } else { $message = pht( 'This event is an instance of %s, and repeats every day.', $parent_link); } break; case PhutilCalendarRecurrenceRule::FREQUENCY_WEEKLY: if ($is_parent) { $message = pht('This event repeats every week.'); } else { $message = pht( 'This event is an instance of %s, and repeats every week.', $parent_link); } break; case PhutilCalendarRecurrenceRule::FREQUENCY_MONTHLY: if ($is_parent) { $message = pht('This event repeats every month.'); } else { $message = pht( 'This event is an instance of %s, and repeats every month.', $parent_link); } break; case PhutilCalendarRecurrenceRule::FREQUENCY_YEARLY: if ($is_parent) { $message = pht('This event repeats every year.'); } else { $message = pht( 'This event is an instance of %s, and repeats every year.', $parent_link); } break; } $properties->addProperty(pht('Event Series'), $message); return $properties; } private function buildDescriptionView( PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); $properties = id(new PHUIPropertyListView()) ->setUser($viewer); if (strlen($event->getDescription())) { $description = new PHUIRemarkupView($viewer, $event->getDescription()); $properties->addTextContent($description); return $properties; } return null; } private function loadEvent() { $request = $this->getRequest(); $viewer = $this->getViewer(); $id = $request->getURIData('id'); $sequence = $request->getURIData('sequence'); // We're going to figure out which event you're trying to look at. Most of // the time this is simple, but you may be looking at an instance of a // recurring event which we haven't generated an object for. // If you are, we're going to generate a "stub" event so we have a real // ID and PHID to work with, since the rest of the infrastructure relies // on these identifiers existing. // Load the event identified by ID first. $event = id(new PhabricatorCalendarEventQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$event) { return null; } // If we aren't looking at an instance of this event, this is a completely // normal request and we can just return this event. if (!$sequence) { return $event; } // When you view "E123/999", E123 is normally the parent event. However, // you might visit a different instance first instead and then fiddle // with the URI. If the event we're looking at is a child, we are going // to act on the parent instead. if ($event->isChildEvent()) { $event = $event->getParentEvent(); } // Try to load the instance. If it already exists, we're all done and // can just return it. $instance = id(new PhabricatorCalendarEventQuery()) ->setViewer($viewer) ->withInstanceSequencePairs( array( array($event->getPHID(), $sequence), )) ->executeOne(); if ($instance) { return $instance; } if (!$viewer->isLoggedIn()) { throw new Exception( pht( 'This event instance has not been created yet. Log in to create '. 'it.')); } if (!$event->isValidSequenceIndex($viewer, $sequence)) { return null; } return $event->newStub($viewer, $sequence); } private function buildSubheaderView(PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); $host_phid = $event->getHostPHID(); $handles = $viewer->loadHandles(array($host_phid)); $handle = $handles[$host_phid]; $host = $viewer->renderHandle($host_phid); $host = phutil_tag('strong', array(), $host); $image_uri = $handles[$host_phid]->getImageURI(); $image_href = $handles[$host_phid]->getURI(); $date = $event->renderEventDate($viewer, true); $content = pht('Hosted by %s on %s.', $host, $date); return id(new PHUIHeadThingView()) ->setImage($image_uri) ->setImageHref($image_href) ->setContent($content); } private function buildRSVPActions(PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); $id = $event->getID(); $invite_status = $event->getUserInviteStatus($viewer->getPHID()); $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED; $is_invite_pending = ($invite_status == $status_invited); if (!$is_invite_pending) { return array(); } $decline_button = id(new PHUIButtonView()) ->setTag('a') ->setIcon('fa-times grey') ->setHref($this->getApplicationURI("/event/decline/{$id}/")) ->setWorkflow(true) ->setText(pht('Decline')); $accept_button = id(new PHUIButtonView()) ->setTag('a') ->setIcon('fa-check green') ->setHref($this->getApplicationURI("/event/accept/{$id}/")) ->setWorkflow(true) ->setText(pht('Accept')); return array($decline_button, $accept_button); } } diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportDeleteController.php b/src/applications/calendar/controller/PhabricatorCalendarImportDeleteController.php new file mode 100644 index 0000000000..fd65777515 --- /dev/null +++ b/src/applications/calendar/controller/PhabricatorCalendarImportDeleteController.php @@ -0,0 +1,64 @@ +getViewer(); + + $import = id(new PhabricatorCalendarImportQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$import) { + return new Aphront404Response(); + } + + $import_uri = $import->getURI(); + + $engine = $import->getEngine(); + if (!$engine->canDeleteAnyEvents($viewer, $import)) { + return $this->newDialog() + ->setTitle(pht('No Imported Events')) + ->appendParagraph( + pht( + 'No events from this source currently exist. They may have '. + 'failed to import, have been updated by another source, or '. + 'already have been deleted.')) + ->addCancelButton($import_uri, pht('Done')); + } + + if ($request->isFormPost()) { + $xactions = array(); + $xactions[] = id(new PhabricatorCalendarImportTransaction()) + ->setTransactionType( + PhabricatorCalendarImportDeleteTransaction::TRANSACTIONTYPE) + ->setNewValue(true); + + $editor = id(new PhabricatorCalendarImportEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->setContentSourceFromRequest($request); + + $editor->applyTransactions($import, $xactions); + + return id(new AphrontRedirectResponse())->setURI($import_uri); + } + + return $this->newDialog() + ->setTitle(pht('Delete Imported Events')) + ->appendParagraph( + pht( + 'Delete all the events that were imported from this source? '. + 'This action can not be undone.')) + ->addCancelButton($import_uri) + ->addSubmitButton(pht('Delete Events')); + } + +} diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportDisableController.php b/src/applications/calendar/controller/PhabricatorCalendarImportDisableController.php new file mode 100644 index 0000000000..5a9b720be4 --- /dev/null +++ b/src/applications/calendar/controller/PhabricatorCalendarImportDisableController.php @@ -0,0 +1,71 @@ +getViewer(); + + $import = id(new PhabricatorCalendarImportQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$import) { + return new Aphront404Response(); + } + + $import_uri = $import->getURI(); + $is_disable = !$import->getIsDisabled(); + + if (!$import->getEngine()->canDisable($viewer, $import)) { + $reason = $import->getEngine()->explainCanDisable($viewer, $import); + return $this->newDialog() + ->setTitle(pht('Unable to Disable')) + ->appendParagraph($reason) + ->addCancelButton($import_uri); + } + + if ($request->isFormPost()) { + $xactions = array(); + $xactions[] = id(new PhabricatorCalendarImportTransaction()) + ->setTransactionType( + PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE) + ->setNewValue($is_disable ? 1 : 0); + + $editor = id(new PhabricatorCalendarImportEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->setContentSourceFromRequest($request); + + $editor->applyTransactions($import, $xactions); + + return id(new AphrontRedirectResponse())->setURI($import_uri); + } + + if ($is_disable) { + $title = pht('Disable Import'); + $body = pht( + 'Disable this import? Events from this source will no longer be '. + 'updated.'); + $button = pht('Disable Import'); + } else { + $title = pht('Enable Import'); + $body = pht( + 'Enable this import? Events from this source will be updated again.'); + $button = pht('Enable Import'); + } + + return $this->newDialog() + ->setTitle($title) + ->appendParagraph($body) + ->addCancelButton($import_uri) + ->addSubmitButton($button); + } + +} diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php b/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php new file mode 100644 index 0000000000..03f515087b --- /dev/null +++ b/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php @@ -0,0 +1,86 @@ +getViewer(); + + if (!$request->validateCSRF()) { + return new Aphront400Response(); + } + + $cancel_uri = $this->getApplicationURI(); + + $ids = $request->getStrList('h'); + if ($ids) { + $files = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withIDs($ids) + ->setRaisePolicyExceptions(true) + ->execute(); + } else { + $files = array(); + } + + if (!$files) { + return $this->newDialog() + ->setTitle(pht('Nothing Uploaded')) + ->appendParagraph( + pht( + 'Drag and drop .ics files to upload them and import them into '. + 'Calendar.')) + ->addCancelButton($cancel_uri, pht('Done')); + } + + $engine = new PhabricatorCalendarICSImportEngine(); + $imports = array(); + foreach ($files as $file) { + $import = PhabricatorCalendarImport::initializeNewCalendarImport( + $viewer, + clone $engine); + + $xactions = array(); + $xactions[] = id(new PhabricatorCalendarImportTransaction()) + ->setTransactionType( + PhabricatorCalendarImportICSFileTransaction::TRANSACTIONTYPE) + ->setNewValue($file->getPHID()); + + $editor = id(new PhabricatorCalendarImportEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->setContentSourceFromRequest($request); + + $editor->applyTransactions($import, $xactions); + + $imports[] = $import; + } + + $import_phids = mpull($imports, 'getPHID'); + $events = id(new PhabricatorCalendarEventQuery()) + ->setViewer($viewer) + ->withImportSourcePHIDs($import_phids) + ->execute(); + + if (count($events) == 1) { + // The user imported exactly one event. This is consistent with dropping + // a .ics file from an email; just take them to the event. + $event = head($events); + $next_uri = $event->getURI(); + } else if (count($imports) > 1) { + // The user imported multiple different files. Take them to a summary + // list of generated import activity. + $source_phids = implode(',', $import_phids); + $next_uri = '/calendar/import/log/?importSourcePHIDs='.$source_phids; + } else { + // The user imported one file, which had zero or more than one event. + // Take them to the import detail page. + $import = head($imports); + $next_uri = $import->getURI(); + } + + return id(new AphrontRedirectResponse())->setURI($next_uri); + } + +} diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportEditController.php b/src/applications/calendar/controller/PhabricatorCalendarImportEditController.php new file mode 100644 index 0000000000..0af9fa1540 --- /dev/null +++ b/src/applications/calendar/controller/PhabricatorCalendarImportEditController.php @@ -0,0 +1,92 @@ +setController($this); + + $id = $request->getURIData('id'); + if (!$id) { + $list_uri = $this->getApplicationURI('import/'); + + $import_type = $request->getStr('importType'); + $import_engines = PhabricatorCalendarImportEngine::getAllImportEngines(); + if (empty($import_engines[$import_type])) { + return $this->buildEngineTypeResponse($list_uri); + } + + $import_engine = $import_engines[$import_type]; + + $engine + ->addContextParameter('importType', $import_type) + ->setImportEngine($import_engine); + } + + return $engine->buildResponse(); + } + + private function buildEngineTypeResponse($cancel_uri) { + $import_engines = PhabricatorCalendarImportEngine::getAllImportEngines(); + + $request = $this->getRequest(); + $viewer = $this->getViewer(); + + $e_import = null; + $errors = array(); + if ($request->isFormPost()) { + $e_import = pht('Required'); + $errors[] = pht( + 'To import events, you must select a source to import from.'); + } + + $type_control = id(new AphrontFormRadioButtonControl()) + ->setLabel(pht('Import Type')) + ->setName('importType') + ->setError($e_import); + + foreach ($import_engines as $import_engine) { + $type_control->addButton( + $import_engine->getImportEngineType(), + $import_engine->getImportEngineName(), + $import_engine->getImportEngineHint()); + } + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('New Import')); + $crumbs->setBorder(true); + + $title = pht('Choose Import Type'); + $header = id(new PHUIHeaderView()) + ->setHeader(pht('New Import')) + ->setHeaderIcon('fa-upload'); + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild($type_control) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue(pht('Continue')) + ->addCancelButton($cancel_uri)); + + $box = id(new PHUIObjectBoxView()) + ->setFormErrors($errors) + ->setHeaderText(pht('Import')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setForm($form); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter( + array( + $box, + )); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); + } + +} diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportListController.php b/src/applications/calendar/controller/PhabricatorCalendarImportListController.php new file mode 100644 index 0000000000..df78ea2445 --- /dev/null +++ b/src/applications/calendar/controller/PhabricatorCalendarImportListController.php @@ -0,0 +1,25 @@ +setController($this) + ->buildResponse(); + } + + protected function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + $crumbs->addAction( + id(new PHUIListItemView()) + ->setName(pht('Import Events')) + ->setHref($this->getApplicationURI('import/edit/')) + ->setIcon('fa-upload')); + + return $crumbs; + } + + +} diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarImportLogListController.php similarity index 59% copy from src/applications/calendar/controller/PhabricatorCalendarEventEditController.php copy to src/applications/calendar/controller/PhabricatorCalendarImportLogListController.php index b5beea9019..91bdef4fdf 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarImportLogListController.php @@ -1,12 +1,12 @@ setController($this) ->buildResponse(); } } diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportViewController.php b/src/applications/calendar/controller/PhabricatorCalendarImportViewController.php new file mode 100644 index 0000000000..59b0f86915 --- /dev/null +++ b/src/applications/calendar/controller/PhabricatorCalendarImportViewController.php @@ -0,0 +1,241 @@ +getViewer(); + + $import = id(new PhabricatorCalendarImportQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->executeOne(); + if (!$import) { + return new Aphront404Response(); + } + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb( + pht('Imports'), + '/calendar/import/'); + $crumbs->addTextCrumb(pht('Import %d', $import->getID())); + $crumbs->setBorder(true); + + $timeline = $this->buildTransactionTimeline( + $import, + new PhabricatorCalendarImportTransactionQuery()); + $timeline->setShouldTerminate(true); + + $header = $this->buildHeaderView($import); + $curtain = $this->buildCurtain($import); + $details = $this->buildPropertySection($import); + + $log_messages = $this->buildLogMessages($import); + $imported_events = $this->buildImportedEvents($import); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setMainColumn( + array( + $log_messages, + $imported_events, + $timeline, + )) + ->setCurtain($curtain) + ->addPropertySection(pht('Details'), $details); + + $page_title = pht( + 'Import %d %s', + $import->getID(), + $import->getDisplayName()); + + return $this->newPage() + ->setTitle($page_title) + ->setCrumbs($crumbs) + ->setPageObjectPHIDs(array($import->getPHID())) + ->appendChild($view); + } + + private function buildHeaderView( + PhabricatorCalendarImport $import) { + $viewer = $this->getViewer(); + $id = $import->getID(); + + if ($import->getIsDisabled()) { + $icon = 'fa-ban'; + $color = 'red'; + $status = pht('Disabled'); + } else { + $icon = 'fa-check'; + $color = 'bluegrey'; + $status = pht('Active'); + } + + $header = id(new PHUIHeaderView()) + ->setViewer($viewer) + ->setHeader($import->getDisplayName()) + ->setStatus($icon, $color, $status) + ->setPolicyObject($import); + + return $header; + } + + private function buildCurtain(PhabricatorCalendarImport $import) { + $viewer = $this->getViewer(); + $id = $import->getID(); + + $curtain = $this->newCurtainView($import); + $engine = $import->getEngine(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $import, + PhabricatorPolicyCapability::CAN_EDIT); + + $edit_uri = "import/edit/{$id}/"; + $edit_uri = $this->getApplicationURI($edit_uri); + + $can_disable = ($can_edit && $engine->canDisable($viewer, $import)); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Import')) + ->setIcon('fa-pencil') + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit) + ->setHref($edit_uri)); + + $disable_uri = "import/disable/{$id}/"; + $disable_uri = $this->getApplicationURI($disable_uri); + if ($import->getIsDisabled()) { + $disable_name = pht('Enable Import'); + $disable_icon = 'fa-check'; + } else { + $disable_name = pht('Disable Import'); + $disable_icon = 'fa-ban'; + } + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName($disable_name) + ->setIcon($disable_icon) + ->setDisabled(!$can_disable) + ->setWorkflow(true) + ->setHref($disable_uri)); + + + if ($can_edit) { + $can_delete = $engine->canDeleteAnyEvents($viewer, $import); + } else { + $can_delete = false; + } + + $delete_uri = "import/delete/{$id}/"; + $delete_uri = $this->getApplicationURI($delete_uri); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Delete Imported Events')) + ->setIcon('fa-times') + ->setDisabled(!$can_delete) + ->setWorkflow(true) + ->setHref($delete_uri)); + + return $curtain; + } + + private function buildPropertySection( + PhabricatorCalendarImport $import) { + $viewer = $this->getViewer(); + + $properties = id(new PHUIPropertyListView()) + ->setViewer($viewer); + + $engine = $import->getEngine(); + + $properties->addProperty( + pht('Source Type'), + $engine->getImportEngineTypeName()); + + $engine->appendImportProperties( + $viewer, + $import, + $properties); + + return $properties; + } + + private function buildLogMessages(PhabricatorCalendarImport $import) { + $viewer = $this->getViewer(); + + $logs = id(new PhabricatorCalendarImportLogQuery()) + ->setViewer($viewer) + ->withImportPHIDs(array($import->getPHID())) + ->setLimit(25) + ->execute(); + + $logs_view = id(new PhabricatorCalendarImportLogView()) + ->setViewer($viewer) + ->setLogs($logs); + + $all_uri = $this->getApplicationURI('import/log/'); + $all_uri = (string)id(new PhutilURI($all_uri)) + ->setQueryParam('importSourcePHID', $import->getPHID()); + + $all_button = id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('View All')) + ->setIcon('fa-search') + ->setHref($all_uri); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Log Messages')) + ->addActionLink($all_button); + + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setTable($logs_view); + } + + private function buildImportedEvents(PhabricatorCalendarImport $import) { + $viewer = $this->getViewer(); + + $engine = id(new PhabricatorCalendarEventSearchEngine()) + ->setViewer($viewer); + + $saved = $engine->newSavedQuery() + ->setParameter('importSourcePHIDs', array($import->getPHID())); + + $pager = $engine->newPagerForSavedQuery($saved); + $pager->setPageSize(25); + + $query = $engine->buildQueryFromSavedQuery($saved); + + $results = $engine->executeQuery($query, $pager); + $view = $engine->renderResults($results, $saved); + $list = $view->getObjectList(); + $list->setNoDataString(pht('No imported events.')); + + $all_uri = $this->getApplicationURI(); + $all_uri = (string)id(new PhutilURI($all_uri)) + ->setQueryParam('importSourcePHID', $import->getPHID()) + ->setQueryParam('display', 'list'); + + $all_button = id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('View All')) + ->setIcon('fa-search') + ->setHref($all_uri); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Imported Events')) + ->addActionLink($all_button); + + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setObjectList($list); + } + +} diff --git a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php index 33442b6702..655037c140 100644 --- a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php +++ b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php @@ -1,325 +1,335 @@ requireActor(); if ($object->getIsStub()) { $this->materializeStub($object); } } private function materializeStub(PhabricatorCalendarEvent $event) { if (!$event->getIsStub()) { throw new Exception( pht('Can not materialize an event stub: this event is not a stub.')); } $actor = $this->getActor(); $event->copyFromParent($actor); $event->setIsStub(0); $invitees = $event->getParentEvent()->getInvitees(); $new_invitees = array(); foreach ($invitees as $invitee) { $invitee = id(new PhabricatorCalendarEventInvitee()) ->setEventPHID($event->getPHID()) ->setInviteePHID($invitee->getInviteePHID()) ->setInviterPHID($invitee->getInviterPHID()) ->setStatus($invitee->getStatus()) ->save(); $new_invitees[] = $invitee; } $event->save(); $event->attachInvitees($new_invitees); } public function getTransactionTypes() { $types = parent::getTransactionTypes(); $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; return $types; } protected function adjustObjectForPolicyChecks( PhabricatorLiskDAO $object, array $xactions) { $copy = parent::adjustObjectForPolicyChecks($object, $xactions); foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorCalendarEventHostTransaction::TRANSACTIONTYPE: $copy->setHostPHID($xaction->getNewValue()); break; case PhabricatorCalendarEventInviteTransaction::TRANSACTIONTYPE: PhabricatorPolicyRule::passTransactionHintToRule( $copy, new PhabricatorCalendarEventInviteesPolicyRule(), array_fuse($xaction->getNewValue())); break; } } return $copy; } protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { // Clear the availability caches for users whose availability is affected // by this edit. $invalidate_all = false; $invalidate_phids = array(); foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorCalendarEventUntilDateTransaction::TRANSACTIONTYPE: case PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE: case PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE: case PhabricatorCalendarEventCancelTransaction::TRANSACTIONTYPE: case PhabricatorCalendarEventAllDayTransaction::TRANSACTIONTYPE: // For these kinds of changes, we need to invalidate the availabilty // caches for all attendees. $invalidate_all = true; break; case PhabricatorCalendarEventAcceptTransaction::TRANSACTIONTYPE: case PhabricatorCalendarEventDeclineTransaction::TRANSACTIONTYPE: $acting_phid = $this->getActingAsPHID(); $invalidate_phids[$acting_phid] = $acting_phid; break; case PhabricatorCalendarEventInviteTransaction::TRANSACTIONTYPE: foreach ($xaction->getNewValue() as $phid => $ignored) { $invalidate_phids[$phid] = $phid; } break; } } $phids = mpull($object->getInvitees(), 'getInviteePHID'); $phids = array_fuse($phids); if (!$invalidate_all) { $phids = array_select_keys($phids, $invalidate_phids); } if ($phids) { $object->applyViewerTimezone($this->getActor()); $user = new PhabricatorUser(); $conn_w = $user->establishConnection('w'); queryfx( $conn_w, 'UPDATE %T SET availabilityCacheTTL = NULL WHERE phid IN (%Ls) AND availabilityCacheTTL >= %d', $user->getTableName(), $phids, $object->getStartDateTimeEpochForCache()); } return $xactions; } protected function validateAllTransactions( PhabricatorLiskDAO $object, array $xactions) { $start_date_xaction = PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE; $end_date_xaction = PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE; $is_recurrence_xaction = PhabricatorCalendarEventRecurringTransaction::TRANSACTIONTYPE; $recurrence_end_xaction = PhabricatorCalendarEventUntilDateTransaction::TRANSACTIONTYPE; $start_date = $object->getStartDateTimeEpoch(); $end_date = $object->getEndDateTimeEpoch(); $recurrence_end = $object->getUntilDateTimeEpoch(); $is_recurring = $object->getIsRecurring(); $errors = array(); foreach ($xactions as $xaction) { if ($xaction->getTransactionType() == $start_date_xaction) { $start_date = $xaction->getNewValue()->getEpoch(); } else if ($xaction->getTransactionType() == $end_date_xaction) { $end_date = $xaction->getNewValue()->getEpoch(); } else if ($xaction->getTransactionType() == $recurrence_end_xaction) { $recurrence_end = $xaction->getNewValue()->getEpoch(); } else if ($xaction->getTransactionType() == $is_recurrence_xaction) { $is_recurring = $xaction->getNewValue(); } } if ($start_date > $end_date) { $errors[] = new PhabricatorApplicationTransactionValidationError( $end_date_xaction, pht('Invalid'), pht('End date must be after start date.'), null); } if ($recurrence_end && !$is_recurring) { $errors[] = new PhabricatorApplicationTransactionValidationError( $recurrence_end_xaction, pht('Invalid'), pht('Event must be recurring to have a recurrence end date.'). null); } return $errors; } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { + + if ($object->isImportedEvent()) { + return false; + } + return true; } protected function supportsSearch() { return true; } protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { + + if ($object->isImportedEvent()) { + return false; + } + return true; } protected function getMailSubjectPrefix() { return pht('[Calendar]'); } protected function getMailTo(PhabricatorLiskDAO $object) { $phids = array(); if ($object->getHostPHID()) { $phids[] = $object->getHostPHID(); } $phids[] = $this->getActingAsPHID(); $invitees = $object->getInvitees(); foreach ($invitees as $invitee) { $status = $invitee->getStatus(); if ($status === PhabricatorCalendarEventInvitee::STATUS_ATTENDING || $status === PhabricatorCalendarEventInvitee::STATUS_INVITED) { $phids[] = $invitee->getInviteePHID(); } } $phids = array_unique($phids); return $phids; } public function getMailTagsMap() { return array( PhabricatorCalendarEventTransaction::MAILTAG_CONTENT => pht( "An event's name, status, invite list, ". "icon, and description changes."), PhabricatorCalendarEventTransaction::MAILTAG_RESCHEDULE => pht( "An event's start and end date ". "and cancellation status changes."), PhabricatorCalendarEventTransaction::MAILTAG_OTHER => pht('Other event activity not listed above occurs.'), ); } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new PhabricatorCalendarReplyHandler()) ->setMailReceiver($object); } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $id = $object->getID(); $name = $object->getName(); return id(new PhabricatorMetaMTAMail()) ->setSubject("E{$id}: {$name}") ->addHeader('Thread-Topic', "E{$id}: ".$object->getName()); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $description = $object->getDescription(); $body = parent::buildMailBody($object, $xactions); if (strlen($description)) { $body->addRemarkupSection( pht('EVENT DESCRIPTION'), $description); } $body->addLinkSection( pht('EVENT DETAIL'), PhabricatorEnv::getProductionURI('/E'.$object->getID())); $ics_attachment = $this->newICSAttachment($object); $body->addAttachment($ics_attachment); return $body; } protected function shouldApplyHeraldRules( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function buildHeraldAdapter( PhabricatorLiskDAO $object, array $xactions) { return id(new PhabricatorCalendarEventHeraldAdapter()) ->setObject($object); } private function newICSAttachment( PhabricatorCalendarEvent $event) { $actor = $this->getActor(); $ics_data = id(new PhabricatorCalendarICSWriter()) ->setViewer($actor) ->setEvents(array($event)) ->writeICSDocument(); $ics_attachment = new PhabricatorMetaMTAAttachment( $ics_data, $event->getICSFilename(), 'text/calendar'); return $ics_attachment; } } diff --git a/src/applications/calendar/editor/PhabricatorCalendarImportEditEngine.php b/src/applications/calendar/editor/PhabricatorCalendarImportEditEngine.php new file mode 100644 index 0000000000..031a890d59 --- /dev/null +++ b/src/applications/calendar/editor/PhabricatorCalendarImportEditEngine.php @@ -0,0 +1,115 @@ +importEngine = $engine; + return $this; + } + + public function getImportEngine() { + return $this->importEngine; + } + + public function getEngineName() { + return pht('Calendar Imports'); + } + + public function isEngineConfigurable() { + return false; + } + + public function getSummaryHeader() { + return pht('Configure Calendar Import Forms'); + } + + public function getSummaryText() { + return pht('Configure how users create and edit imports.'); + } + + public function getEngineApplicationClass() { + return 'PhabricatorCalendarApplication'; + } + + protected function newEditableObject() { + $viewer = $this->getViewer(); + $engine = $this->getImportEngine(); + + return PhabricatorCalendarImport::initializeNewCalendarImport( + $viewer, + $engine); + } + + protected function newObjectQuery() { + return new PhabricatorCalendarImportQuery(); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create New Import'); + } + + protected function getObjectEditTitleText($object) { + return pht('Edit Import: %s', $object->getDisplayName()); + } + + protected function getObjectEditShortText($object) { + return pht('Import %d', $object->getID()); + } + + protected function getObjectCreateShortText() { + return pht('Create Import'); + } + + protected function getObjectName() { + return pht('Import'); + } + + protected function getObjectViewURI($object) { + return $object->getURI(); + } + + protected function getEditorURI() { + return $this->getApplication()->getApplicationURI('import/edit/'); + } + + protected function buildCustomEditFields($object) { + $viewer = $this->getViewer(); + + $fields = array( + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setDescription(pht('Name of the import.')) + ->setTransactionType( + PhabricatorCalendarImportNameTransaction::TRANSACTIONTYPE) + ->setConduitDescription(pht('Rename the import.')) + ->setConduitTypeDescription(pht('New import name.')) + ->setValue($object->getName()), + id(new PhabricatorBoolEditField()) + ->setKey('disabled') + ->setOptions(pht('Active'), pht('Disabled')) + ->setLabel(pht('Disabled')) + ->setDescription(pht('Disable the import.')) + ->setTransactionType( + PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE) + ->setIsConduitOnly(true) + ->setConduitDescription(pht('Disable or restore the import.')) + ->setConduitTypeDescription(pht('True to cancel the import.')) + ->setValue($object->getIsDisabled()), + ); + + $import_engine = $object->getEngine(); + foreach ($import_engine->newEditEngineFields($this, $object) as $field) { + $fields[] = $field; + } + + return $fields; + } + + +} diff --git a/src/applications/calendar/editor/PhabricatorCalendarImportEditor.php b/src/applications/calendar/editor/PhabricatorCalendarImportEditor.php new file mode 100644 index 0000000000..fe22a9f8c9 --- /dev/null +++ b/src/applications/calendar/editor/PhabricatorCalendarImportEditor.php @@ -0,0 +1,42 @@ +getIsNewObject()) { + $actor = $this->getActor(); + + $import_engine = $object->getEngine(); + $import_engine->didCreateImport($actor, $object); + } + + return $xactions; + } + + +} diff --git a/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php new file mode 100644 index 0000000000..7284776da6 --- /dev/null +++ b/src/applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php @@ -0,0 +1,102 @@ +getParameter($phid_key); + + $properties->addProperty( + pht('Source File'), + $viewer->renderHandle($file_phid)); + } + + public function newEditEngineFields( + PhabricatorEditEngine $engine, + PhabricatorCalendarImport $import) { + $fields = array(); + + if ($engine->getIsCreate()) { + $fields[] = id(new PhabricatorFileEditField()) + ->setKey('icsFilePHID') + ->setLabel(pht('ICS File')) + ->setDescription(pht('ICS file to import.')) + ->setTransactionType( + PhabricatorCalendarImportICSFileTransaction::TRANSACTIONTYPE) + ->setConduitDescription(pht('File PHID to import.')) + ->setConduitTypeDescription(pht('File PHID.')); + } + + return $fields; + } + + public function getDisplayName(PhabricatorCalendarImport $import) { + $filename_key = PhabricatorCalendarImportICSFileTransaction::PARAMKEY_NAME; + $filename = $import->getParameter($filename_key); + if (strlen($filename)) { + return pht('ICS File "%s"', $filename); + } else { + return pht('ICS File'); + } + } + + public function didCreateImport( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import) { + + $phid_key = PhabricatorCalendarImportICSFileTransaction::PARAMKEY_FILE; + $file_phid = $import->getParameter($phid_key); + + $file = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs(array($file_phid)) + ->executeOne(); + if (!$file) { + throw new Exception( + pht( + 'Unable to load file ("%s") for import.', + $file_phid)); + } + + $data = $file->loadFileData(); + + return $this->importICSData($viewer, $import, $data); + } + + + public function canDisable( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import) { + return false; + } + + public function explainCanDisable( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import) { + return pht( + 'You can not disable import of an ICS file because the entire import '. + 'occurs immediately when you upload the file. There is no further '. + 'activity to disable.'); + } + + +} diff --git a/src/applications/calendar/import/PhabricatorCalendarICSImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarICSImportEngine.php new file mode 100644 index 0000000000..3d94085469 --- /dev/null +++ b/src/applications/calendar/import/PhabricatorCalendarICSImportEngine.php @@ -0,0 +1,34 @@ +parseICSData($data); + } catch (PhutilICSParserException $ex) { + // TODO: In theory, it would be nice to store these in a fully abstract + // form so they can be translated at display time. As-is, we'll store the + // error messages in whatever language we were using when the parser + // failure occurred. + + $import->newLogMessage( + PhabricatorCalendarImportICSLogType::LOGTYPE, + array( + 'ics.code' => $ex->getParserFailureCode(), + 'ics.message' => $ex->getMessage(), + )); + + $document = null; + } + + return $this->importEventDocument($viewer, $import, $document); + } + +} diff --git a/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php new file mode 100644 index 0000000000..7b1754a911 --- /dev/null +++ b/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php @@ -0,0 +1,111 @@ +getParameter($uri_key); + + // Since the URI may contain a secret hash, don't show it to users who + // can not edit the import. + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $import, + PhabricatorPolicyCapability::CAN_EDIT); + if (!$can_edit) { + $uri_display = phutil_tag('em', array(), pht('Restricted')); + } else if (!PhabricatorEnv::isValidRemoteURIForLink($uri)) { + $uri_display = $uri; + } else { + $uri_display = phutil_tag( + 'a', + array( + 'href' => $uri, + 'target' => '_blank', + ), + $uri); + } + + $properties->addProperty(pht('Source URI'), $uri_display); + } + + public function newEditEngineFields( + PhabricatorEditEngine $engine, + PhabricatorCalendarImport $import) { + $fields = array(); + + if ($engine->getIsCreate()) { + $fields[] = id(new PhabricatorTextEditField()) + ->setKey('uri') + ->setLabel(pht('URI')) + ->setDescription(pht('URI to import.')) + ->setTransactionType( + PhabricatorCalendarImportICSURITransaction::TRANSACTIONTYPE) + ->setConduitDescription(pht('URI to import.')) + ->setConduitTypeDescription(pht('New URI.')); + } + + return $fields; + } + + public function getDisplayName(PhabricatorCalendarImport $import) { + return pht('ICS URI'); + } + + public function didCreateImport( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import) { + + $uri_key = PhabricatorCalendarImportICSURITransaction::PARAMKEY_URI; + $uri = $import->getParameter($uri_key); + + PhabricatorSystemActionEngine::willTakeAction( + array($viewer->getPHID()), + new PhabricatorFilesOutboundRequestAction(), + 1); + + $file = PhabricatorFile::newFromFileDownload( + $uri, + array( + 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, + 'authorPHID' => $import->getAuthorPHID(), + 'canCDN' => true, + )); + + $import->newLogMessage( + PhabricatorCalendarImportFetchLogType::LOGTYPE, + array( + 'file.phid' => $file->getPHID(), + )); + + $data = $file->loadFileData(); + + return $this->importICSData($viewer, $import, $data); + } + + public function canDisable( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import) { + return true; + } + +} diff --git a/src/applications/calendar/import/PhabricatorCalendarImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarImportEngine.php new file mode 100644 index 0000000000..2fc9399fe3 --- /dev/null +++ b/src/applications/calendar/import/PhabricatorCalendarImportEngine.php @@ -0,0 +1,424 @@ +getPhobjectClassConstant('ENGINETYPE', 64); + } + + + abstract public function getImportEngineName(); + abstract public function getImportEngineTypeName(); + abstract public function getImportEngineHint(); + + public function appendImportProperties( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import, + PHUIPropertyListView $properties) { + return; + } + + abstract public function newEditEngineFields( + PhabricatorEditEngine $engine, + PhabricatorCalendarImport $import); + + abstract public function getDisplayName(PhabricatorCalendarImport $import); + + abstract public function didCreateImport( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import); + + abstract public function canDisable( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import); + + public function explainCanDisable( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import) { + throw new PhutilMethodNotImplementedException(); + } + + final public static function getAllImportEngines() { + return id(new PhutilClassMapQuery()) + ->setAncestorClass(__CLASS__) + ->setUniqueMethod('getImportEngineType') + ->setSortMethod('getImportEngineName') + ->execute(); + } + + final protected function importEventDocument( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import, + PhutilCalendarRootNode $root = null) { + + $event_type = PhutilCalendarEventNode::NODETYPE; + + $nodes = array(); + if ($root) { + foreach ($root->getChildren() as $document) { + foreach ($document->getChildren() as $node) { + $node_type = $node->getNodeType(); + if ($node_type != $event_type) { + $import->newLogMessage( + PhabricatorCalendarImportIgnoredNodeLogType::LOGTYPE, + array( + 'node.type' => $node_type, + )); + continue; + } + + $nodes[] = $node; + } + } + } + + // Reject events which have dates outside of the range of a signed + // 32-bit integer. We'll need to accommodate a wider range of events + // eventually, but have about 20 years until it's an issue and we'll + // all be dead by then. + foreach ($nodes as $key => $node) { + $dates = array(); + $dates[] = $node->getStartDateTime(); + $dates[] = $node->getEndDateTime(); + $dates[] = $node->getCreatedDateTime(); + $dates[] = $node->getModifiedDateTime(); + $rrule = $node->getRecurrenceRule(); + if ($rrule) { + $dates[] = $rrule->getUntil(); + } + + $bad_date = false; + foreach ($dates as $date) { + if ($date === null) { + continue; + } + + $year = $date->getYear(); + if ($year < 1970 || $year > 2037) { + $bad_date = true; + break; + } + } + + if ($bad_date) { + $import->newLogMessage( + PhabricatorCalendarImportEpochLogType::LOGTYPE, + array()); + unset($nodes[$key]); + } + } + + // Reject events which occur too frequently. Users do not normally define + // these events and the UI and application make many assumptions which are + // incompatible with events recurring once per second. + foreach ($nodes as $key => $node) { + $rrule = $node->getRecurrenceRule(); + if (!$rrule) { + // This is not a recurring event, so we don't need to check the + // frequency. + continue; + } + $scale = $rrule->getFrequencyScale(); + if ($scale >= PhutilCalendarRecurrenceRule::SCALE_DAILY) { + // This is a daily, weekly, monthly, or yearly event. These are + // supported. + } else { + // This is an hourly, minutely, or secondly event. + $import->newLogMessage( + PhabricatorCalendarImportFrequencyLogType::LOGTYPE, + array( + 'frequency' => $rrule->getFrequency(), + )); + unset($nodes[$key]); + } + } + + $node_map = array(); + foreach ($nodes as $node) { + $full_uid = $this->getFullNodeUID($node); + if (isset($node_map[$full_uid])) { + $import->newLogMessage( + PhabricatorCalendarImportDuplicateLogType::LOGTYPE, + array( + 'uid.full' => $full_uid, + )); + continue; + } + $node_map[$full_uid] = $node; + } + + // If we already know about some of these events and they were created + // here, we're not going to import it again. This can happen if a user + // exports an event and then tries to import it again. This is probably + // not what they meant to do and this pathway generally leads to madness. + $likely_phids = array(); + foreach ($node_map as $full_uid => $node) { + $uid = $node->getUID(); + $matches = null; + if (preg_match('/^(PHID-.*)@(.*)\z/', $uid, $matches)) { + $likely_phids[$full_uid] = $matches[1]; + } + } + + if ($likely_phids) { + // NOTE: We're using the omnipotent viewer here because we don't want + // to collide with events that already exist, even if you can't see + // them. + $events = id(new PhabricatorCalendarEventQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPHIDs($likely_phids) + ->execute(); + $events = mpull($events, null, 'getPHID'); + foreach ($node_map as $full_uid => $node) { + $phid = idx($likely_phids, $full_uid); + if (!$phid) { + continue; + } + + $event = idx($events, $phid); + if (!$event) { + continue; + } + + $import->newLogMessage( + PhabricatorCalendarImportOriginalLogType::LOGTYPE, + array( + 'phid' => $event->getPHID(), + )); + + unset($node_map[$full_uid]); + } + } + + if ($node_map) { + $events = id(new PhabricatorCalendarEventQuery()) + ->setViewer($viewer) + ->withImportAuthorPHIDs(array($viewer->getPHID())) + ->withImportUIDs(array_keys($node_map)) + ->execute(); + $events = mpull($events, null, 'getImportUID'); + } else { + $events = null; + } + + $xactions = array(); + $update_map = array(); + foreach ($node_map as $full_uid => $node) { + $event = idx($events, $full_uid); + if (!$event) { + $event = PhabricatorCalendarEvent::initializeNewCalendarEvent($viewer); + } + + $event + ->setImportAuthorPHID($viewer->getPHID()) + ->setImportSourcePHID($import->getPHID()) + ->setImportUID($full_uid) + ->attachImportSource($import); + + $this->updateEventFromNode($viewer, $event, $node); + $xactions[$full_uid] = $this->newUpdateTransactions($event, $node); + $update_map[$full_uid] = $event; + } + + // Reorder events so we create parents first. This allows us to populate + // "instanceOfEventPHID" correctly. + $insert_order = array(); + foreach ($update_map as $full_uid => $event) { + $parent_uid = $this->getParentNodeUID($node_map[$full_uid]); + if ($parent_uid === null) { + $insert_order[$full_uid] = $full_uid; + continue; + } + + if (empty($update_map[$parent_uid])) { + // The parent was not present in this import, which means it either + // does not exist or we're going to delete it anyway. We just drop + // this node. + + $import->newLogMessage( + PhabricatorCalendarImportOrphanLogType::LOGTYPE, + array( + 'uid.full' => $full_uid, + 'uid.parent' => $parent_uid, + )); + + continue; + } + + // Otherwise, we're going to insert the parent first, then insert + // the child. + $insert_order[$parent_uid] = $parent_uid; + $insert_order[$full_uid] = $full_uid; + } + + // TODO: Define per-engine content sources so this can say "via Upload" or + // whatever. + $content_source = PhabricatorContentSource::newForSource( + PhabricatorWebContentSource::SOURCECONST); + + // NOTE: We're using the omnipotent user here because imported events are + // otherwise immutable. + $edit_actor = PhabricatorUser::getOmnipotentUser(); + + $update_map = array_select_keys($update_map, $insert_order); + foreach ($update_map as $full_uid => $event) { + $parent_uid = $this->getParentNodeUID($node_map[$full_uid]); + if ($parent_uid) { + $parent_phid = $update_map[$full_uid]->getPHID(); + } else { + $parent_phid = null; + } + + $event->setInstanceOfEventPHID($parent_phid); + + $event_xactions = $xactions[$full_uid]; + + $editor = id(new PhabricatorCalendarEventEditor()) + ->setActor($edit_actor) + ->setActingAsPHID($import->getPHID()) + ->setContentSource($content_source) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true); + + $is_new = !$event->getID(); + + $editor->applyTransactions($event, $event_xactions); + + $import->newLogMessage( + PhabricatorCalendarImportUpdateLogType::LOGTYPE, + array( + 'new' => $is_new, + 'phid' => $event->getPHID(), + )); + } + + if (!$update_map) { + $import->newLogMessage( + PhabricatorCalendarImportEmptyLogType::LOGTYPE, + array()); + } + + // TODO: When the source is a subscription-based ICS file or some other + // similar source, we should load all events from the source here and + // destroy the ones we didn't update. These are events that have been + // deleted. + } + + private function getFullNodeUID(PhutilCalendarEventNode $node) { + $uid = $node->getUID(); + $instance_epoch = $this->getNodeInstanceEpoch($node); + $full_uid = $uid.'/'.$instance_epoch; + + return $full_uid; + } + + private function getParentNodeUID(PhutilCalendarEventNode $node) { + $recurrence_id = $node->getRecurrenceID(); + + if (!strlen($recurrence_id)) { + return null; + } + + return $node->getUID().'/'; + } + + private function getNodeInstanceEpoch(PhutilCalendarEventNode $node) { + $instance_iso = $node->getRecurrenceID(); + if (strlen($instance_iso)) { + $instance_datetime = PhutilCalendarAbsoluteDateTime::newFromISO8601( + $instance_iso); + $instance_epoch = $instance_datetime->getEpoch(); + } else { + $instance_epoch = null; + } + + return $instance_epoch; + } + + private function newUpdateTransactions( + PhabricatorCalendarEvent $event, + PhutilCalendarEventNode $node) { + + $xactions = array(); + $uid = $node->getUID(); + + $name = $node->getName(); + if (!strlen($name)) { + if (strlen($uid)) { + $name = pht('Unnamed Event "%s"', $uid); + } else { + $name = pht('Unnamed Imported Event'); + } + } + $xactions[] = id(new PhabricatorCalendarEventTransaction()) + ->setTransactionType( + PhabricatorCalendarEventNameTransaction::TRANSACTIONTYPE) + ->setNewValue($name); + + $description = $node->getDescription(); + $xactions[] = id(new PhabricatorCalendarEventTransaction()) + ->setTransactionType( + PhabricatorCalendarEventDescriptionTransaction::TRANSACTIONTYPE) + ->setNewValue((string)$description); + + $is_recurring = (bool)$node->getRecurrenceRule(); + $xactions[] = id(new PhabricatorCalendarEventTransaction()) + ->setTransactionType( + PhabricatorCalendarEventRecurringTransaction::TRANSACTIONTYPE) + ->setNewValue($is_recurring); + + return $xactions; + } + + private function updateEventFromNode( + PhabricatorUser $actor, + PhabricatorCalendarEvent $event, + PhutilCalendarEventNode $node) { + + $instance_epoch = $this->getNodeInstanceEpoch($node); + $event->setUTCInstanceEpoch($instance_epoch); + + $timezone = $actor->getTimezoneIdentifier(); + + // TODO: These should be transactional, but the transaction only accepts + // epoch timestamps right now. + $start_datetime = $node->getStartDateTime() + ->setViewerTimezone($timezone); + $end_datetime = $node->getEndDateTime() + ->setViewerTimezone($timezone); + + $event + ->setStartDateTime($start_datetime) + ->setEndDateTime($end_datetime); + + // TODO: This should be transactional, but the transaction only accepts + // simple frequency rules right now. + $rrule = $node->getRecurrenceRule(); + if ($rrule) { + $event->setRecurrenceRule($rrule); + + $until_datetime = $rrule->getUntil(); + if ($until_datetime) { + $until_datetime->setViewerTimezone($timezone); + $event->setUntilDateTime($until_datetime); + } + } + + return $event; + } + + public function canDeleteAnyEvents( + PhabricatorUser $viewer, + PhabricatorCalendarImport $import) { + + $any_event = id(new PhabricatorCalendarEventQuery()) + ->setViewer($viewer) + ->withImportSourcePHIDs(array($import->getPHID())) + ->setLimit(1) + ->execute(); + + return (bool)$any_event; + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportDefaultLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportDefaultLogType.php new file mode 100644 index 0000000000..4e61e3f94f --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportDefaultLogType.php @@ -0,0 +1,20 @@ +getParameter('type'); + if (strlen($type)) { + return pht('Unknown Message "%s"', $type); + } else { + return pht('Unknown Message'); + } + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportDuplicateLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportDuplicateLogType.php new file mode 100644 index 0000000000..0f72932404 --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportDuplicateLogType.php @@ -0,0 +1,23 @@ +getParameter('uid.full'); + return pht( + 'Ignored duplicate event "%s" present in source.', + $duplicate_uid); + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportEmptyLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportEmptyLogType.php new file mode 100644 index 0000000000..5a540645ba --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportEmptyLogType.php @@ -0,0 +1,32 @@ +renderHandle($log->getParameter('file.phid')); + } + + public function getDisplayIcon( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'fa-download'; + } + + public function getDisplayColor( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'green'; + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportFrequencyLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportFrequencyLogType.php new file mode 100644 index 0000000000..b7d6177939 --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportFrequencyLogType.php @@ -0,0 +1,38 @@ +getParameter('frequency'); + + return pht( + 'Ignored an event with an unsupported frequency rule ("%s"). Events '. + 'which repeat more frequently than daily are not supported.', + $frequency); + } + + public function getDisplayIcon( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'fa-clock-o'; + } + + public function getDisplayColor( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'red'; + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportICSLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportICSLogType.php new file mode 100644 index 0000000000..b3032f073e --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportICSLogType.php @@ -0,0 +1,36 @@ +getParameter('ics.code'), + $log->getParameter('ics.message')); + } + + + public function getDisplayIcon( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'fa-file'; + } + + public function getDisplayColor( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'red'; + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportIgnoredNodeLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportIgnoredNodeLogType.php new file mode 100644 index 0000000000..5f7d45db78 --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportIgnoredNodeLogType.php @@ -0,0 +1,23 @@ +getParameter('node.type'); + return pht( + 'Ignored unsupported "%s" node present in source.', + $node_type); + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportLogType.php new file mode 100644 index 0000000000..a6c4ca4ec3 --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportLogType.php @@ -0,0 +1,39 @@ +getPhobjectClassConstant('LOGTYPE', 64); + } + + final public static function getAllLogTypes() { + return id(new PhutilClassMapQuery()) + ->setAncestorClass(__CLASS__) + ->setUniqueMethod('getLogTypeConstant') + ->execute(); + } + + abstract public function getDisplayType( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log); + + public function getDisplayIcon( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'fa-warning'; + } + + public function getDisplayColor( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'yellow'; + } + + public function getDisplayDescription( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return null; + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportOriginalLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportOriginalLogType.php new file mode 100644 index 0000000000..567cc5f68e --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportOriginalLogType.php @@ -0,0 +1,26 @@ +getParameter('phid'); + + return pht( + 'Ignored an event (%s) because the original version of this event '. + 'was created here.', + $viewer->renderHandle($phid)); + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportOrphanLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportOrphanLogType.php new file mode 100644 index 0000000000..236b0e7f65 --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportOrphanLogType.php @@ -0,0 +1,25 @@ +getParameter('uid.full'); + $parent_uid = $log->getParameter('uid.parent'); + return pht( + 'Found orphaned child event ("%s") without a parent event ("%s").', + $child_uid, + $parent_uid); + } + +} diff --git a/src/applications/calendar/importlog/PhabricatorCalendarImportUpdateLogType.php b/src/applications/calendar/importlog/PhabricatorCalendarImportUpdateLogType.php new file mode 100644 index 0000000000..9b20c54615 --- /dev/null +++ b/src/applications/calendar/importlog/PhabricatorCalendarImportUpdateLogType.php @@ -0,0 +1,38 @@ +getParameter('new'); + if ($is_new) { + return pht('Imported Event'); + } else { + return pht('Updated Event'); + } + } + + public function getDisplayDescription( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + $event_phid = $log->getParameter('phid'); + return $viewer->renderHandle($event_phid); + } + + public function getDisplayIcon( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'fa-upload'; + } + + public function getDisplayColor( + PhabricatorUser $viewer, + PhabricatorCalendarImportLog $log) { + return 'green'; + } + +} diff --git a/src/applications/calendar/phid/PhabricatorCalendarImportPHIDType.php b/src/applications/calendar/phid/PhabricatorCalendarImportPHIDType.php new file mode 100644 index 0000000000..876ec7acf7 --- /dev/null +++ b/src/applications/calendar/phid/PhabricatorCalendarImportPHIDType.php @@ -0,0 +1,50 @@ +withPHIDs($phids); + } + + public function loadHandles( + PhabricatorHandleQuery $query, + array $handles, + array $objects) { + + foreach ($handles as $phid => $handle) { + $import = $objects[$phid]; + + $id = $import->getID(); + $name = $import->getDisplayName(); + $uri = $import->getURI(); + + $handle + ->setName($name) + ->setFullName(pht('Calendar Import %s: %s', $id, $name)) + ->setURI($uri); + + if ($import->getIsDisabled()) { + $handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED); + } + } + } + +} diff --git a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php index 9b928c9d1a..9949ee2f5a 100644 --- a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php +++ b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php @@ -1,565 +1,639 @@ generateGhosts = $generate_ghosts; return $this; } public function withIDs(array $ids) { $this->ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withDateRange($begin, $end) { $this->rangeBegin = $begin; $this->rangeEnd = $end; return $this; } public function withInvitedPHIDs(array $phids) { $this->inviteePHIDs = $phids; return $this; } public function withHostPHIDs(array $phids) { $this->hostPHIDs = $phids; return $this; } public function withIsCancelled($is_cancelled) { $this->isCancelled = $is_cancelled; return $this; } public function withIsStub($is_stub) { $this->isStub = $is_stub; return $this; } public function withEventsWithNoParent($events_with_no_parent) { $this->eventsWithNoParent = $events_with_no_parent; return $this; } public function withInstanceSequencePairs(array $pairs) { $this->instanceSequencePairs = $pairs; return $this; } public function withParentEventPHIDs(array $parent_phids) { $this->parentEventPHIDs = $parent_phids; return $this; } + public function withImportSourcePHIDs(array $import_phids) { + $this->importSourcePHIDs = $import_phids; + return $this; + } + + public function withImportAuthorPHIDs(array $author_phids) { + $this->importAuthorPHIDs = $author_phids; + return $this; + } + + public function withImportUIDs(array $uids) { + $this->importUIDs = $uids; + return $this; + } + protected function getDefaultOrderVector() { return array('start', 'id'); } public function getBuiltinOrders() { return array( 'start' => array( 'vector' => array('start', 'id'), 'name' => pht('Event Start'), ), ) + parent::getBuiltinOrders(); } public function getOrderableColumns() { return array( 'start' => array( 'table' => $this->getPrimaryTableAlias(), 'column' => 'dateFrom', 'reverse' => true, 'type' => 'int', 'unique' => false, ), ) + parent::getOrderableColumns(); } protected function getPagingValueMap($cursor, array $keys) { $event = $this->loadCursorObject($cursor); return array( 'start' => $event->getStartDateTimeEpoch(), 'id' => $event->getID(), ); } protected function shouldLimitResults() { // When generating ghosts, we can't rely on database ordering because // MySQL can't predict the ghost start times. We'll just load all matching // events, then generate results from there. if ($this->generateGhosts) { return false; } return true; } protected function loadPage() { $events = $this->loadStandardPage($this->newResultObject()); $viewer = $this->getViewer(); foreach ($events as $event) { $event->applyViewerTimezone($viewer); } if (!$this->generateGhosts) { return $events; } $raw_limit = $this->getRawResultLimit(); if (!$raw_limit && !$this->rangeEnd) { throw new Exception( pht( 'Event queries which generate ghost events must include either a '. 'result limit or an end date, because they may otherwise generate '. 'an infinite number of results. This query has neither.')); } foreach ($events as $key => $event) { $sequence_start = 0; $sequence_end = null; $end = null; $instance_of = $event->getInstanceOfEventPHID(); if ($instance_of == null && $this->isCancelled !== null) { if ($event->getIsCancelled() != $this->isCancelled) { unset($events[$key]); continue; } } } // Pull out all of the parents first. We may discard them as we begin // generating ghost events, but we still want to process all of them. $parents = array(); foreach ($events as $key => $event) { if ($event->isParentEvent()) { $parents[$key] = $event; } } // Now that we've picked out all the parent events, we can immediately // discard anything outside of the time window. $events = $this->getEventsInRange($events); $generate_from = $this->rangeBegin; $generate_until = $this->rangeEnd; foreach ($parents as $key => $event) { $duration = $event->getDuration(); $start_date = $this->getRecurrenceWindowStart( $event, $generate_from - $duration); $end_date = $this->getRecurrenceWindowEnd( $event, $generate_until); $limit = $this->getRecurrenceLimit($event, $raw_limit); $set = $event->newRecurrenceSet(); $recurrences = $set->getEventsBetween( null, $end_date, $limit + 1); // We're generating events from the beginning and then filtering them // here (instead of only generating events starting at the start date) // because we need to know the proper sequence indexes to generate ghost // events. This may change after RDATE support. if ($start_date) { $start_epoch = $start_date->getEpoch(); } else { $start_epoch = null; } foreach ($recurrences as $sequence_index => $sequence_datetime) { if (!$sequence_index) { // This is the parent event, which we already have. continue; } if ($start_epoch) { if ($sequence_datetime->getEpoch() < $start_epoch) { continue; } } $events[] = $event->newGhost( $viewer, $sequence_index, $sequence_datetime); } // NOTE: We're slicing results every time because this makes it cheaper // to generate future ghosts. If we already have 100 events that occur // before July 1, we know we never need to generate ghosts after that // because they couldn't possibly ever appear in the result set. if ($raw_limit) { if (count($events) > $raw_limit) { $events = msort($events, 'getStartDateTimeEpoch'); $events = array_slice($events, 0, $raw_limit, true); $generate_until = last($events)->getEndDateTimeEpoch(); } } } // Now that we're done generating ghost events, we're going to remove any // ghosts that we have concrete events for (or which we can load the // concrete events for). These concrete events are generated when users // edit a ghost, and replace the ghost events. // First, generate a map of all concrete events we // already loaded. We don't need to load these again. $have_pairs = array(); foreach ($events as $event) { if ($event->getIsGhostEvent()) { continue; } $parent_phid = $event->getInstanceOfEventPHID(); $sequence = $event->getSequenceIndex(); $have_pairs[$parent_phid][$sequence] = true; } // Now, generate a map of all events we generated // ghosts for. We need to try to load these if we don't already have them. $map = array(); $parent_pairs = array(); foreach ($events as $key => $event) { if (!$event->getIsGhostEvent()) { continue; } $parent_phid = $event->getInstanceOfEventPHID(); $sequence = $event->getSequenceIndex(); // We already loaded the concrete version of this event, so we can just // throw out the ghost and move on. if (isset($have_pairs[$parent_phid][$sequence])) { unset($events[$key]); continue; } // We didn't load the concrete version of this event, so we need to // try to load it if it exists. $parent_pairs[] = array($parent_phid, $sequence); $map[$parent_phid][$sequence] = $key; } if ($parent_pairs) { $instances = id(new self()) ->setViewer($viewer) ->setParentQuery($this) ->withInstanceSequencePairs($parent_pairs) ->execute(); foreach ($instances as $instance) { $parent_phid = $instance->getInstanceOfEventPHID(); $sequence = $instance->getSequenceIndex(); $indexes = idx($map, $parent_phid); $key = idx($indexes, $sequence); // Replace the ghost with the corresponding concrete event. $events[$key] = $instance; } } $events = msort($events, 'getStartDateTimeEpoch'); return $events; } protected function buildJoinClauseParts(AphrontDatabaseConnection $conn_r) { $parts = parent::buildJoinClauseParts($conn_r); if ($this->inviteePHIDs !== null) { $parts[] = qsprintf( $conn_r, 'JOIN %T invitee ON invitee.eventPHID = event.phid AND invitee.status != %s', id(new PhabricatorCalendarEventInvitee())->getTableName(), PhabricatorCalendarEventInvitee::STATUS_UNINVITED); } return $parts; } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( $conn, 'event.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, 'event.phid IN (%Ls)', $this->phids); } // NOTE: The date ranges we query for are larger than the requested ranges // because we need to catch all-day events. We'll refine this range later // after adjusting the visible range of events we load. if ($this->rangeBegin) { $where[] = qsprintf( $conn, '(event.utcUntilEpoch >= %d) OR (event.utcUntilEpoch IS NULL)', $this->rangeBegin - phutil_units('16 hours in seconds')); } if ($this->rangeEnd) { $where[] = qsprintf( $conn, 'event.utcInitialEpoch <= %d', $this->rangeEnd + phutil_units('16 hours in seconds')); } if ($this->inviteePHIDs !== null) { $where[] = qsprintf( $conn, 'invitee.inviteePHID IN (%Ls)', $this->inviteePHIDs); } if ($this->hostPHIDs !== null) { $where[] = qsprintf( $conn, 'event.hostPHID IN (%Ls)', $this->hostPHIDs); } if ($this->isCancelled !== null) { $where[] = qsprintf( $conn, 'event.isCancelled = %d', (int)$this->isCancelled); } if ($this->eventsWithNoParent == true) { $where[] = qsprintf( $conn, 'event.instanceOfEventPHID IS NULL'); } if ($this->instanceSequencePairs !== null) { $sql = array(); foreach ($this->instanceSequencePairs as $pair) { $sql[] = qsprintf( $conn, '(event.instanceOfEventPHID = %s AND event.sequenceIndex = %d)', $pair[0], $pair[1]); } $where[] = qsprintf( $conn, '%Q', implode(' OR ', $sql)); } if ($this->isStub !== null) { $where[] = qsprintf( $conn, 'event.isStub = %d', (int)$this->isStub); } if ($this->parentEventPHIDs !== null) { $where[] = qsprintf( $conn, 'event.instanceOfEventPHID IN (%Ls)', $this->parentEventPHIDs); } + if ($this->importSourcePHIDs !== null) { + $where[] = qsprintf( + $conn, + 'event.importSourcePHID IN (%Ls)', + $this->importSourcePHIDs); + } + + if ($this->importAuthorPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'event.importAuthorPHID IN (%Ls)', + $this->importAuthorPHIDs); + } + + if ($this->importUIDs !== null) { + $where[] = qsprintf( + $conn, + 'event.importUID IN (%Ls)', + $this->importUIDs); + } + return $where; } protected function getPrimaryTableAlias() { return 'event'; } protected function shouldGroupQueryResultRows() { if ($this->inviteePHIDs !== null) { return true; } return parent::shouldGroupQueryResultRows(); } protected function getApplicationSearchObjectPHIDColumn() { return 'event.phid'; } public function getQueryApplicationClass() { return 'PhabricatorCalendarApplication'; } protected function willFilterPage(array $events) { $instance_of_event_phids = array(); $recurring_events = array(); $viewer = $this->getViewer(); $events = $this->getEventsInRange($events); + $import_phids = array(); + foreach ($events as $event) { + $import_phid = $event->getImportSourcePHID(); + if ($import_phid !== null) { + $import_phids[$import_phid] = $import_phid; + } + } + + if ($import_phids) { + $imports = id(new PhabricatorCalendarImportQuery()) + ->setParentQuery($this) + ->setViewer($viewer) + ->withPHIDs($import_phids) + ->execute(); + $imports = mpull($imports, null, 'getPHID'); + } else { + $imports = array(); + } + + foreach ($events as $key => $event) { + $import_phid = $event->getImportSourcePHID(); + if ($import_phid === null) { + $event->attachImportSource(null); + continue; + } + + $import = idx($imports, $import_phid); + if (!$import) { + unset($events[$key]); + $this->didRejectResult($event); + continue; + } + + $event->attachImportSource($import); + } + $phids = array(); foreach ($events as $event) { $phids[] = $event->getPHID(); $instance_of = $event->getInstanceOfEventPHID(); if ($instance_of) { $instance_of_event_phids[] = $instance_of; } } if (count($instance_of_event_phids) > 0) { $recurring_events = id(new PhabricatorCalendarEventQuery()) ->setViewer($viewer) ->withPHIDs($instance_of_event_phids) ->withEventsWithNoParent(true) ->execute(); $recurring_events = mpull($recurring_events, null, 'getPHID'); } if ($events) { $invitees = id(new PhabricatorCalendarEventInviteeQuery()) ->setViewer($viewer) ->withEventPHIDs($phids) ->execute(); $invitees = mgroup($invitees, 'getEventPHID'); } else { $invitees = array(); } foreach ($events as $key => $event) { $event_invitees = idx($invitees, $event->getPHID(), array()); $event->attachInvitees($event_invitees); $instance_of = $event->getInstanceOfEventPHID(); if (!$instance_of) { continue; } $parent = idx($recurring_events, $instance_of); // should never get here if (!$parent) { unset($events[$key]); continue; } $event->attachParentEvent($parent); if ($this->isCancelled !== null) { if ($event->getIsCancelled() != $this->isCancelled) { unset($events[$key]); continue; } } } $events = msort($events, 'getStartDateTimeEpoch'); return $events; } private function getEventsInRange(array $events) { $range_start = $this->rangeBegin; $range_end = $this->rangeEnd; foreach ($events as $key => $event) { $event_start = $event->getStartDateTimeEpoch(); $event_end = $event->getEndDateTimeEpoch(); if ($range_start && $event_end < $range_start) { unset($events[$key]); } if ($range_end && $event_start > $range_end) { unset($events[$key]); } } return $events; } private function getRecurrenceWindowStart( PhabricatorCalendarEvent $event, $generate_from) { if (!$generate_from) { return null; } return PhutilCalendarAbsoluteDateTime::newFromEpoch($generate_from); } private function getRecurrenceWindowEnd( PhabricatorCalendarEvent $event, $generate_until) { $end_epochs = array(); if ($generate_until) { $end_epochs[] = $generate_until; } $until_epoch = $event->getUntilDateTimeEpoch(); if ($until_epoch) { $end_epochs[] = $until_epoch; } if (!$end_epochs) { return null; } return PhutilCalendarAbsoluteDateTime::newFromEpoch(min($end_epochs)); } private function getRecurrenceLimit( PhabricatorCalendarEvent $event, $raw_limit) { return $raw_limit; } - } diff --git a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php index a29b7ea37a..26c3dc938b 100644 --- a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php +++ b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php @@ -1,591 +1,617 @@ setLabel(pht('Hosts')) ->setKey('hostPHIDs') ->setAliases(array('host', 'hostPHID', 'hosts')) ->setDatasource(new PhabricatorPeopleUserFunctionDatasource()), id(new PhabricatorSearchDatasourceField()) ->setLabel(pht('Invited')) ->setKey('invitedPHIDs') ->setDatasource(new PhabricatorPeopleUserFunctionDatasource()), id(new PhabricatorSearchDateControlField()) ->setLabel(pht('Occurs After')) ->setKey('rangeStart'), id(new PhabricatorSearchDateControlField()) ->setLabel(pht('Occurs Before')) ->setKey('rangeEnd') ->setAliases(array('rangeEnd')), id(new PhabricatorSearchCheckboxesField()) ->setKey('upcoming') ->setOptions(array( 'upcoming' => pht('Show only upcoming events.'), )), id(new PhabricatorSearchSelectField()) ->setLabel(pht('Cancelled Events')) ->setKey('isCancelled') ->setOptions($this->getCancelledOptions()) ->setDefault('active'), + id(new PhabricatorPHIDsSearchField()) + ->setLabel(pht('Import Sources')) + ->setKey('importSourcePHIDs') + ->setAliases(array('importSourcePHID')), id(new PhabricatorSearchSelectField()) ->setLabel(pht('Display Options')) ->setKey('display') ->setOptions($this->getViewOptions()) ->setDefault('month'), ); } private function getCancelledOptions() { return array( 'active' => pht('Active Events Only'), 'cancelled' => pht('Cancelled Events Only'), 'both' => pht('Both Cancelled and Active Events'), ); } private function getViewOptions() { return array( 'month' => pht('Month View'), 'day' => pht('Day View'), 'list' => pht('List View'), ); } protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); $viewer = $this->requireViewer(); if ($map['hostPHIDs']) { $query->withHostPHIDs($map['hostPHIDs']); } if ($map['invitedPHIDs']) { $query->withInvitedPHIDs($map['invitedPHIDs']); } $range_start = $map['rangeStart']; $range_end = $map['rangeEnd']; $display = $map['display']; if ($map['upcoming'] && $map['upcoming'][0] == 'upcoming') { $upcoming = true; } else { $upcoming = false; } list($range_start, $range_end) = $this->getQueryDateRange( $range_start, $range_end, $display, $upcoming); $query->withDateRange($range_start, $range_end); switch ($map['isCancelled']) { case 'active': $query->withIsCancelled(false); break; case 'cancelled': $query->withIsCancelled(true); break; } + if ($map['importSourcePHIDs']) { + $query->withImportSourcePHIDs($map['importSourcePHIDs']); + } + // Generate ghosts (and ignore stub events) if we aren't querying for // specific events or exporting. if (!empty($map['export'])) { // This is a specific mode enabled by event exports. $query ->withIsStub(false); } else if (!$map['ids'] && !$map['phids']) { $query ->withIsStub(false) ->setGenerateGhosts(true); } return $query; } private function getQueryDateRange( $start_date_wild, $end_date_wild, $display, $upcoming) { $start_date_value = $this->getSafeDate($start_date_wild); $end_date_value = $this->getSafeDate($end_date_wild); $viewer = $this->requireViewer(); $timezone = new DateTimeZone($viewer->getTimezoneIdentifier()); $min_range = null; $max_range = null; $min_range = $start_date_value->getEpoch(); $max_range = $end_date_value->getEpoch(); if ($display == 'month' || $display == 'day') { list($start_year, $start_month, $start_day) = $this->getDisplayYearAndMonthAndDay($min_range, $max_range, $display); $start_day = new DateTime( "{$start_year}-{$start_month}-{$start_day}", $timezone); $next = clone $start_day; if ($display == 'month') { $next->modify('+1 month'); } else if ($display == 'day') { $next->modify('+7 day'); } $display_start = $start_day->format('U'); $display_end = $next->format('U'); $start_of_week = $viewer->getUserSetting( PhabricatorWeekStartDaySetting::SETTINGKEY); $end_of_week = ($start_of_week + 6) % 7; $first_of_month = $start_day->format('w'); $last_of_month = id(clone $next)->modify('-1 day')->format('w'); if (!$min_range || ($min_range < $display_start)) { $min_range = $display_start; if ($display == 'month' && $first_of_month !== $start_of_week) { $interim_day_num = ($first_of_month + 7 - $start_of_week) % 7; $min_range = id(clone $start_day) ->modify('-'.$interim_day_num.' days') ->format('U'); } } if (!$max_range || ($max_range > $display_end)) { $max_range = $display_end; if ($display == 'month' && $last_of_month !== $end_of_week) { $interim_day_num = ($end_of_week + 7 - $last_of_month) % 7; $max_range = id(clone $next) ->modify('+'.$interim_day_num.' days') ->format('U'); } } } if ($upcoming) { $now = PhabricatorTime::getNow(); if ($min_range) { $min_range = max($now, $min_range); } else { $min_range = $now; } } return array($min_range, $max_range); } protected function getURI($path) { return '/calendar/'.$path; } protected function getBuiltinQueryNames() { $names = array( 'month' => pht('Month View'), 'day' => pht('Day View'), 'upcoming' => pht('Upcoming Events'), 'all' => pht('All Events'), ); return $names; } public function setCalendarYearAndMonthAndDay($year, $month, $day = null) { $this->calendarYear = $year; $this->calendarMonth = $month; $this->calendarDay = $day; return $this; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'month': return $query->setParameter('display', 'month'); case 'day': return $query->setParameter('display', 'day'); case 'upcoming': return $query ->setParameter('display', 'list') ->setParameter('upcoming', array( 0 => 'upcoming', )); case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } protected function renderResultList( array $events, PhabricatorSavedQuery $query, array $handles) { if ($this->isMonthView($query)) { $result = $this->buildCalendarMonthView($events, $query); } else if ($this->isDayView($query)) { $result = $this->buildCalendarDayView($events, $query); } else { $result = $this->buildCalendarListView($events, $query); } return $result; } private function buildCalendarListView( array $events, PhabricatorSavedQuery $query) { assert_instances_of($events, 'PhabricatorCalendarEvent'); $viewer = $this->requireViewer(); $list = new PHUIObjectItemListView(); foreach ($events as $event) { if ($event->getIsGhostEvent()) { $monogram = $event->getParentEvent()->getMonogram(); $index = $event->getSequenceIndex(); $monogram = "{$monogram}/{$index}"; } else { $monogram = $event->getMonogram(); } $item = id(new PHUIObjectItemView()) ->setUser($viewer) ->setObject($event) ->setObjectName($monogram) ->setHeader($event->getName()) ->setHref($event->getURI()); $item->addAttribute($event->renderEventDate($viewer, false)); if ($event->isCancelledEvent()) { $item->setDisabled(true); } $status_icon = $event->getDisplayIcon($viewer); $status_color = $event->getDisplayIconColor($viewer); $status_label = $event->getDisplayIconLabel($viewer); $item->setStatusIcon("{$status_icon} {$status_color}", $status_label); $host = pht( 'Hosted by %s', $viewer->renderHandle($event->getHostPHID())); $item->addByline($host); $list->addItem($item); } - $result = new PhabricatorApplicationSearchResultView(); - $result->setObjectList($list); - $result->setNoDataString(pht('No events found.')); - - return $result; + return $this->newResultView() + ->setObjectList($list) + ->setNoDataString(pht('No events found.')); } private function buildCalendarMonthView( array $events, PhabricatorSavedQuery $query) { assert_instances_of($events, 'PhabricatorCalendarEvent'); $viewer = $this->requireViewer(); $now = PhabricatorTime::getNow(); list($start_year, $start_month) = $this->getDisplayYearAndMonthAndDay( $this->getQueryDateFrom($query)->getEpoch(), $this->getQueryDateTo($query)->getEpoch(), $query->getParameter('display')); $now_year = phabricator_format_local_time($now, $viewer, 'Y'); $now_month = phabricator_format_local_time($now, $viewer, 'm'); $now_day = phabricator_format_local_time($now, $viewer, 'j'); if ($start_month == $now_month && $start_year == $now_year) { $month_view = new PHUICalendarMonthView( $this->getQueryDateFrom($query), $this->getQueryDateTo($query), $start_month, $start_year, $now_day); } else { $month_view = new PHUICalendarMonthView( $this->getQueryDateFrom($query), $this->getQueryDateTo($query), $start_month, $start_year); } $month_view->setUser($viewer); foreach ($events as $event) { $epoch_min = $event->getStartDateTimeEpoch(); $epoch_max = $event->getEndDateTimeEpoch(); $event_view = id(new AphrontCalendarEventView()) ->setHostPHID($event->getHostPHID()) ->setEpochRange($epoch_min, $epoch_max) ->setIsCancelled($event->isCancelledEvent()) ->setName($event->getName()) ->setURI($event->getURI()) ->setIsAllDay($event->getIsAllDay()) ->setIcon($event->getDisplayIcon($viewer)) ->setIconColor($event->getDisplayIconColor($viewer)); $month_view->addEvent($event_view); } $month_view->setBrowseURI( $this->getURI('query/'.$query->getQueryKey().'/')); $from = $this->getQueryDateFrom($query)->getDateTime(); $crumbs = array(); $crumbs[] = id(new PHUICrumbView()) ->setName($from->format('F Y')); $header = id(new PHUIHeaderView()) ->setProfileHeader(true) ->setHeader($from->format('F Y')); - return id(new PhabricatorApplicationSearchResultView()) + return $this->newResultView($month_view) ->setCrumbs($crumbs) - ->setHeader($header) - ->setContent($month_view); + ->setHeader($header); } private function buildCalendarDayView( array $events, PhabricatorSavedQuery $query) { $viewer = $this->requireViewer(); list($start_year, $start_month, $start_day) = $this->getDisplayYearAndMonthAndDay( $this->getQueryDateFrom($query)->getEpoch(), $this->getQueryDateTo($query)->getEpoch(), $query->getParameter('display')); $day_view = id(new PHUICalendarDayView( $this->getQueryDateFrom($query), $this->getQueryDateTo($query), $start_year, $start_month, $start_day)) ->setQuery($query->getQueryKey()); $day_view->setUser($viewer); $phids = mpull($events, 'getHostPHID'); foreach ($events as $event) { $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $event, PhabricatorPolicyCapability::CAN_EDIT); $epoch_min = $event->getStartDateTimeEpoch(); $epoch_max = $event->getEndDateTimeEpoch(); $status_icon = $event->getDisplayIcon($viewer); $status_color = $event->getDisplayIconColor($viewer); $event_view = id(new AphrontCalendarEventView()) ->setCanEdit($can_edit) ->setEventID($event->getID()) ->setEpochRange($epoch_min, $epoch_max) ->setIsAllDay($event->getIsAllDay()) ->setIcon($status_icon) ->setIconColor($status_color) ->setName($event->getName()) ->setURI($event->getURI()) ->setIsCancelled($event->isCancelledEvent()); $day_view->addEvent($event_view); } $browse_uri = $this->getURI('query/'.$query->getQueryKey().'/'); $day_view->setBrowseURI($browse_uri); $from = $this->getQueryDateFrom($query)->getDateTime(); $month_uri = $browse_uri.$from->format('Y/m/'); $crumbs = array( id(new PHUICrumbView()) ->setName($from->format('F Y')) ->setHref($month_uri), id(new PHUICrumbView()) ->setName($from->format('D jS')), ); $header = id(new PHUIHeaderView()) ->setProfileHeader(true) ->setHeader($from->format('D, F jS')); - return id(new PhabricatorApplicationSearchResultView()) + return $this->newResultView($day_view) ->setCrumbs($crumbs) - ->setHeader($header) - ->setContent($day_view); + ->setHeader($header); } private function getDisplayYearAndMonthAndDay( $range_start, $range_end, $display) { $viewer = $this->requireViewer(); $epoch = null; if ($this->calendarYear && $this->calendarMonth) { $start_year = $this->calendarYear; $start_month = $this->calendarMonth; $start_day = $this->calendarDay ? $this->calendarDay : 1; } else { if ($range_start) { $epoch = $range_start; } else if ($range_end) { $epoch = $range_end; } else { $epoch = time(); } if ($display == 'month') { $day = 1; } else { $day = phabricator_format_local_time($epoch, $viewer, 'd'); } $start_year = phabricator_format_local_time($epoch, $viewer, 'Y'); $start_month = phabricator_format_local_time($epoch, $viewer, 'm'); $start_day = $day; } return array($start_year, $start_month, $start_day); } public function getPageSize(PhabricatorSavedQuery $saved) { if ($this->isMonthView($saved) || $this->isDayView($saved)) { return $saved->getParameter('limit', 1000); } else { return $saved->getParameter('limit', 100); } } private function getQueryDateFrom(PhabricatorSavedQuery $saved) { if ($this->calendarYear && $this->calendarMonth) { $viewer = $this->requireViewer(); $start_year = $this->calendarYear; $start_month = $this->calendarMonth; $start_day = $this->calendarDay ? $this->calendarDay : 1; return AphrontFormDateControlValue::newFromDictionary( $viewer, array( 'd' => "{$start_year}-{$start_month}-{$start_day}", )); } return $this->getQueryDate($saved, 'rangeStart'); } private function getQueryDateTo(PhabricatorSavedQuery $saved) { return $this->getQueryDate($saved, 'rangeEnd'); } private function getQueryDate(PhabricatorSavedQuery $saved, $key) { $viewer = $this->requireViewer(); $wild = $saved->getParameter($key); return $this->getSafeDate($wild); } private function getSafeDate($value) { $viewer = $this->requireViewer(); if ($value) { // ideally this would be consistent and always pass in the same type if ($value instanceof AphrontFormDateControlValue) { return $value; } else { $value = AphrontFormDateControlValue::newFromWild($viewer, $value); } } else { $value = AphrontFormDateControlValue::newFromEpoch( $viewer, PhabricatorTime::getTodayMidnightDateTime($viewer)->format('U')); $value->setEnabled(false); } $value->setOptional(true); return $value; } private function isMonthView(PhabricatorSavedQuery $query) { if ($this->isDayView($query)) { return false; } if ($query->getParameter('display') == 'month') { return true; } } private function isDayView(PhabricatorSavedQuery $query) { if ($query->getParameter('display') == 'day') { return true; } if ($this->calendarDay) { return true; } return false; } public function newUseResultsActions(PhabricatorSavedQuery $saved) { $viewer = $this->requireViewer(); $can_export = $viewer->isLoggedIn(); return array( id(new PhabricatorActionView()) ->setIcon('fa-download') ->setName(pht('Export Query as .ics')) ->setDisabled(!$can_export) ->setHref('/calendar/export/edit/?queryKey='.$saved->getQueryKey()), ); } + + private function newResultView($content = null) { + // If we aren't rendering a dashboard panel, activate global drag-and-drop + // so you can import ".ics" files by dropping them directly onto the + // calendar. + if (!$this->isPanelContext()) { + $drop_upload = id(new PhabricatorGlobalUploadTargetView()) + ->setViewer($this->requireViewer()) + ->setHintText("\xE2\x87\xAA ".pht('Drop .ics Files to Import')) + ->setSubmitURI('/calendar/import/drop/') + ->setViewPolicy(PhabricatorPolicies::POLICY_NOONE); + + $content = array( + $drop_upload, + $content, + ); + } + + return id(new PhabricatorApplicationSearchResultView()) + ->setContent($content); + } + } diff --git a/src/applications/calendar/query/PhabricatorCalendarImportLogQuery.php b/src/applications/calendar/query/PhabricatorCalendarImportLogQuery.php new file mode 100644 index 0000000000..81f309bdca --- /dev/null +++ b/src/applications/calendar/query/PhabricatorCalendarImportLogQuery.php @@ -0,0 +1,111 @@ +ids = $ids; + return $this; + } + + public function withPHIDs(array $phids) { + $this->phids = $phids; + return $this; + } + + public function withImportPHIDs(array $phids) { + $this->importPHIDs = $phids; + return $this; + } + + public function newResultObject() { + return new PhabricatorCalendarImportLog(); + } + + protected function loadPage() { + return $this->loadStandardPage($this->newResultObject()); + } + + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); + + if ($this->ids !== null) { + $where[] = qsprintf( + $conn, + 'log.id IN (%Ld)', + $this->ids); + } + + if ($this->phids !== null) { + $where[] = qsprintf( + $conn, + 'log.phid IN (%Ls)', + $this->phids); + } + + if ($this->importPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'log.importPHID IN (%Ls)', + $this->importPHIDs); + } + + + return $where; + } + + protected function willFilterPage(array $page) { + $viewer = $this->getViewer(); + + $type_map = PhabricatorCalendarImportLogType::getAllLogTypes(); + foreach ($page as $log) { + $type_constant = $log->getParameter('type'); + + $type_object = idx($type_map, $type_constant); + if (!$type_object) { + $type_object = new PhabricatorCalendarImportDefaultLogType(); + } + + $type_object = clone $type_object; + $log->attachLogType($type_object); + } + + $import_phids = mpull($page, 'getImportPHID'); + + if ($import_phids) { + $imports = id(new PhabricatorCalendarImportQuery()) + ->setViewer($viewer) + ->withPHIDs($import_phids) + ->execute(); + $imports = mpull($imports, null, 'getPHID'); + } else { + $imports = array(); + } + + foreach ($page as $key => $log) { + $import = idx($imports, $log->getImportPHID()); + if (!$import) { + $this->didRejectResult($import); + unset($page[$key]); + continue; + } + + $log->attachImport($import); + } + + return $page; + } + + protected function getPrimaryTableAlias() { + return 'log'; + } + + public function getQueryApplicationClass() { + return 'PhabricatorCalendarApplication'; + } + +} diff --git a/src/applications/calendar/query/PhabricatorCalendarImportLogSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarImportLogSearchEngine.php new file mode 100644 index 0000000000..81a1256fca --- /dev/null +++ b/src/applications/calendar/query/PhabricatorCalendarImportLogSearchEngine.php @@ -0,0 +1,77 @@ +setLabel(pht('Import Sources')) + ->setKey('importSourcePHIDs') + ->setAliases(array('importSourcePHID')), + ); + } + + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); + + if ($map['importSourcePHIDs']) { + $query->withImportPHIDs($map['importSourcePHIDs']); + } + + return $query; + } + + protected function getURI($path) { + return '/calendar/import/log/'.$path; + } + + protected function getBuiltinQueryNames() { + $names = array( + 'all' => pht('All Logs'), + ); + + return $names; + } + + public function buildSavedQueryFromBuiltin($query_key) { + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'all': + return $query; + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + + protected function renderResultList( + array $logs, + PhabricatorSavedQuery $query, + array $handles) { + + assert_instances_of($logs, 'PhabricatorCalendarImportLog'); + $viewer = $this->requireViewer(); + + $view = id(new PhabricatorCalendarImportLogView()) + ->setShowImportSources(true) + ->setViewer($viewer) + ->setLogs($logs); + + return id(new PhabricatorApplicationSearchResultView()) + ->setTable($view->newTable()); + } +} diff --git a/src/applications/calendar/query/PhabricatorCalendarImportQuery.php b/src/applications/calendar/query/PhabricatorCalendarImportQuery.php new file mode 100644 index 0000000000..5d44657994 --- /dev/null +++ b/src/applications/calendar/query/PhabricatorCalendarImportQuery.php @@ -0,0 +1,99 @@ +ids = $ids; + return $this; + } + + public function withPHIDs(array $phids) { + $this->phids = $phids; + return $this; + } + + public function withAuthorPHIDs(array $phids) { + $this->authorPHIDs = $phids; + return $this; + } + + public function withIsDisabled($is_disabled) { + $this->isDisabled = $is_disabled; + return $this; + } + + public function newResultObject() { + return new PhabricatorCalendarImport(); + } + + protected function loadPage() { + return $this->loadStandardPage($this->newResultObject()); + } + + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); + + if ($this->ids !== null) { + $where[] = qsprintf( + $conn, + 'import.id IN (%Ld)', + $this->ids); + } + + if ($this->phids !== null) { + $where[] = qsprintf( + $conn, + 'import.phid IN (%Ls)', + $this->phids); + } + + if ($this->authorPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'import.authorPHID IN (%Ls)', + $this->authorPHIDs); + } + + if ($this->isDisabled !== null) { + $where[] = qsprintf( + $conn, + 'import.isDisabled = %d', + (int)$this->isDisabled); + } + + return $where; + } + + protected function willFilterPage(array $page) { + $engines = PhabricatorCalendarImportEngine::getAllImportEngines(); + foreach ($page as $key => $import) { + $engine_type = $import->getEngineType(); + $engine = idx($engines, $engine_type); + + if (!$engine) { + unset($page[$key]); + $this->didRejectResult($import); + continue; + } + + $import->attachEngine(clone $engine); + } + + return $page; + } + + protected function getPrimaryTableAlias() { + return 'import'; + } + + public function getQueryApplicationClass() { + return 'PhabricatorCalendarApplication'; + } + +} diff --git a/src/applications/calendar/query/PhabricatorCalendarImportSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarImportSearchEngine.php new file mode 100644 index 0000000000..75252b6dac --- /dev/null +++ b/src/applications/calendar/query/PhabricatorCalendarImportSearchEngine.php @@ -0,0 +1,81 @@ +newQuery(); + + return $query; + } + + protected function getURI($path) { + return '/calendar/import/'.$path; + } + + protected function getBuiltinQueryNames() { + $names = array( + 'all' => pht('All Imports'), + ); + + return $names; + } + + public function buildSavedQueryFromBuiltin($query_key) { + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'all': + return $query; + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + + protected function renderResultList( + array $imports, + PhabricatorSavedQuery $query, + array $handles) { + + assert_instances_of($imports, 'PhabricatorCalendarImport'); + $viewer = $this->requireViewer(); + + $list = new PHUIObjectItemListView(); + foreach ($imports as $import) { + $item = id(new PHUIObjectItemView()) + ->setViewer($viewer) + ->setObjectName(pht('Import %d', $import->getID())) + ->setHeader($import->getDisplayName()) + ->setHref($import->getURI()); + + if ($import->getIsDisabled()) { + $item->setDisabled(true); + } + + $list->addItem($item); + } + + $result = new PhabricatorApplicationSearchResultView(); + $result->setObjectList($list); + $result->setNoDataString(pht('No imports found.')); + + return $result; + } +} diff --git a/src/applications/calendar/query/PhabricatorCalendarImportTransactionQuery.php b/src/applications/calendar/query/PhabricatorCalendarImportTransactionQuery.php new file mode 100644 index 0000000000..123ec9b3c4 --- /dev/null +++ b/src/applications/calendar/query/PhabricatorCalendarImportTransactionQuery.php @@ -0,0 +1,10 @@ +setViewer($actor) ->withClasses(array('PhabricatorCalendarApplication')) ->executeOne(); $view_default = PhabricatorCalendarEventDefaultViewCapability::CAPABILITY; $edit_default = PhabricatorCalendarEventDefaultEditCapability::CAPABILITY; $view_policy = $app->getPolicy($view_default); $edit_policy = $app->getPolicy($edit_default); $now = PhabricatorTime::getNow(); $default_icon = 'fa-calendar'; $datetime_start = PhutilCalendarAbsoluteDateTime::newFromEpoch( $now, $actor->getTimezoneIdentifier()); $datetime_end = $datetime_start->newRelativeDateTime('PT1H'); return id(new PhabricatorCalendarEvent()) + ->setDescription('') ->setHostPHID($actor->getPHID()) ->setIsCancelled(0) ->setIsAllDay(0) ->setIsStub(0) ->setIsRecurring(0) ->setIcon($default_icon) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) ->setSpacePHID($actor->getDefaultSpacePHID()) ->attachInvitees(array()) ->setDateFrom(0) ->setDateTo(0) ->setAllDayDateFrom(0) ->setAllDayDateTo(0) ->setStartDateTime($datetime_start) ->setEndDateTime($datetime_end) + ->attachImportSource(null) ->applyViewerTimezone($actor); } private function newChild( PhabricatorUser $actor, $sequence, PhutilCalendarDateTime $start = null) { if (!$this->isParentEvent()) { throw new Exception( pht( 'Unable to generate a new child event for an event which is not '. 'a recurring parent event!')); } $child = id(new self()) ->setIsCancelled(0) ->setIsStub(0) ->setInstanceOfEventPHID($this->getPHID()) ->setSequenceIndex($sequence) ->setIsRecurring(true) ->attachParentEvent($this) ->setAllDayDateFrom(0) ->setAllDayDateTo(0) ->setDateFrom(0) ->setDateTo(0); return $child->copyFromParent($actor, $start); } protected function readField($field) { static $inherit = array( 'hostPHID' => true, 'isAllDay' => true, 'icon' => true, 'spacePHID' => true, 'viewPolicy' => true, 'editPolicy' => true, 'name' => true, 'description' => true, ); // Read these fields from the parent event instead of this event. For // example, we want any changes to the parent event's name to apply to // the child. if (isset($inherit[$field])) { if ($this->getIsStub()) { // TODO: This should be unconditional, but the execution order of // CalendarEventQuery and applyViewerTimezone() are currently odd. if ($this->parentEvent !== self::ATTACHABLE) { return $this->getParentEvent()->readField($field); } } } return parent::readField($field); } public function copyFromParent( PhabricatorUser $actor, PhutilCalendarDateTime $start = null) { if (!$this->isChildEvent()) { throw new Exception( pht( 'Unable to copy from parent event: this is not a child event.')); } $parent = $this->getParentEvent(); $this ->setHostPHID($parent->getHostPHID()) ->setIsAllDay($parent->getIsAllDay()) ->setIcon($parent->getIcon()) ->setSpacePHID($parent->getSpacePHID()) ->setViewPolicy($parent->getViewPolicy()) ->setEditPolicy($parent->getEditPolicy()) ->setName($parent->getName()) ->setDescription($parent->getDescription()); - $sequence = $this->getSequenceIndex(); - if ($start) { $start_datetime = $start; } else { + $sequence = $this->getSequenceIndex(); $start_datetime = $parent->newSequenceIndexDateTime($sequence); if (!$start_datetime) { throw new Exception( pht( 'Sequence "%s" is not valid for event!', $sequence)); } } $duration = $parent->newDuration(); $end_datetime = $start_datetime->newRelativeDateTime($duration); $this ->setStartDateTime($start_datetime) ->setEndDateTime($end_datetime); + if ($parent->isImportedEvent()) { + $full_uid = $parent->getImportUID().'/'.$start_datetime->getEpoch(); + + // NOTE: We don't attach the import source because this gets called + // from CalendarEventQuery while building ghosts, before we've loaded + // and attached sources. Possibly this sequence should be flipped. + + $this + ->setImportAuthorPHID($parent->getImportAuthorPHID()) + ->setImportSourcePHID($parent->getImportSourcePHID()) + ->setImportUID($full_uid); + } + return $this; } public function isValidSequenceIndex(PhabricatorUser $viewer, $sequence) { return (bool)$this->newSequenceIndexDateTime($sequence); } public function newSequenceIndexDateTime($sequence) { $set = $this->newRecurrenceSet(); if (!$set) { return null; } $instances = $set->getEventsBetween( null, $this->newUntilDateTime(), $sequence + 1); return idx($instances, $sequence, null); } public function newStub(PhabricatorUser $actor, $sequence) { $stub = $this->newChild($actor, $sequence); $stub->setIsStub(1); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $stub->save(); unset($unguarded); $stub->applyViewerTimezone($actor); return $stub; } public function newGhost( PhabricatorUser $actor, $sequence, PhutilCalendarDateTime $start = null) { $ghost = $this->newChild($actor, $sequence, $start); $ghost ->setIsGhostEvent(true) ->makeEphemeral(); $ghost->applyViewerTimezone($actor); return $ghost; } public function applyViewerTimezone(PhabricatorUser $viewer) { $this->viewerTimezone = $viewer->getTimezoneIdentifier(); return $this; } public function getDuration() { return ($this->getEndDateTimeEpoch() - $this->getStartDateTimeEpoch()); } public function updateUTCEpochs() { // The "intitial" epoch is the start time of the event, in UTC. $start_date = $this->newStartDateTime() ->setViewerTimezone('UTC'); $start_epoch = $start_date->getEpoch(); $this->setUTCInitialEpoch($start_epoch); // The "until" epoch is the last UTC epoch on which any instance of this // event occurs. For infinitely recurring events, it is `null`. if (!$this->getIsRecurring()) { $end_date = $this->newEndDateTime() ->setViewerTimezone('UTC'); $until_epoch = $end_date->getEpoch(); } else { $until_epoch = null; $until_date = $this->newUntilDateTime(); if ($until_date) { $until_date->setViewerTimezone('UTC'); $duration = $this->newDuration(); $until_epoch = id(new PhutilCalendarRelativeDateTime()) ->setOrigin($until_date) ->setDuration($duration) ->getEpoch(); } } $this->setUTCUntilEpoch($until_epoch); // The "instance" epoch is a property of instances of recurring events. // It's the original UTC epoch on which the instance started. Usually that // is the same as the start date, but they may be different if the instance // has been edited. // The ICS format uses this value (original start time) to identify event // instances, and must do so because it allows additional arbitrary // instances to be added (with "RDATE"). $instance_epoch = null; $instance_date = $this->newInstanceDateTime(); if ($instance_date) { $instance_epoch = $instance_date ->setViewerTimezone('UTC') ->getEpoch(); } $this->setUTCInstanceEpoch($instance_epoch); return $this; } public function save() { if (!$this->mailKey) { $this->mailKey = Filesystem::readRandomCharacters(20); } + $import_uid = $this->getImportUID(); + if ($import_uid !== null) { + $index = PhabricatorHash::digestForIndex($import_uid); + } else { + $index = null; + } + $this->setImportUIDIndex($index); + $this->updateUTCEpochs(); return parent::save(); } /** * Get the event start epoch for evaluating invitee availability. * * When assessing availability, we pretend events start earlier than they * really do. This allows us to mark users away for the entire duration of a * series of back-to-back meetings, even if they don't strictly overlap. * * @return int Event start date for availability caches. */ public function getStartDateTimeEpochForCache() { $epoch = $this->getStartDateTimeEpoch(); $window = phutil_units('15 minutes in seconds'); return ($epoch - $window); } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'text', 'description' => 'text', 'isCancelled' => 'bool', 'isAllDay' => 'bool', 'icon' => 'text32', 'mailKey' => 'bytes20', 'isRecurring' => 'bool', 'instanceOfEventPHID' => 'phid?', 'sequenceIndex' => 'uint32?', 'isStub' => 'bool', 'utcInitialEpoch' => 'epoch', 'utcUntilEpoch' => 'epoch?', 'utcInstanceEpoch' => 'epoch?', + 'importAuthorPHID' => 'phid?', + 'importSourcePHID' => 'phid?', + 'importUIDIndex' => 'bytes12?', + 'importUID' => 'text?', + // TODO: DEPRECATED. 'allDayDateFrom' => 'epoch', 'allDayDateTo' => 'epoch', 'dateFrom' => 'epoch', 'dateTo' => 'epoch', 'recurrenceEndDate' => 'epoch?', ), self::CONFIG_KEY_SCHEMA => array( 'key_date' => array( 'columns' => array('dateFrom', 'dateTo'), ), 'key_instance' => array( 'columns' => array('instanceOfEventPHID', 'sequenceIndex'), 'unique' => true, ), 'key_epoch' => array( 'columns' => array('utcInitialEpoch', 'utcUntilEpoch'), ), 'key_rdate' => array( 'columns' => array('instanceOfEventPHID', 'utcInstanceEpoch'), 'unique' => true, ), ), self::CONFIG_SERIALIZATION => array( 'recurrenceFrequency' => self::SERIALIZATION_JSON, 'parameters' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorCalendarEventPHIDType::TYPECONST); } public function getMonogram() { return 'E'.$this->getID(); } public function getInvitees() { return $this->assertAttached($this->invitees); } public function attachInvitees(array $invitees) { $this->invitees = $invitees; return $this; } public function getInviteePHIDsForEdit() { $invitees = array(); foreach ($this->getInvitees() as $invitee) { if ($invitee->isUninvited()) { continue; } $invitees[] = $invitee->getInviteePHID(); } return $invitees; } public function getUserInviteStatus($phid) { $invitees = $this->getInvitees(); $invitees = mpull($invitees, null, 'getInviteePHID'); $invited = idx($invitees, $phid); if (!$invited) { return PhabricatorCalendarEventInvitee::STATUS_UNINVITED; } $invited = $invited->getStatus(); return $invited; } public function getIsUserAttending($phid) { $attending_status = PhabricatorCalendarEventInvitee::STATUS_ATTENDING; $old_status = $this->getUserInviteStatus($phid); $is_attending = ($old_status == $attending_status); return $is_attending; } public function getIsUserInvited($phid) { $uninvited_status = PhabricatorCalendarEventInvitee::STATUS_UNINVITED; $declined_status = PhabricatorCalendarEventInvitee::STATUS_DECLINED; $status = $this->getUserInviteStatus($phid); if ($status == $uninvited_status || $status == $declined_status) { return false; } return true; } public function getIsGhostEvent() { return $this->isGhostEvent; } public function setIsGhostEvent($is_ghost_event) { $this->isGhostEvent = $is_ghost_event; return $this; } public function getURI() { if ($this->getIsGhostEvent()) { $base = $this->getParentEvent()->getURI(); $sequence = $this->getSequenceIndex(); return "{$base}/{$sequence}/"; } return '/'.$this->getMonogram(); } public function getParentEvent() { return $this->assertAttached($this->parentEvent); } public function attachParentEvent($event) { $this->parentEvent = $event; return $this; } public function isParentEvent() { return ($this->getIsRecurring() && !$this->getInstanceOfEventPHID()); } public function isChildEvent() { return ($this->instanceOfEventPHID !== null); } public function isCancelledEvent() { if ($this->getIsCancelled()) { return true; } if ($this->isChildEvent()) { if ($this->getParentEvent()->getIsCancelled()) { return true; } } return false; } public function renderEventDate( PhabricatorUser $viewer, $show_end) { $start = $this->newStartDateTime(); $end = $this->newEndDateTime(); if ($show_end) { $min_date = $start->newPHPDateTime(); $max_date = $end->newPHPDateTime(); $min_day = $min_date->format('Y m d'); $max_day = $max_date->format('Y m d'); $show_end_date = ($min_day != $max_day); } else { $show_end_date = false; } $min_epoch = $start->getEpoch(); $max_epoch = $end->getEpoch(); if ($this->getIsAllDay()) { if ($show_end_date) { return pht( '%s - %s, All Day', phabricator_date($min_epoch, $viewer), phabricator_date($max_epoch, $viewer)); } else { return pht( '%s, All Day', phabricator_date($min_epoch, $viewer)); } } else if ($show_end_date) { return pht( '%s - %s', phabricator_datetime($min_epoch, $viewer), phabricator_datetime($max_epoch, $viewer)); } else if ($show_end) { return pht( '%s - %s', phabricator_datetime($min_epoch, $viewer), phabricator_time($max_epoch, $viewer)); } else { return pht( '%s', phabricator_datetime($min_epoch, $viewer)); } } public function getDisplayIcon(PhabricatorUser $viewer) { if ($this->isCancelledEvent()) { return 'fa-times'; } if ($viewer->isLoggedIn()) { $status = $this->getUserInviteStatus($viewer->getPHID()); switch ($status) { case PhabricatorCalendarEventInvitee::STATUS_ATTENDING: return 'fa-check-circle'; case PhabricatorCalendarEventInvitee::STATUS_INVITED: return 'fa-user-plus'; case PhabricatorCalendarEventInvitee::STATUS_DECLINED: return 'fa-times'; } } + if ($this->isImportedEvent()) { + return 'fa-download'; + } + return $this->getIcon(); } public function getDisplayIconColor(PhabricatorUser $viewer) { if ($this->isCancelledEvent()) { return 'red'; } + if ($this->isImportedEvent()) { + return 'orange'; + } + if ($viewer->isLoggedIn()) { $status = $this->getUserInviteStatus($viewer->getPHID()); switch ($status) { case PhabricatorCalendarEventInvitee::STATUS_ATTENDING: return 'green'; case PhabricatorCalendarEventInvitee::STATUS_INVITED: return 'green'; case PhabricatorCalendarEventInvitee::STATUS_DECLINED: return 'grey'; } } return 'bluegrey'; } public function getDisplayIconLabel(PhabricatorUser $viewer) { if ($this->isCancelledEvent()) { return pht('Cancelled'); } if ($viewer->isLoggedIn()) { $status = $this->getUserInviteStatus($viewer->getPHID()); switch ($status) { case PhabricatorCalendarEventInvitee::STATUS_ATTENDING: return pht('Attending'); case PhabricatorCalendarEventInvitee::STATUS_INVITED: return pht('Invited'); case PhabricatorCalendarEventInvitee::STATUS_DECLINED: return pht('Declined'); } } return null; } public function getICSFilename() { return $this->getMonogram().'.ics'; } public function newIntermediateEventNode( PhabricatorUser $viewer, array $children) { $base_uri = new PhutilURI(PhabricatorEnv::getProductionURI('/')); $domain = $base_uri->getDomain(); // NOTE: For recurring events, all of the events in the series have the // same UID (the UID of the parent). The child event instances are // differentiated by the "RECURRENCE-ID" field. if ($this->isChildEvent()) { $parent = $this->getParentEvent(); $instance_datetime = PhutilCalendarAbsoluteDateTime::newFromEpoch( $this->getUTCInstanceEpoch()); $recurrence_id = $instance_datetime->getISO8601(); $rrule = null; } else { $parent = $this; $recurrence_id = null; $rrule = $this->newRecurrenceRule(); } $uid = $parent->getPHID().'@'.$domain; $created = $this->getDateCreated(); $created = PhutilCalendarAbsoluteDateTime::newFromEpoch($created); $modified = $this->getDateModified(); $modified = PhutilCalendarAbsoluteDateTime::newFromEpoch($modified); $date_start = $this->newStartDateTime(); $date_end = $this->newEndDateTime(); if ($this->getIsAllDay()) { $date_start->setIsAllDay(true); $date_end->setIsAllDay(true); } $host_phid = $this->getHostPHID(); $invitees = $this->getInvitees(); foreach ($invitees as $key => $invitee) { if ($invitee->isUninvited()) { unset($invitees[$key]); } } $phids = array(); $phids[] = $host_phid; foreach ($invitees as $invitee) { $phids[] = $invitee->getInviteePHID(); } $handles = $viewer->loadHandles($phids); $host_handle = $handles[$host_phid]; $host_name = $host_handle->getFullName(); $host_uri = $host_handle->getURI(); $host_uri = PhabricatorEnv::getURI($host_uri); $organizer = id(new PhutilCalendarUserNode()) ->setName($host_name) ->setURI($host_uri); $attendees = array(); foreach ($invitees as $invitee) { $invitee_phid = $invitee->getInviteePHID(); $invitee_handle = $handles[$invitee_phid]; $invitee_name = $invitee_handle->getFullName(); $invitee_uri = $invitee_handle->getURI(); $invitee_uri = PhabricatorEnv::getURI($invitee_uri); switch ($invitee->getStatus()) { case PhabricatorCalendarEventInvitee::STATUS_ATTENDING: $status = PhutilCalendarUserNode::STATUS_ACCEPTED; break; case PhabricatorCalendarEventInvitee::STATUS_DECLINED: $status = PhutilCalendarUserNode::STATUS_DECLINED; break; case PhabricatorCalendarEventInvitee::STATUS_INVITED: default: $status = PhutilCalendarUserNode::STATUS_INVITED; break; } $attendees[] = id(new PhutilCalendarUserNode()) ->setName($invitee_name) ->setURI($invitee_uri) ->setStatus($status); } // TODO: Use $children to generate EXDATE/RDATE information. $node = id(new PhutilCalendarEventNode()) ->setUID($uid) ->setName($this->getName()) ->setDescription($this->getDescription()) ->setCreatedDateTime($created) ->setModifiedDateTime($modified) ->setStartDateTime($date_start) ->setEndDateTime($date_end) ->setOrganizer($organizer) ->setAttendees($attendees); if ($rrule) { $node->setRecurrenceRule($rrule); } if ($recurrence_id) { $node->setRecurrenceID($recurrence_id); } return $node; } public function newStartDateTime() { $datetime = $this->getParameter('startDateTime'); if ($datetime) { return $this->newDateTimeFromDictionary($datetime); } $epoch = $this->getDateFrom(); return $this->newDateTimeFromEpoch($epoch); } public function getStartDateTimeEpoch() { return $this->newStartDateTime()->getEpoch(); } public function newEndDateTime() { $datetime = $this->getParameter('endDateTime'); if ($datetime) { return $this->newDateTimeFromDictionary($datetime); } $epoch = $this->getDateTo(); return $this->newDateTimeFromEpoch($epoch); } public function getEndDateTimeEpoch() { return $this->newEndDateTime()->getEpoch(); } public function newUntilDateTime() { $datetime = $this->getParameter('untilDateTime'); if ($datetime) { return $this->newDateTimeFromDictionary($datetime); } $epoch = $this->getRecurrenceEndDate(); if (!$epoch) { return null; } return $this->newDateTimeFromEpoch($epoch); } public function getUntilDateTimeEpoch() { $datetime = $this->newUntilDateTime(); if (!$datetime) { return null; } return $datetime->getEpoch(); } public function newDuration() { return id(new PhutilCalendarDuration()) ->setSeconds($this->getDuration()); } public function newInstanceDateTime() { if (!$this->getIsRecurring()) { return null; } $index = $this->getSequenceIndex(); if (!$index) { return null; } return $this->newSequenceIndexDateTime($index); } private function newDateTimeFromEpoch($epoch) { $datetime = PhutilCalendarAbsoluteDateTime::newFromEpoch($epoch); if ($this->getIsAllDay()) { $datetime->setIsAllDay(true); } return $this->newDateTimeFromDateTime($datetime); } private function newDateTimeFromDictionary(array $dict) { $datetime = PhutilCalendarAbsoluteDateTime::newFromDictionary($dict); return $this->newDateTimeFromDateTime($datetime); } private function newDateTimeFromDateTime(PhutilCalendarDateTime $datetime) { $viewer_timezone = $this->viewerTimezone; if ($viewer_timezone) { $datetime->setViewerTimezone($viewer_timezone); } return $datetime; } public function getParameter($key, $default = null) { return idx($this->parameters, $key, $default); } public function setParameter($key, $value) { $this->parameters[$key] = $value; return $this; } public function setStartDateTime(PhutilCalendarDateTime $datetime) { return $this->setParameter( 'startDateTime', $datetime->newAbsoluteDateTime()->toDictionary()); } public function setEndDateTime(PhutilCalendarDateTime $datetime) { return $this->setParameter( 'endDateTime', $datetime->newAbsoluteDateTime()->toDictionary()); } public function setUntilDateTime(PhutilCalendarDateTime $datetime) { return $this->setParameter( 'untilDateTime', $datetime->newAbsoluteDateTime()->toDictionary()); } public function setRecurrenceRule(PhutilCalendarRecurrenceRule $rrule) { return $this->setParameter( 'recurrenceRule', $rrule->toDictionary()); } public function newRecurrenceRule() { if ($this->isChildEvent()) { return $this->getParentEvent()->newRecurrenceRule(); } if (!$this->getIsRecurring()) { return null; } $dict = $this->getParameter('recurrenceRule'); if (!$dict) { return null; } $rrule = PhutilCalendarRecurrenceRule::newFromDictionary($dict); $start = $this->newStartDateTime(); $rrule->setStartDateTime($start); $until = $this->newUntilDateTime(); if ($until) { $rrule->setUntil($until); } return $rrule; } public function newRecurrenceSet() { if ($this->isChildEvent()) { return $this->getParentEvent()->newRecurrenceSet(); } $set = new PhutilCalendarRecurrenceSet(); $rrule = $this->newRecurrenceRule(); if (!$rrule) { return null; } $set->addSource($rrule); return $set; } + public function isImportedEvent() { + return (bool)$this->getImportSourcePHID(); + } + + public function getImportSource() { + return $this->assertAttached($this->importSource); + } + + public function attachImportSource( + PhabricatorCalendarImport $import = null) { + $this->importSource = $import; + return $this; + } + + /* -( Markup Interface )--------------------------------------------------- */ /** * @task markup */ public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); $id = $this->getID(); return "calendar:T{$id}:{$field}:{$hash}"; } /** * @task markup */ public function getMarkupText($field) { return $this->getDescription(); } /** * @task markup */ public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newCalendarMarkupEngine(); } /** * @task markup */ public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } /** * @task markup */ public function shouldUseMarkupCache($field) { return (bool)$this->getID(); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: - return $this->getEditPolicy(); + if ($this->getImportSource()) { + return PhabricatorPolicies::POLICY_NOONE; + } else { + return $this->getEditPolicy(); + } } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + if ($this->getImportSource()) { + return false; + } + // The host of an event can always view and edit it. $user_phid = $this->getHostPHID(); if ($user_phid) { $viewer_phid = $viewer->getPHID(); if ($viewer_phid == $user_phid) { return true; } } if ($capability == PhabricatorPolicyCapability::CAN_VIEW) { $status = $this->getUserInviteStatus($viewer->getPHID()); if ($status == PhabricatorCalendarEventInvitee::STATUS_INVITED || $status == PhabricatorCalendarEventInvitee::STATUS_ATTENDING || $status == PhabricatorCalendarEventInvitee::STATUS_DECLINED) { return true; } } return false; } public function describeAutomaticCapability($capability) { + if ($this->getImportSource()) { + return pht( + 'Events imported from external sources can not be edited in '. + 'Phabricator.'); + } + return pht( 'The host of an event can always view and edit it. Users who are '. 'invited to an event can always view it.'); } +/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */ + + + public function getExtendedPolicy($capability, PhabricatorUser $viewer) { + $extended = array(); + + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + $import_source = $this->getImportSource(); + if ($import_source) { + $extended[] = array( + $import_source, + PhabricatorPolicyCapability::CAN_VIEW, + ); + } + break; + } + + return $extended; + } + + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new PhabricatorCalendarEventEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new PhabricatorCalendarEventTransaction(); } public function willRenderTimeline( PhabricatorApplicationTransactionView $timeline, AphrontRequest $request) { return $timeline; } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return ($phid == $this->getHostPHID()); } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array($this->getHostPHID()); } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } /* -( PhabricatorSpacesInterface )----------------------------------------- */ public function getSpacePHID() { return $this->spacePHID; } /* -( PhabricatorFulltextInterface )--------------------------------------- */ public function newFulltextEngine() { return new PhabricatorCalendarEventFulltextEngine(); } /* -( PhabricatorConduitResultInterface )---------------------------------- */ public function getFieldSpecificationsForConduit() { return array( id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('name') ->setType('string') ->setDescription(pht('The name of the event.')), id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('description') ->setType('string') ->setDescription(pht('The event description.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('isAllDay') + ->setType('bool') + ->setDescription(pht('True if the event is an all day event.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('startDateTime') + ->setType('datetime') + ->setDescription(pht('Start date and time of the event.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('endDateTime') + ->setType('datetime') + ->setDescription(pht('End date and time of the event.')), ); } public function getFieldValuesForConduit() { + $start_datetime = $this->newStartDateTime(); + $end_datetime = $this->newEndDateTime(); + return array( 'name' => $this->getName(), 'description' => $this->getDescription(), + 'isAllDay' => (bool)$this->getIsAllDay(), + 'startDateTime' => $this->getConduitDateTime($start_datetime), + 'endDateTime' => $this->getConduitDateTime($end_datetime), ); } public function getConduitSearchAttachments() { return array(); } + private function getConduitDateTime($datetime) { + if (!$datetime) { + return null; + } + + $epoch = $datetime->getEpoch(); + + // TODO: Possibly pass the actual viewer in from the Conduit stuff, or + // retain it when setting the viewer timezone? + $viewer = id(new PhabricatorUser()) + ->overrideTimezoneIdentifier($this->viewerTimezone); + + return array( + 'epoch' => (int)$epoch, + 'display' => array( + 'default' => phabricator_datetime($epoch, $viewer), + ), + 'iso8601' => $datetime->getISO8601(), + 'timezone' => $this->viewerTimezone, + ); + } + } diff --git a/src/applications/calendar/storage/PhabricatorCalendarImport.php b/src/applications/calendar/storage/PhabricatorCalendarImport.php new file mode 100644 index 0000000000..93b0897ee5 --- /dev/null +++ b/src/applications/calendar/storage/PhabricatorCalendarImport.php @@ -0,0 +1,178 @@ +setName('') + ->setAuthorPHID($actor->getPHID()) + ->setViewPolicy($actor->getPHID()) + ->setEditPolicy($actor->getPHID()) + ->setIsDisabled(0) + ->setEngineType($engine->getImportEngineType()) + ->attachEngine($engine); + } + + protected function getConfiguration() { + return array( + self::CONFIG_AUX_PHID => true, + self::CONFIG_SERIALIZATION => array( + 'parameters' => self::SERIALIZATION_JSON, + ), + self::CONFIG_COLUMN_SCHEMA => array( + 'name' => 'text', + 'engineType' => 'text64', + 'isDisabled' => 'bool', + ), + self::CONFIG_KEY_SCHEMA => array( + 'key_author' => array( + 'columns' => array('authorPHID'), + ), + ), + ) + parent::getConfiguration(); + } + + public function getPHIDType() { + return PhabricatorCalendarImportPHIDType::TYPECONST; + } + + public function getURI() { + $id = $this->getID(); + return "/calendar/import/{$id}/"; + } + + public function attachEngine(PhabricatorCalendarImportEngine $engine) { + $this->engine = $engine; + return $this; + } + + public function getEngine() { + return $this->assertAttached($this->engine); + } + + public function getParameter($key, $default = null) { + return idx($this->parameters, $key, $default); + } + + public function setParameter($key, $value) { + $this->parameters[$key] = $value; + return $this; + } + + public function getDisplayName() { + $name = $this->getName(); + if (strlen($name)) { + return $name; + } + + return $this->getEngine()->getDisplayName($this); + } + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + ); + } + + public function getPolicy($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return $this->getViewPolicy(); + case PhabricatorPolicyCapability::CAN_EDIT: + return $this->getEditPolicy(); + } + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return false; + } + + public function describeAutomaticCapability($capability) { + return null; + } + + +/* -( PhabricatorApplicationTransactionInterface )------------------------- */ + + + public function getApplicationTransactionEditor() { + return new PhabricatorCalendarImportEditor(); + } + + public function getApplicationTransactionObject() { + return $this; + } + + public function getApplicationTransactionTemplate() { + return new PhabricatorCalendarImportTransaction(); + } + + public function willRenderTimeline( + PhabricatorApplicationTransactionView $timeline, + AphrontRequest $request) { + return $timeline; + } + + public function newLogMessage($type, array $parameters) { + $parameters = array( + 'type' => $type, + ) + $parameters; + + return id(new PhabricatorCalendarImportLog()) + ->setImportPHID($this->getPHID()) + ->setParameters($parameters) + ->save(); + } + + +/* -( PhabricatorDestructibleInterface )----------------------------------- */ + + + public function destroyObjectPermanently( + PhabricatorDestructionEngine $engine) { + $viewer = $engine->getViewer(); + + $this->openTransaction(); + + $events = id(new PhabricatorCalendarEventQuery()) + ->setViewer($viewer) + ->withImportSourcePHIDs(array($this->getPHID())) + ->execute(); + foreach ($events as $event) { + $engine->destroyObject($event); + } + + $logs = id(new PhabricatorCalendarImportLogQuery()) + ->setViewer($viewer) + ->withImportPHIDs(array($this->getPHID())) + ->execute(); + foreach ($logs as $log) { + $engine->destroyObject($log); + } + + $this->delete(); + $this->saveTransaction(); + } + +} diff --git a/src/applications/calendar/storage/PhabricatorCalendarImportLog.php b/src/applications/calendar/storage/PhabricatorCalendarImportLog.php new file mode 100644 index 0000000000..e25a3090e0 --- /dev/null +++ b/src/applications/calendar/storage/PhabricatorCalendarImportLog.php @@ -0,0 +1,103 @@ + array( + 'parameters' => self::SERIALIZATION_JSON, + ), + self::CONFIG_KEY_SCHEMA => array( + 'key_import' => array( + 'columns' => array('importPHID'), + ), + ), + ) + parent::getConfiguration(); + } + + public function getParameter($key, $default = null) { + return idx($this->parameters, $key, $default); + } + + public function setParameter($key, $value) { + $this->parameters[$key] = $value; + return $this; + } + + public function getImport() { + return $this->assertAttached($this->import); + } + + public function attachImport(PhabricatorCalendarImport $import) { + $this->import = $import; + return $this; + } + + public function getDisplayIcon(PhabricatorUser $viewer) { + return $this->getLogType()->getDisplayIcon($viewer, $this); + } + + public function getDisplayColor(PhabricatorUser $viewer) { + return $this->getLogType()->getDisplayColor($viewer, $this); + } + + public function getDisplayType(PhabricatorUser $viewer) { + return $this->getLogType()->getDisplayType($viewer, $this); + } + + public function getDisplayDescription(PhabricatorUser $viewer) { + return $this->getLogType()->getDisplayDescription($viewer, $this); + } + + public function getLogType() { + return $this->assertAttached($this->logType); + } + + public function attachLogType(PhabricatorCalendarImportLogType $type) { + $this->logType = $type; + return $this; + } + + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + ); + } + + public function getPolicy($capability) { + return PhabricatorPolicies::getMostOpenPolicy(); + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return false; + } + + public function describeAutomaticCapability($capability) { + return null; + } + + +/* -( PhabricatorDestructibleInterface )----------------------------------- */ + + + public function destroyObjectPermanently( + PhabricatorDestructionEngine $engine) { + $viewer = $engine->getViewer(); + $this->delete(); + } + +} diff --git a/src/applications/calendar/storage/PhabricatorCalendarImportTransaction.php b/src/applications/calendar/storage/PhabricatorCalendarImportTransaction.php new file mode 100644 index 0000000000..2102e94576 --- /dev/null +++ b/src/applications/calendar/storage/PhabricatorCalendarImportTransaction.php @@ -0,0 +1,18 @@ +logs = $logs; + return $this; + } + + public function getLogs() { + return $this->logs; + } + + public function setShowImportSources($show_import_sources) { + $this->showImportSources = $show_import_sources; + return $this; + } + + public function getShowImportSources() { + return $this->showImportSources; + } + + public function render() { + return $this->newTable(); + } + + public function newTable() { + $viewer = $this->getViewer(); + $logs = $this->getLogs(); + + $show_sources = $this->getShowImportSources(); + + $rows = array(); + foreach ($logs as $log) { + $icon = $log->getDisplayIcon($viewer); + $color = $log->getDisplayColor($viewer); + $name = $log->getDisplayType($viewer); + $description = $log->getDisplayDescription($viewer); + + $rows[] = array( + $log->getID(), + ($show_sources + ? $viewer->renderHandle($log->getImport()->getPHID()) + : null), + id(new PHUIIconView())->setIcon($icon, $color), + $name, + phutil_escape_html_newlines($description), + phabricator_datetime($log->getDateCreated(), $viewer), + ); + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + pht('ID'), + pht('Source'), + null, + pht('Type'), + pht('Message'), + pht('Date'), + )) + ->setColumnVisibility( + array( + true, + $show_sources, + )) + ->setColumnClasses( + array( + 'top', + 'top', + 'top', + 'top pri', + 'top wide', + 'top', + )); + + return $table; + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarImportDeleteTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarImportDeleteTransaction.php new file mode 100644 index 0000000000..83bf78169f --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarImportDeleteTransaction.php @@ -0,0 +1,30 @@ +setViewer($this->getActor()) + ->withImportSourcePHIDs(array($object->getPHID())) + ->execute(); + + $engine = new PhabricatorDestructionEngine(); + foreach ($events as $event) { + $engine->destroyObject($event); + } + } + + public function getTitle() { + return pht( + '%s deleted imported events from this source.', + $this->renderAuthor()); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarImportDisableTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarImportDisableTransaction.php new file mode 100644 index 0000000000..9cc23ab33f --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarImportDisableTransaction.php @@ -0,0 +1,28 @@ +getIsDisabled(); + } + + public function applyInternalEffects($object, $value) { + $object->setIsDisabled((int)$value); + } + + public function getTitle() { + if ($this->getNewValue()) { + return pht( + '%s disabled this import.', + $this->renderAuthor()); + } else { + return pht( + '%s enabled this import.', + $this->renderAuthor()); + } + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php new file mode 100644 index 0000000000..26a968d13d --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php @@ -0,0 +1,80 @@ +getParameter(self::PARAMKEY_FILE); + } + + public function applyInternalEffects($object, $value) { + $object->setParameter(self::PARAMKEY_FILE, $value); + + $viewer = $this->getActor(); + $file = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs(array($value)) + ->executeOne(); + if ($file) { + $object->setParameter(self::PARAMKEY_NAME, $file->getName()); + } + } + + public function getTitle() { + return pht( + '%s imported an ICS file.', + $this->renderAuthor()); + } + + public function validateTransactions($object, array $xactions) { + $viewer = $this->getActor(); + $errors = array(); + + $ics_type = PhabricatorCalendarICSFileImportEngine::ENGINETYPE; + $import_type = $object->getEngine()->getImportEngineType(); + if ($import_type != $ics_type) { + if (!$xactions) { + return $errors; + } + + $errors[] = $this->newInvalidError( + pht( + 'You can not attach an ICS file to an import type other than '. + 'an ICS import (type is "%s").', + $import_type)); + + return $errors; + } + + $new_value = $object->getParameter(self::PARAMKEY_FILE); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + if (!strlen($new_value)) { + continue; + } + + $file = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs(array($new_value)) + ->executeOne(); + if (!$file) { + $errors[] = $this->newInvalidError( + pht( + 'File PHID "%s" is not valid or not visible.', + $new_value), + $xaction); + } + } + + if (!$new_value) { + $errors[] = $this->newRequiredError( + pht('You must select an ".ics" file to import.')); + } + + return $errors; + } +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarImportICSURITransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarImportICSURITransaction.php new file mode 100644 index 0000000000..13fdbd232b --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarImportICSURITransaction.php @@ -0,0 +1,73 @@ +getParameter(self::PARAMKEY_URI); + } + + public function applyInternalEffects($object, $value) { + $object->setParameter(self::PARAMKEY_URI, $value); + } + + public function getTitle() { + // NOTE: This transaction intentionally does not disclose the actual + // URI. + return pht( + '%s updated the import URI.', + $this->renderAuthor()); + } + + public function validateTransactions($object, array $xactions) { + $viewer = $this->getActor(); + $errors = array(); + + $ics_type = PhabricatorCalendarICSURIImportEngine::ENGINETYPE; + $import_type = $object->getEngine()->getImportEngineType(); + if ($import_type != $ics_type) { + if (!$xactions) { + return $errors; + } + + $errors[] = $this->newInvalidError( + pht( + 'You can not attach an ICS URI to an import type other than '. + 'an ICS URI import (type is "%s").', + $import_type)); + + return $errors; + } + + $new_value = $object->getParameter(self::PARAMKEY_URI); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + if (!strlen($new_value)) { + continue; + } + + try { + PhabricatorEnv::requireValidRemoteURIForFetch( + $new_value, + array( + 'http', + 'https', + )); + } catch (Exception $ex) { + $errors[] = $this->newInvalidError( + $ex->getMessage(), + $xaction); + } + } + + if (!strlen($new_value)) { + $errors[] = $this->newRequiredError( + pht('You must select an ".ics" URI to import.')); + } + + return $errors; + } +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarImportNameTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarImportNameTransaction.php new file mode 100644 index 0000000000..49705af009 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarImportNameTransaction.php @@ -0,0 +1,39 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if (!strlen($old)) { + return pht( + '%s named this import %s.', + $this->renderAuthor(), + $this->renderNewValue()); + } else if (!strlen($new)) { + return pht( + '%s removed the name of this import (was: %s).', + $this->renderAuthor(), + $this->renderOldValue()); + } else { + return pht( + '%s renamed this import from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarImportTransactionType.php b/src/applications/calendar/xaction/PhabricatorCalendarImportTransactionType.php new file mode 100644 index 0000000000..9659ce7759 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarImportTransactionType.php @@ -0,0 +1,4 @@ +getCelerityResourceMap(); $expect_hash = $map->getHashForName($path); // Test if the URI hash is correct for our current resource map. If it // is not, refuse to cache this resource. This avoids poisoning caches // and CDNs if we're getting a request for a new resource to an old node // shortly after a push. $is_cacheable = ($hash === $expect_hash); $is_locally_cacheable = $this->isLocallyCacheableResourceType($type); if (AphrontRequest::getHTTPHeader('If-Modified-Since') && $is_cacheable) { // Return a "304 Not Modified". We don't care about the value of this // field since we never change what resource is served by a given URI. return $this->makeResponseCacheable(new Aphront304Response()); } $cache = null; $data = null; if ($is_cacheable && $is_locally_cacheable && !$dev_mode) { $cache = PhabricatorCaches::getImmutableCache(); $request_path = $this->getRequest()->getPath(); $cache_key = $this->getCacheKey($request_path); $data = $cache->getKey($cache_key); } if ($data === null) { if ($map->isPackageResource($path)) { $resource_names = $map->getResourceNamesForPackageName($path); if (!$resource_names) { return new Aphront404Response(); } try { $data = array(); foreach ($resource_names as $resource_name) { $data[] = $map->getResourceDataForName($resource_name); } $data = implode("\n\n", $data); } catch (Exception $ex) { return new Aphront404Response(); } } else { try { $data = $map->getResourceDataForName($path); } catch (Exception $ex) { return new Aphront404Response(); } } $xformer = $this->buildResourceTransformer(); if ($xformer) { $data = $xformer->transformResource($path, $data); } if ($cache) { $cache->setKey($cache_key, $data); } } $response = new AphrontFileResponse(); $response->setContent($data); $response->setMimeType($type_map[$type]); // NOTE: This is a piece of magic required to make WOFF fonts work in // Firefox and IE. Possibly we should generalize this more. $cross_origin_types = array( 'woff' => true, 'woff2' => true, 'eot' => true, ); if (isset($cross_origin_types[$type])) { // We could be more tailored here, but it's not currently trivial to // generate a comprehensive list of valid origins (an install may have // arbitrarily many Phame blogs, for example), and we lose nothing by // allowing access from anywhere. $response->addAllowOrigin('*'); } if ($is_cacheable) { $response = $this->makeResponseCacheable($response); } return $response; } public static function getSupportedResourceTypes() { return array( 'css' => 'text/css; charset=utf-8', 'js' => 'text/javascript; charset=utf-8', 'png' => 'image/png', 'svg' => 'image/svg+xml', 'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'swf' => 'application/x-shockwave-flash', 'woff' => 'font/woff', 'woff2' => 'font/woff2', 'eot' => 'font/eot', 'ttf' => 'font/ttf', 'mp3' => 'audio/mpeg', + 'ico' => 'image/x-icon', ); } private function makeResponseCacheable(AphrontResponse $response) { $response->setCacheDurationInSeconds(60 * 60 * 24 * 30); $response->setLastModified(time()); $response->setCanCDN(true); return $response; } /** * Is it appropriate to cache the data for this resource type in the fast * immutable cache? * * Generally, text resources (which are small, and expensive to process) * are cached, while other types of resources (which are large, and cheap * to process) are not. * * @param string Resource type. * @return bool True to enable caching. */ private function isLocallyCacheableResourceType($type) { $types = array( 'js' => true, 'css' => true, ); return isset($types[$type]); } protected function getCacheKey($path) { return 'celerity:'.PhabricatorHash::digestToLength($path, 64); } } diff --git a/src/applications/celerity/resources/CelerityResourcesOnDisk.php b/src/applications/celerity/resources/CelerityResourcesOnDisk.php index 3187c5b9ad..1f9e614da9 100644 --- a/src/applications/celerity/resources/CelerityResourcesOnDisk.php +++ b/src/applications/celerity/resources/CelerityResourcesOnDisk.php @@ -1,75 +1,76 @@ getPathToResources().DIRECTORY_SEPARATOR.$name; } public function getResourceData($name) { return Filesystem::readFile($this->getPathToResource($name)); } public function findBinaryResources() { return $this->findResourcesWithSuffixes($this->getBinaryFileSuffixes()); } public function findTextResources() { return $this->findResourcesWithSuffixes($this->getTextFileSuffixes()); } public function getResourceModifiedTime($name) { return (int)filemtime($this->getPathToResource($name)); } protected function getBinaryFileSuffixes() { return array( 'png', 'jpg', 'gif', 'swf', 'svg', 'woff', 'woff2', 'ttf', 'eot', 'mp3', + 'ico', ); } protected function getTextFileSuffixes() { return array( 'js', 'css', ); } private function findResourcesWithSuffixes(array $suffixes) { $root = $this->getPathToResources(); $finder = id(new FileFinder($root)) ->withType('f') ->withFollowSymlinks(true) ->setGenerateChecksums(true); foreach ($suffixes as $suffix) { $finder->withSuffix($suffix); } $raw_files = $finder->find(); $results = array(); foreach ($raw_files as $path => $hash) { $readable = Filesystem::readablePath($path, $root); $results[$readable] = $hash; } return $results; } } diff --git a/src/applications/conduit/call/ConduitCall.php b/src/applications/conduit/call/ConduitCall.php index 017d96ae8b..6be49daef0 100644 --- a/src/applications/conduit/call/ConduitCall.php +++ b/src/applications/conduit/call/ConduitCall.php @@ -1,155 +1,155 @@ 'value')); * $call->setUser($user); * $result = $call->execute(); * */ final class ConduitCall extends Phobject { private $method; private $handler; private $request; private $user; - public function __construct($method, array $params) { + public function __construct($method, array $params, $strictly_typed = true) { $this->method = $method; $this->handler = $this->buildMethodHandler($method); $param_types = $this->handler->getParamTypes(); foreach ($param_types as $key => $spec) { if (ConduitAPIMethod::getParameterMetadataKey($key) !== null) { throw new ConduitException( pht( 'API Method "%s" defines a disallowed parameter, "%s". This '. 'parameter name is reserved.', $method, $key)); } } $invalid_params = array_diff_key($params, $param_types); if ($invalid_params) { throw new ConduitException( pht( 'API Method "%s" does not define these parameters: %s.', $method, "'".implode("', '", array_keys($invalid_params))."'")); } - $this->request = new ConduitAPIRequest($params); + $this->request = new ConduitAPIRequest($params, $strictly_typed); } public function getAPIRequest() { return $this->request; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } public function getUser() { return $this->user; } public function shouldRequireAuthentication() { return $this->handler->shouldRequireAuthentication(); } public function shouldAllowUnguardedWrites() { return $this->handler->shouldAllowUnguardedWrites(); } public function getErrorDescription($code) { return $this->handler->getErrorDescription($code); } public function execute() { $profiler = PhutilServiceProfiler::getInstance(); $call_id = $profiler->beginServiceCall( array( 'type' => 'conduit', 'method' => $this->method, )); try { $result = $this->executeMethod(); } catch (Exception $ex) { $profiler->endServiceCall($call_id, array()); throw $ex; } $profiler->endServiceCall($call_id, array()); return $result; } private function executeMethod() { $user = $this->getUser(); if (!$user) { $user = new PhabricatorUser(); } $this->request->setUser($user); if (!$this->shouldRequireAuthentication()) { // No auth requirement here. } else { $allow_public = $this->handler->shouldAllowPublic() && PhabricatorEnv::getEnvConfig('policy.allow-public'); if (!$allow_public) { if (!$user->isLoggedIn() && !$user->isOmnipotent()) { // TODO: As per below, this should get centralized and cleaned up. throw new ConduitException('ERR-INVALID-AUTH'); } } // TODO: This would be slightly cleaner by just using a Query, but the // Conduit auth workflow requires the Call and User be built separately. // Just do it this way for the moment. $application = $this->handler->getApplication(); if ($application) { $can_view = PhabricatorPolicyFilter::hasCapability( $user, $application, PhabricatorPolicyCapability::CAN_VIEW); if (!$can_view) { throw new ConduitException( pht( 'You do not have access to the application which provides this '. 'API method.')); } } } return $this->handler->executeMethod($this->request); } protected function buildMethodHandler($method_name) { $method = ConduitAPIMethod::getConduitMethod($method_name); if (!$method) { throw new ConduitMethodDoesNotExistException($method_name); } $application = $method->getApplication(); if ($application && !$application->isInstalled()) { $app_name = $application->getName(); throw new ConduitApplicationNotInstalledException($method, $app_name); } return $method; } public function getMethodImplementation() { return $this->handler; } } diff --git a/src/applications/conduit/controller/PhabricatorConduitAPIController.php b/src/applications/conduit/controller/PhabricatorConduitAPIController.php index b9e8b1b15e..991865b564 100644 --- a/src/applications/conduit/controller/PhabricatorConduitAPIController.php +++ b/src/applications/conduit/controller/PhabricatorConduitAPIController.php @@ -1,707 +1,709 @@ getURIData('method'); $time_start = microtime(true); $api_request = null; $method_implementation = null; $log = new PhabricatorConduitMethodCallLog(); $log->setMethod($method); $metadata = array(); $multimeter = MultimeterControl::getInstance(); if ($multimeter) { $multimeter->setEventContext('api.'.$method); } try { - list($metadata, $params) = $this->decodeConduitParams($request, $method); + list($metadata, $params, $strictly_typed) = $this->decodeConduitParams( + $request, + $method); - $call = new ConduitCall($method, $params); + $call = new ConduitCall($method, $params, $strictly_typed); $method_implementation = $call->getMethodImplementation(); $result = null; // TODO: The relationship between ConduitAPIRequest and ConduitCall is a // little odd here and could probably be improved. Specifically, the // APIRequest is a sub-object of the Call, which does not parallel the // role of AphrontRequest (which is an indepenent object). // In particular, the setUser() and getUser() existing independently on // the Call and APIRequest is very awkward. $api_request = $call->getAPIRequest(); $allow_unguarded_writes = false; $auth_error = null; $conduit_username = '-'; if ($call->shouldRequireAuthentication()) { $auth_error = $this->authenticateUser($api_request, $metadata, $method); // If we've explicitly authenticated the user here and either done // CSRF validation or are using a non-web authentication mechanism. $allow_unguarded_writes = true; if ($auth_error === null) { $conduit_user = $api_request->getUser(); if ($conduit_user && $conduit_user->getPHID()) { $conduit_username = $conduit_user->getUsername(); } $call->setUser($api_request->getUser()); } } $access_log = PhabricatorAccessLog::getLog(); if ($access_log) { $access_log->setData( array( 'u' => $conduit_username, 'm' => $method, )); } if ($call->shouldAllowUnguardedWrites()) { $allow_unguarded_writes = true; } if ($auth_error === null) { if ($allow_unguarded_writes) { $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); } try { $result = $call->execute(); $error_code = null; $error_info = null; } catch (ConduitException $ex) { $result = null; $error_code = $ex->getMessage(); if ($ex->getErrorDescription()) { $error_info = $ex->getErrorDescription(); } else { $error_info = $call->getErrorDescription($error_code); } } if ($allow_unguarded_writes) { unset($unguarded); } } else { list($error_code, $error_info) = $auth_error; } } catch (Exception $ex) { if (!($ex instanceof ConduitMethodNotFoundException)) { phlog($ex); } $result = null; $error_code = ($ex instanceof ConduitException ? 'ERR-CONDUIT-CALL' : 'ERR-CONDUIT-CORE'); $error_info = $ex->getMessage(); } $time_end = microtime(true); $log ->setCallerPHID( isset($conduit_user) ? $conduit_user->getPHID() : null) ->setError((string)$error_code) ->setDuration(1000000 * ($time_end - $time_start)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $log->save(); unset($unguarded); $response = id(new ConduitAPIResponse()) ->setResult($result) ->setErrorCode($error_code) ->setErrorInfo($error_info); switch ($request->getStr('output')) { case 'human': return $this->buildHumanReadableResponse( $method, $api_request, $response->toDictionary(), $method_implementation); case 'json': default: return id(new AphrontJSONResponse()) ->setAddJSONShield(false) ->setContent($response->toDictionary()); } } /** * Authenticate the client making the request to a Phabricator user account. * * @param ConduitAPIRequest Request being executed. * @param dict Request metadata. * @return null|pair Null to indicate successful authentication, or * an error code and error message pair. */ private function authenticateUser( ConduitAPIRequest $api_request, array $metadata, $method) { $request = $this->getRequest(); if ($request->getUser()->getPHID()) { $request->validateCSRF(); return $this->validateAuthenticatedUser( $api_request, $request->getUser()); } $auth_type = idx($metadata, 'auth.type'); if ($auth_type === ConduitClient::AUTH_ASYMMETRIC) { $host = idx($metadata, 'auth.host'); if (!$host) { return array( 'ERR-INVALID-AUTH', pht( 'Request is missing required "%s" parameter.', 'auth.host'), ); } // TODO: Validate that we are the host! $raw_key = idx($metadata, 'auth.key'); $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($raw_key); $ssl_public_key = $public_key->toPKCS8(); // First, verify the signature. try { $protocol_data = $metadata; ConduitClient::verifySignature( $method, $api_request->getAllParameters(), $protocol_data, $ssl_public_key); } catch (Exception $ex) { return array( 'ERR-INVALID-AUTH', pht( 'Signature verification failure. %s', $ex->getMessage()), ); } // If the signature is valid, find the user or device which is // associated with this public key. $stored_key = id(new PhabricatorAuthSSHKeyQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withKeys(array($public_key)) ->withIsActive(true) ->executeOne(); if (!$stored_key) { return array( 'ERR-INVALID-AUTH', pht('No user or device is associated with that public key.'), ); } $object = $stored_key->getObject(); if ($object instanceof PhabricatorUser) { $user = $object; } else { if (!$stored_key->getIsTrusted()) { return array( 'ERR-INVALID-AUTH', pht( 'The key which signed this request is not trusted. Only '. 'trusted keys can be used to sign API calls.'), ); } if (!PhabricatorEnv::isClusterRemoteAddress()) { return array( 'ERR-INVALID-AUTH', pht( 'This request originates from outside of the Phabricator '. 'cluster address range. Requests signed with trusted '. 'device keys must originate from within the cluster.'), ); } $user = PhabricatorUser::getOmnipotentUser(); // Flag this as an intracluster request. $api_request->setIsClusterRequest(true); } return $this->validateAuthenticatedUser( $api_request, $user); } else if ($auth_type === null) { // No specified authentication type, continue with other authentication // methods below. } else { return array( 'ERR-INVALID-AUTH', pht( 'Provided "%s" ("%s") is not recognized.', 'auth.type', $auth_type), ); } $token_string = idx($metadata, 'token'); if (strlen($token_string)) { if (strlen($token_string) != 32) { return array( 'ERR-INVALID-AUTH', pht( 'API token "%s" has the wrong length. API tokens should be '. '32 characters long.', $token_string), ); } $type = head(explode('-', $token_string)); $valid_types = PhabricatorConduitToken::getAllTokenTypes(); $valid_types = array_fuse($valid_types); if (empty($valid_types[$type])) { return array( 'ERR-INVALID-AUTH', pht( 'API token "%s" has the wrong format. API tokens should be '. '32 characters long and begin with one of these prefixes: %s.', $token_string, implode(', ', $valid_types)), ); } $token = id(new PhabricatorConduitTokenQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withTokens(array($token_string)) ->withExpired(false) ->executeOne(); if (!$token) { $token = id(new PhabricatorConduitTokenQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withTokens(array($token_string)) ->withExpired(true) ->executeOne(); if ($token) { return array( 'ERR-INVALID-AUTH', pht( 'API token "%s" was previously valid, but has expired.', $token_string), ); } else { return array( 'ERR-INVALID-AUTH', pht( 'API token "%s" is not valid.', $token_string), ); } } // If this is a "cli-" token, it expires shortly after it is generated // by default. Once it is actually used, we extend its lifetime and make // it permanent. This allows stray tokens to get cleaned up automatically // if they aren't being used. if ($token->getTokenType() == PhabricatorConduitToken::TYPE_COMMANDLINE) { if ($token->getExpires()) { $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $token->setExpires(null); $token->save(); unset($unguarded); } } // If this is a "clr-" token, Phabricator must be configured in cluster // mode and the remote address must be a cluster node. if ($token->getTokenType() == PhabricatorConduitToken::TYPE_CLUSTER) { if (!PhabricatorEnv::isClusterRemoteAddress()) { return array( 'ERR-INVALID-AUTH', pht( 'This request originates from outside of the Phabricator '. 'cluster address range. Requests signed with cluster API '. 'tokens must originate from within the cluster.'), ); } // Flag this as an intracluster request. $api_request->setIsClusterRequest(true); } $user = $token->getObject(); if (!($user instanceof PhabricatorUser)) { return array( 'ERR-INVALID-AUTH', pht('API token is not associated with a valid user.'), ); } return $this->validateAuthenticatedUser( $api_request, $user); } $access_token = idx($metadata, 'access_token'); if ($access_token) { $token = id(new PhabricatorOAuthServerAccessToken()) ->loadOneWhere('token = %s', $access_token); if (!$token) { return array( 'ERR-INVALID-AUTH', pht('Access token does not exist.'), ); } $oauth_server = new PhabricatorOAuthServer(); $authorization = $oauth_server->authorizeToken($token); if (!$authorization) { return array( 'ERR-INVALID-AUTH', pht('Access token is invalid or expired.'), ); } $user = id(new PhabricatorPeopleQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs(array($token->getUserPHID())) ->executeOne(); if (!$user) { return array( 'ERR-INVALID-AUTH', pht('Access token is for invalid user.'), ); } $ok = $this->authorizeOAuthMethodAccess($authorization, $method); if (!$ok) { return array( 'ERR-OAUTH-ACCESS', pht('You do not have authorization to call this method.'), ); } $api_request->setOAuthToken($token); return $this->validateAuthenticatedUser( $api_request, $user); } // For intracluster requests, use a public user if no authentication // information is provided. We could do this safely for any request, // but making the API fully public means there's no way to disable badly // behaved clients. if (PhabricatorEnv::isClusterRemoteAddress()) { if (PhabricatorEnv::getEnvConfig('policy.allow-public')) { $api_request->setIsClusterRequest(true); $user = new PhabricatorUser(); return $this->validateAuthenticatedUser( $api_request, $user); } } // Handle sessionless auth. // TODO: This is super messy. // TODO: Remove this in favor of token-based auth. if (isset($metadata['authUser'])) { $user = id(new PhabricatorUser())->loadOneWhere( 'userName = %s', $metadata['authUser']); if (!$user) { return array( 'ERR-INVALID-AUTH', pht('Authentication is invalid.'), ); } $token = idx($metadata, 'authToken'); $signature = idx($metadata, 'authSignature'); $certificate = $user->getConduitCertificate(); $hash = sha1($token.$certificate); if (!phutil_hashes_are_identical($hash, $signature)) { return array( 'ERR-INVALID-AUTH', pht('Authentication is invalid.'), ); } return $this->validateAuthenticatedUser( $api_request, $user); } // Handle session-based auth. // TODO: Remove this in favor of token-based auth. $session_key = idx($metadata, 'sessionKey'); if (!$session_key) { return array( 'ERR-INVALID-SESSION', pht('Session key is not present.'), ); } $user = id(new PhabricatorAuthSessionEngine()) ->loadUserForSession(PhabricatorAuthSession::TYPE_CONDUIT, $session_key); if (!$user) { return array( 'ERR-INVALID-SESSION', pht('Session key is invalid.'), ); } return $this->validateAuthenticatedUser( $api_request, $user); } private function validateAuthenticatedUser( ConduitAPIRequest $request, PhabricatorUser $user) { if (!$user->canEstablishAPISessions()) { return array( 'ERR-INVALID-AUTH', pht('User account is not permitted to use the API.'), ); } $request->setUser($user); id(new PhabricatorAuthSessionEngine()) ->willServeRequestForUser($user); return null; } private function buildHumanReadableResponse( $method, ConduitAPIRequest $request = null, $result = null, ConduitAPIMethod $method_implementation = null) { $param_rows = array(); $param_rows[] = array('Method', $this->renderAPIValue($method)); if ($request) { foreach ($request->getAllParameters() as $key => $value) { $param_rows[] = array( $key, $this->renderAPIValue($value), ); } } $param_table = new AphrontTableView($param_rows); $param_table->setColumnClasses( array( 'header', 'wide', )); $result_rows = array(); foreach ($result as $key => $value) { $result_rows[] = array( $key, $this->renderAPIValue($value), ); } $result_table = new AphrontTableView($result_rows); $result_table->setColumnClasses( array( 'header', 'wide', )); $param_panel = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Method Parameters')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setTable($param_table); $result_panel = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Method Result')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setTable($result_table); $method_uri = $this->getApplicationURI('method/'.$method.'/'); $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb($method, $method_uri) ->addTextCrumb(pht('Call')) ->setBorder(true); $example_panel = null; if ($request && $method_implementation) { $params = $request->getAllParameters(); $example_panel = $this->renderExampleBox( $method_implementation, $params); } $title = pht('Method Call Result'); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setHeaderIcon('fa-exchange'); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setFooter(array( $param_panel, $result_panel, $example_panel, )); $title = pht('Method Call Result'); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild($view); } private function renderAPIValue($value) { $json = new PhutilJSON(); if (is_array($value)) { $value = $json->encodeFormatted($value); } $value = phutil_tag( 'pre', array('style' => 'white-space: pre-wrap;'), $value); return $value; } private function decodeConduitParams( AphrontRequest $request, $method) { // Look for parameters from the Conduit API Console, which are encoded // as HTTP POST parameters in an array, e.g.: // // params[name]=value¶ms[name2]=value2 // // The fields are individually JSON encoded, since we require users to // enter JSON so that we avoid type ambiguity. $params = $request->getArr('params', null); if ($params !== null) { foreach ($params as $key => $value) { if ($value == '') { // Interpret empty string null (e.g., the user didn't type anything // into the box). $value = 'null'; } $decoded_value = json_decode($value, true); if ($decoded_value === null && strtolower($value) != 'null') { // When json_decode() fails, it returns null. This almost certainly // indicates that a user was using the web UI and didn't put quotes // around a string value. We can either do what we think they meant // (treat it as a string) or fail. For now, err on the side of // caution and fail. In the future, if we make the Conduit API // actually do type checking, it might be reasonable to treat it as // a string if the parameter type is string. throw new Exception( pht( "The value for parameter '%s' is not valid JSON. All ". "parameters must be encoded as JSON values, including strings ". "(which means you need to surround them in double quotes). ". "Check your syntax. Value was: %s.", $key, $value)); } $params[$key] = $decoded_value; } $metadata = idx($params, '__conduit__', array()); unset($params['__conduit__']); - return array($metadata, $params); + return array($metadata, $params, true); } // Otherwise, look for a single parameter called 'params' which has the // entire param dictionary JSON encoded. $params_json = $request->getStr('params'); if (strlen($params_json)) { $params = null; try { $params = phutil_json_decode($params_json); } catch (PhutilJSONParserException $ex) { throw new PhutilProxyException( pht( "Invalid parameter information was passed to method '%s'.", $method), $ex); } $metadata = idx($params, '__conduit__', array()); unset($params['__conduit__']); - return array($metadata, $params); + return array($metadata, $params, true); } // If we do not have `params`, assume this is a simple HTTP request with // HTTP key-value pairs. $params = array(); $metadata = array(); foreach ($request->getPassthroughRequestData() as $key => $value) { $meta_key = ConduitAPIMethod::getParameterMetadataKey($key); if ($meta_key !== null) { $metadata[$meta_key] = $value; } else { $params[$key] = $value; } } - return array($metadata, $params); + return array($metadata, $params, false); } private function authorizeOAuthMethodAccess( PhabricatorOAuthClientAuthorization $authorization, $method_name) { $method = ConduitAPIMethod::getConduitMethod($method_name); if (!$method) { return false; } $required_scope = $method->getRequiredScope(); switch ($required_scope) { case ConduitAPIMethod::SCOPE_ALWAYS: return true; case ConduitAPIMethod::SCOPE_NEVER: return false; } $authorization_scope = $authorization->getScope(); if (!empty($authorization_scope[$required_scope])) { return true; } return false; } } diff --git a/src/applications/conduit/parametertype/ConduitBoolParameterType.php b/src/applications/conduit/parametertype/ConduitBoolParameterType.php index fe1564350f..7ad9dd13e5 100644 --- a/src/applications/conduit/parametertype/ConduitBoolParameterType.php +++ b/src/applications/conduit/parametertype/ConduitBoolParameterType.php @@ -1,36 +1,28 @@ raiseValidationException( - $request, - $key, - pht('Expected boolean (true or false), got something else.')); - } - - return $value; + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); + return $this->parseBoolValue($request, $key, $value, $strict); } protected function getParameterTypeName() { return 'bool'; } protected function getParameterFormatDescriptions() { return array( pht('A boolean.'), ); } protected function getParameterExamples() { return array( 'true', 'false', ); } } diff --git a/src/applications/conduit/parametertype/ConduitColumnsParameterType.php b/src/applications/conduit/parametertype/ConduitColumnsParameterType.php index c6669fae06..1892747892 100644 --- a/src/applications/conduit/parametertype/ConduitColumnsParameterType.php +++ b/src/applications/conduit/parametertype/ConduitColumnsParameterType.php @@ -1,38 +1,38 @@ raiseValidationException( - $request, - $key, - pht('Expected epoch timestamp as integer, got something else.')); - } + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); + $value = $this->parseIntValue($request, $key, $value, $strict); if ($value <= 0) { $this->raiseValidationException( $request, $key, pht('Epoch timestamp must be larger than 0, got %d.', $value)); } return $value; } protected function getParameterTypeName() { return 'epoch'; } protected function getParameterFormatDescriptions() { return array( pht('Epoch timestamp, as an integer.'), ); } protected function getParameterExamples() { return array( '1450019509', ); } } diff --git a/src/applications/conduit/parametertype/ConduitIntListParameterType.php b/src/applications/conduit/parametertype/ConduitIntListParameterType.php index 07c87dcd8a..27e0ff9843 100644 --- a/src/applications/conduit/parametertype/ConduitIntListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitIntListParameterType.php @@ -1,40 +1,36 @@ $item) { - if (!is_int($item)) { - $this->raiseValidationException( - $request, - $key, - pht( - 'Expected a list of integers, but item with index "%s" is '. - 'not an integer.', - $idx)); - } + $list[$idx] = $this->parseIntValue( + $request, + $key.'['.$idx.']', + $item, + $strict); } return $list; } protected function getParameterTypeName() { return 'list'; } protected function getParameterFormatDescriptions() { return array( pht('List of integers.'), ); } protected function getParameterExamples() { return array( '[123, 0, -456]', ); } } diff --git a/src/applications/conduit/parametertype/ConduitIntParameterType.php b/src/applications/conduit/parametertype/ConduitIntParameterType.php index 54f66fdf6c..e0d91e5d93 100644 --- a/src/applications/conduit/parametertype/ConduitIntParameterType.php +++ b/src/applications/conduit/parametertype/ConduitIntParameterType.php @@ -1,37 +1,29 @@ raiseValidationException( - $request, - $key, - pht('Expected integer, got something else.')); - } - - return $value; + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); + return $this->parseIntValue($request, $key, $value, $strict); } protected function getParameterTypeName() { return 'int'; } protected function getParameterFormatDescriptions() { return array( pht('An integer.'), ); } protected function getParameterExamples() { return array( '123', '0', '-345', ); } } diff --git a/src/applications/conduit/parametertype/ConduitListParameterType.php b/src/applications/conduit/parametertype/ConduitListParameterType.php index 6ec3898ac2..aebadeb175 100644 --- a/src/applications/conduit/parametertype/ConduitListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitListParameterType.php @@ -1,71 +1,72 @@ allowEmptyList = $allow_empty_list; return $this; } public function getAllowEmptyList() { return $this->allowEmptyList; } - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); if (!is_array($value)) { $this->raiseValidationException( $request, $key, pht('Expected a list, but value is not a list.')); } $actual_keys = array_keys($value); if ($value) { $natural_keys = range(0, count($value) - 1); } else { $natural_keys = array(); } if ($actual_keys !== $natural_keys) { $this->raiseValidationException( $request, $key, pht('Expected a list, but value is an object.')); } if (!$value && !$this->getAllowEmptyList()) { $this->raiseValidationException( $request, $key, pht('Expected a nonempty list, but value is an empty list.')); } return $value; } - protected function validateStringList(array $request, $key, array $list) { + protected function parseStringList( + array $request, + $key, + array $list, + $strict) { + foreach ($list as $idx => $item) { - if (!is_string($item)) { - $this->raiseValidationException( - $request, - $key, - pht( - 'Expected a list of strings, but item with index "%s" is '. - 'not a string.', - $idx)); - } + $list[$idx] = $this->parseStringValue( + $request, + $key.'['.$idx.']', + $item, + $strict); } return $list; } protected function getParameterDefault() { return array(); } } diff --git a/src/applications/conduit/parametertype/ConduitPHIDListParameterType.php b/src/applications/conduit/parametertype/ConduitPHIDListParameterType.php index 60199dbe45..bbe89b6d43 100644 --- a/src/applications/conduit/parametertype/ConduitPHIDListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitPHIDListParameterType.php @@ -1,27 +1,27 @@ validateStringList($request, $key, $list); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); + return $this->parseStringList($request, $key, $list, $strict); } protected function getParameterTypeName() { return 'list'; } protected function getParameterFormatDescriptions() { return array( pht('List of PHIDs.'), ); } protected function getParameterExamples() { return array( '["PHID-WXYZ-1111", "PHID-WXYZ-2222"]', ); } } diff --git a/src/applications/conduit/parametertype/ConduitPHIDParameterType.php b/src/applications/conduit/parametertype/ConduitPHIDParameterType.php index f182758071..3bb45697dc 100644 --- a/src/applications/conduit/parametertype/ConduitPHIDParameterType.php +++ b/src/applications/conduit/parametertype/ConduitPHIDParameterType.php @@ -1,35 +1,35 @@ raiseValidationException( $request, $key, pht('Expected PHID, got something else.')); } return $value; } protected function getParameterTypeName() { return 'phid'; } protected function getParameterFormatDescriptions() { return array( pht('A PHID.'), ); } protected function getParameterExamples() { return array( '"PHID-WXYZ-1111222233334444"', ); } } diff --git a/src/applications/conduit/parametertype/ConduitParameterType.php b/src/applications/conduit/parametertype/ConduitParameterType.php index 011401433e..4eca31d96c 100644 --- a/src/applications/conduit/parametertype/ConduitParameterType.php +++ b/src/applications/conduit/parametertype/ConduitParameterType.php @@ -1,108 +1,155 @@ viewer = $viewer; return $this; } final public function getViewer() { if (!$this->viewer) { throw new PhutilInvalidStateException('setViewer'); } return $this->viewer; } final public function getExists(array $request, $key) { return $this->getParameterExists($request, $key); } - final public function getValue(array $request, $key) { + final public function getValue(array $request, $key, $strict = true) { if (!$this->getExists($request, $key)) { return $this->getParameterDefault(); } - return $this->getParameterValue($request, $key); + return $this->getParameterValue($request, $key, $strict); } final public function getKeys($key) { return $this->getParameterKeys($key); } final public function getDefaultValue() { return $this->getParameterDefault(); } final public function getTypeName() { return $this->getParameterTypeName(); } final public function getFormatDescriptions() { return $this->getParameterFormatDescriptions(); } final public function getExamples() { return $this->getParameterExamples(); } protected function raiseValidationException(array $request, $key, $message) { // TODO: Specialize this so we can give users more tailored messages from // Conduit. throw new Exception( pht( 'Error while reading "%s": %s', $key, $message)); } final public static function getAllTypes() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) ->setUniqueMethod('getTypeName') ->setSortMethod('getTypeName') ->execute(); } protected function getParameterExists(array $request, $key) { return array_key_exists($key, $request); } - protected function getParameterValue(array $request, $key) { + protected function getParameterValue(array $request, $key, $strict) { return $request[$key]; } protected function getParameterKeys($key) { return array($key); } + protected function parseStringValue(array $request, $key, $value, $strict) { + if (!is_string($value)) { + $this->raiseValidationException( + $request, + $key, + pht('Expected string, got something else.')); + } + return $value; + } + + protected function parseIntValue(array $request, $key, $value, $strict) { + if (!$strict && is_string($value) && ctype_digit($value)) { + $value = $value + 0; + if (!is_int($value)) { + $this->raiseValidationException( + $request, + $key, + pht('Integer overflow.')); + } + } else if (!is_int($value)) { + $this->raiseValidationException( + $request, + $key, + pht('Expected integer, got something else.')); + } + return $value; + } + + protected function parseBoolValue(array $request, $key, $value, $strict) { + $bool_strings = array( + '0' => false, + '1' => true, + 'false' => false, + 'true' => true, + ); + + if (!$strict && is_string($value) && isset($bool_strings[$value])) { + $value = $bool_strings[$value]; + } else if (!is_bool($value)) { + $this->raiseValidationException( + $request, + $key, + pht('Expected boolean (true or false), got something else.')); + } + return $value; + } + abstract protected function getParameterTypeName(); abstract protected function getParameterFormatDescriptions(); abstract protected function getParameterExamples(); protected function getParameterDefault() { return null; } } diff --git a/src/applications/conduit/parametertype/ConduitPointsParameterType.php b/src/applications/conduit/parametertype/ConduitPointsParameterType.php index 5b330aabd1..9e5be819f2 100644 --- a/src/applications/conduit/parametertype/ConduitPointsParameterType.php +++ b/src/applications/conduit/parametertype/ConduitPointsParameterType.php @@ -1,49 +1,49 @@ raiseValidationException( $request, $key, pht('Expected numeric points value, got something else.')); } if ($value !== null) { $value = (double)$value; if ($value < 0) { $this->raiseValidationException( $request, $key, pht('Point values must be nonnegative.')); } } return $value; } protected function getParameterTypeName() { return 'points'; } protected function getParameterFormatDescriptions() { return array( pht('A nonnegative number, or null.'), ); } protected function getParameterExamples() { return array( 'null', '0', '1', '15', '0.5', ); } } diff --git a/src/applications/conduit/parametertype/ConduitProjectListParameterType.php b/src/applications/conduit/parametertype/ConduitProjectListParameterType.php index c26db7febf..bd504c7eb4 100644 --- a/src/applications/conduit/parametertype/ConduitProjectListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitProjectListParameterType.php @@ -1,34 +1,34 @@ validateStringList($request, $key, $list); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); + $list = $this->parseStringList($request, $key, $list, $strict); return id(new PhabricatorProjectPHIDResolver()) ->setViewer($this->getViewer()) ->resolvePHIDs($list); } protected function getParameterTypeName() { return 'list'; } protected function getParameterFormatDescriptions() { return array( pht('List of project PHIDs.'), pht('List of project tags.'), pht('List with a mixture of PHIDs and tags.'), ); } protected function getParameterExamples() { return array( '["PHID-PROJ-1111"]', '["backend"]', '["PHID-PROJ-2222", "frontend"]', ); } } diff --git a/src/applications/conduit/parametertype/ConduitStringListParameterType.php b/src/applications/conduit/parametertype/ConduitStringListParameterType.php index 664a1ded99..20c9389f81 100644 --- a/src/applications/conduit/parametertype/ConduitStringListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitStringListParameterType.php @@ -1,27 +1,27 @@ validateStringList($request, $key, $list); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); + return $this->parseStringList($request, $key, $list, $strict); } protected function getParameterTypeName() { return 'list'; } protected function getParameterFormatDescriptions() { return array( pht('List of strings.'), ); } protected function getParameterExamples() { return array( '["mango", "nectarine"]', ); } } diff --git a/src/applications/conduit/parametertype/ConduitStringParameterType.php b/src/applications/conduit/parametertype/ConduitStringParameterType.php index b93490fc73..f10f3731e2 100644 --- a/src/applications/conduit/parametertype/ConduitStringParameterType.php +++ b/src/applications/conduit/parametertype/ConduitStringParameterType.php @@ -1,35 +1,27 @@ raiseValidationException( - $request, - $key, - pht('Expected string, got something else.')); - } - - return $value; + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); + return $this->parseStringValue($request, $key, $value, $strict); } protected function getParameterTypeName() { return 'string'; } protected function getParameterFormatDescriptions() { return array( pht('A string.'), ); } protected function getParameterExamples() { return array( '"papaya"', ); } } diff --git a/src/applications/conduit/parametertype/ConduitUserListParameterType.php b/src/applications/conduit/parametertype/ConduitUserListParameterType.php index ad6555146d..85a9095ac5 100644 --- a/src/applications/conduit/parametertype/ConduitUserListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitUserListParameterType.php @@ -1,34 +1,34 @@ validateStringList($request, $key, $list); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); + $list = $this->parseStringList($request, $key, $list, $strict); return id(new PhabricatorUserPHIDResolver()) ->setViewer($this->getViewer()) ->resolvePHIDs($list); } protected function getParameterTypeName() { return 'list'; } protected function getParameterFormatDescriptions() { return array( pht('List of user PHIDs.'), pht('List of usernames.'), pht('List with a mixture of PHIDs and usernames.'), ); } protected function getParameterExamples() { return array( '["PHID-USER-1111"]', '["alincoln"]', '["PHID-USER-2222", "alincoln"]', ); } } diff --git a/src/applications/conduit/parametertype/ConduitUserParameterType.php b/src/applications/conduit/parametertype/ConduitUserParameterType.php index 3590d1a405..ede7f1f466 100644 --- a/src/applications/conduit/parametertype/ConduitUserParameterType.php +++ b/src/applications/conduit/parametertype/ConduitUserParameterType.php @@ -1,47 +1,47 @@ raiseValidationException( $request, $key, pht('Expected PHID or null, got something else.')); } $user_phids = id(new PhabricatorUserPHIDResolver()) ->setViewer($this->getViewer()) ->resolvePHIDs(array($value)); return nonempty(head($user_phids), null); } protected function getParameterTypeName() { return 'phid|string|null'; } protected function getParameterFormatDescriptions() { return array( pht('User PHID.'), pht('Username.'), pht('Literal null.'), ); } protected function getParameterExamples() { return array( '"PHID-USER-1111"', '"alincoln"', 'null', ); } } diff --git a/src/applications/conduit/protocol/ConduitAPIRequest.php b/src/applications/conduit/protocol/ConduitAPIRequest.php index 47cc31fba0..3a2818a47a 100644 --- a/src/applications/conduit/protocol/ConduitAPIRequest.php +++ b/src/applications/conduit/protocol/ConduitAPIRequest.php @@ -1,76 +1,82 @@ params = $params; + $this->isStrictlyTyped = $strictly_typed; } public function getValue($key, $default = null) { return coalesce(idx($this->params, $key), $default); } public function getValueExists($key) { return array_key_exists($key, $this->params); } public function getAllParameters() { return $this->params; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } /** * Retrieve the authentic identity of the user making the request. If a * method requires authentication (the default) the user object will always * be available. If a method does not require authentication (i.e., overrides * shouldRequireAuthentication() to return false) the user object will NEVER * be available. * * @return PhabricatorUser Authentic user, available ONLY if the method * requires authentication. */ public function getUser() { if (!$this->user) { throw new Exception( pht( 'You can not access the user inside the implementation of a Conduit '. 'method which does not require authentication (as per %s).', 'shouldRequireAuthentication()')); } return $this->user; } public function setOAuthToken( PhabricatorOAuthServerAccessToken $oauth_token) { $this->oauthToken = $oauth_token; return $this; } public function getOAuthToken() { return $this->oauthToken; } public function setIsClusterRequest($is_cluster_request) { $this->isClusterRequest = $is_cluster_request; return $this; } public function getIsClusterRequest() { return $this->isClusterRequest; } + public function getIsStrictlyTyped() { + return $this->isStrictlyTyped; + } + public function newContentSource() { return PhabricatorContentSource::newForSource( PhabricatorConduitContentSource::SOURCECONST); } } diff --git a/src/applications/conpherence/ConpherenceTransactionRenderer.php b/src/applications/conpherence/ConpherenceTransactionRenderer.php index 341d287e8b..187247e063 100644 --- a/src/applications/conpherence/ConpherenceTransactionRenderer.php +++ b/src/applications/conpherence/ConpherenceTransactionRenderer.php @@ -1,197 +1,195 @@ getTransactions(); $oldest_transaction_id = 0; $newest_transaction_id = 0; $too_many = ConpherenceThreadQuery::TRANSACTION_LIMIT + 1; if (count($transactions) == $too_many) { if ($marker_type == 'olderandnewer') { $last_transaction = end($transactions); $first_transaction = reset($transactions); unset($transactions[$last_transaction->getID()]); unset($transactions[$first_transaction->getID()]); $oldest_transaction_id = $last_transaction->getID(); $newest_transaction_id = $first_transaction->getID(); } else if ($marker_type == 'newer') { $first_transaction = reset($transactions); unset($transactions[$first_transaction->getID()]); $newest_transaction_id = $first_transaction->getID(); } else if ($marker_type == 'older') { $last_transaction = end($transactions); unset($transactions[$last_transaction->getID()]); $oldest_transaction = end($transactions); $oldest_transaction_id = $oldest_transaction->getID(); } // we need **at least** the newer marker in this mode even if // we didn't get a full set of transactions } else if ($marker_type == 'olderandnewer') { $first_transaction = reset($transactions); unset($transactions[$first_transaction->getID()]); $newest_transaction_id = $first_transaction->getID(); } $transactions = array_reverse($transactions); $handles = $conpherence->getHandles(); $rendered_transactions = array(); $engine = id(new PhabricatorMarkupEngine()) ->setViewer($user) ->setContextObject($conpherence); foreach ($transactions as $key => $transaction) { if ($transaction->shouldHide()) { unset($transactions[$key]); continue; } if ($transaction->getComment()) { $engine->addObject( $transaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } } $engine->process(); // we're going to insert a dummy date marker transaction for breaks // between days. some setup required! $previous_transaction = null; $date_marker_transaction = id(new ConpherenceTransaction()) ->setTransactionType(ConpherenceTransaction::TYPE_DATE_MARKER) ->makeEphemeral(); $date_marker_transaction_view = id(new ConpherenceTransactionView()) ->setUser($user) ->setConpherenceTransaction($date_marker_transaction) ->setConpherenceThread($conpherence) ->setHandles($handles) ->setMarkupEngine($engine); $transaction_view_template = id(new ConpherenceTransactionView()) ->setUser($user) ->setConpherenceThread($conpherence) ->setHandles($handles) - ->setMarkupEngine($engine) - ->setFullDisplay($full_display); + ->setMarkupEngine($engine); foreach ($transactions as $transaction) { $collapsed = false; if ($previous_transaction) { $previous_day = phabricator_format_local_time( $previous_transaction->getDateCreated(), $user, 'Ymd'); $current_day = phabricator_format_local_time( $transaction->getDateCreated(), $user, 'Ymd'); // See if same user / time $previous_author = $previous_transaction->getAuthorPHID(); $current_author = $transaction->getAuthorPHID(); $previous_time = $previous_transaction->getDateCreated(); $current_time = $transaction->getDateCreated(); $previous_type = $previous_transaction->getTransactionType(); $current_type = $transaction->getTransactionType(); if (($previous_author == $current_author) && ($previous_type == $current_type)) { // Group messages within the last x seconds if (($current_time - $previous_time) < 120) { $collapsed = true; } } // date marker transaction time! if ($previous_day != $current_day) { $date_marker_transaction->setDateCreated( $transaction->getDateCreated()); $date_marker_transaction->setID($previous_transaction->getID()); $rendered_transactions[] = $date_marker_transaction_view->render(); } } $transaction_view = id(clone $transaction_view_template) ->setConpherenceTransaction($transaction); if ($collapsed) { $transaction_view->addClass('conpherence-transaction-collapsed'); } $rendered_transactions[] = $transaction_view->render(); $previous_transaction = $transaction; } $latest_transaction_id = $transaction->getID(); return array( 'transactions' => $rendered_transactions, 'latest_transaction' => $transaction, 'latest_transaction_id' => $latest_transaction_id, 'oldest_transaction_id' => $oldest_transaction_id, 'newest_transaction_id' => $newest_transaction_id, ); } public static function renderMessagePaneContent( array $transactions, $oldest_transaction_id, $newest_transaction_id) { $oldscrollbutton = ''; if ($oldest_transaction_id) { $oldscrollbutton = javelin_tag( 'a', array( 'href' => '#', 'mustcapture' => true, 'sigil' => 'show-older-messages', 'class' => 'conpherence-show-more-messages', 'meta' => array( 'oldest_transaction_id' => $oldest_transaction_id, ), ), pht('Show Older Messages')); $oldscrollbutton = javelin_tag( 'div', array( 'sigil' => 'conpherence-transaction-view', 'meta' => array( 'id' => $oldest_transaction_id - 0.5, ), ), $oldscrollbutton); } $newscrollbutton = ''; if ($newest_transaction_id) { $newscrollbutton = javelin_tag( 'a', array( 'href' => '#', 'mustcapture' => true, 'sigil' => 'show-newer-messages', 'class' => 'conpherence-show-more-messages', 'meta' => array( 'newest_transaction_id' => $newest_transaction_id, ), ), pht('Show Newer Messages')); $newscrollbutton = javelin_tag( 'div', array( 'sigil' => 'conpherence-transaction-view', 'meta' => array( 'id' => $newest_transaction_id + 0.5, ), ), $newscrollbutton); } return hsprintf( '%s%s%s', $oldscrollbutton, $transactions, $newscrollbutton); } } diff --git a/src/applications/conpherence/application/PhabricatorConpherenceApplication.php b/src/applications/conpherence/application/PhabricatorConpherenceApplication.php index 3081919503..5faaf40b9c 100644 --- a/src/applications/conpherence/application/PhabricatorConpherenceApplication.php +++ b/src/applications/conpherence/application/PhabricatorConpherenceApplication.php @@ -1,79 +1,81 @@ [1-9]\d*)' => 'ConpherenceViewController', '/conpherence/' => array( '' => 'ConpherenceListController', 'thread/(?P[1-9]\d*)/' => 'ConpherenceListController', + 'threadsearch/(?P[1-9]\d*)/' + => 'ConpherenceThreadSearchController', '(?P[1-9]\d*)/' => 'ConpherenceViewController', '(?P[1-9]\d*)/(?P[1-9]\d*)/' => 'ConpherenceViewController', 'columnview/' => 'ConpherenceColumnViewController', 'new/' => 'ConpherenceNewRoomController', 'picture/(?P[1-9]\d*)/' => 'ConpherenceRoomPictureController', 'search/(?:query/(?P[^/]+)/)?' => 'ConpherenceRoomListController', 'panel/' => 'ConpherenceNotificationPanelController', 'participant/(?P[1-9]\d*)/' => 'ConpherenceParticipantController', 'update/(?P[1-9]\d*)/' => 'ConpherenceUpdateController', ), ); } public function getQuicksandURIPatternBlacklist() { return array( '/conpherence/.*', '/Z\d+', ); } public function getMailCommandObjects() { // TODO: Conpherence threads don't currently support any commands directly, // so the documentation page we end up generating is empty and funny // looking. Add support here once we support "!add", "!leave", "!topic", // or whatever else. return array(); } } diff --git a/src/applications/conpherence/controller/ConpherenceColumnViewController.php b/src/applications/conpherence/controller/ConpherenceColumnViewController.php index 9705c1f755..de83379aab 100644 --- a/src/applications/conpherence/controller/ConpherenceColumnViewController.php +++ b/src/applications/conpherence/controller/ConpherenceColumnViewController.php @@ -1,109 +1,109 @@ getUser(); $latest_conpherences = array(); $latest_participant = id(new ConpherenceParticipantQuery()) ->withParticipantPHIDs(array($user->getPHID())) - ->setLimit(6) + ->setLimit(8) ->execute(); if ($latest_participant) { $conpherence_phids = mpull($latest_participant, 'getConpherencePHID'); $latest_conpherences = id(new ConpherenceThreadQuery()) ->setViewer($user) ->withPHIDs($conpherence_phids) ->needProfileImage(true) ->needParticipantCache(true) ->execute(); $latest_conpherences = mpull($latest_conpherences, null, 'getPHID'); $latest_conpherences = array_select_keys( $latest_conpherences, $conpherence_phids); } $conpherence = null; $should_404 = false; if ($request->getInt('id')) { $conpherence = id(new ConpherenceThreadQuery()) ->setViewer($user) ->withIDs(array($request->getInt('id'))) ->needProfileImage(true) ->needTransactions(true) ->setTransactionLimit(ConpherenceThreadQuery::TRANSACTION_LIMIT) ->executeOne(); $should_404 = true; } else if ($latest_participant) { $participant = head($latest_participant); $conpherence = id(new ConpherenceThreadQuery()) ->setViewer($user) ->withPHIDs(array($participant->getConpherencePHID())) ->needProfileImage(true) ->needTransactions(true) ->setTransactionLimit(ConpherenceThreadQuery::TRANSACTION_LIMIT) ->executeOne(); $should_404 = true; } $durable_column = id(new ConpherenceDurableColumnView()) ->setUser($user) ->setVisible(true); if (!$conpherence) { if ($should_404) { return new Aphront404Response(); } $conpherence_id = null; $conpherence_phid = null; $latest_transaction_id = null; $can_edit = false; } else { $this->setConpherence($conpherence); $participant = $conpherence->getParticipant($user->getPHID()); $transactions = $conpherence->getTransactions(); $latest_transaction = head($transactions); $write_guard = AphrontWriteGuard::beginScopedUnguardedWrites(); $participant->markUpToDate($conpherence, $latest_transaction); unset($write_guard); $draft = PhabricatorDraft::newFromUserAndKey( $user, $conpherence->getPHID()); $durable_column ->setDraft($draft) ->setSelectedConpherence($conpherence) ->setConpherences($latest_conpherences); $conpherence_id = $conpherence->getID(); $conpherence_phid = $conpherence->getPHID(); $latest_transaction_id = $latest_transaction->getID(); $can_edit = PhabricatorPolicyFilter::hasCapability( $user, $conpherence, PhabricatorPolicyCapability::CAN_EDIT); } $dropdown_query = id(new AphlictDropdownDataQuery()) ->setViewer($user); $dropdown_query->execute(); $response = array( 'content' => hsprintf('%s', $durable_column), 'threadID' => $conpherence_id, 'threadPHID' => $conpherence_phid, 'latestTransactionID' => $latest_transaction_id, 'canEdit' => $can_edit, 'aphlictDropdownData' => array( $dropdown_query->getNotificationData(), $dropdown_query->getConpherenceData(), ), ); return id(new AphrontAjaxResponse())->setContent($response); } } diff --git a/src/applications/conpherence/controller/ConpherenceController.php b/src/applications/conpherence/controller/ConpherenceController.php index 389a8ce9b7..e6690a55d1 100644 --- a/src/applications/conpherence/controller/ConpherenceController.php +++ b/src/applications/conpherence/controller/ConpherenceController.php @@ -1,152 +1,225 @@ conpherence = $conpherence; return $this; } public function getConpherence() { return $this->conpherence; } public function buildApplicationMenu() { $nav = new PHUIListView(); $conpherence = $this->conpherence; // Local Links if ($conpherence) { + $nav->addMenuItem( + id(new PHUIListItemView()) + ->setName(pht('Joined Rooms')) + ->setType(PHUIListItemView::TYPE_LINK) + ->setHref($this->getApplicationURI())); + $nav->addMenuItem( id(new PHUIListItemView()) ->setName(pht('Edit Room')) ->setType(PHUIListItemView::TYPE_LINK) ->setHref( $this->getApplicationURI('update/'.$conpherence->getID()).'/') ->setWorkflow(true)); $nav->addMenuItem( id(new PHUIListItemView()) ->setName(pht('Add Participants')) ->setType(PHUIListItemView::TYPE_LINK) ->setHref('#') ->addSigil('conpherence-widget-adder') ->setMetadata(array('widget' => 'widgets-people'))); } // Global Links $nav->newLabel(pht('Conpherence')); $nav->newLink( pht('New Room'), $this->getApplicationURI('new/')); $nav->newLink( pht('Search Rooms'), $this->getApplicationURI('search/')); return $nav; } protected function buildHeaderPaneContent( ConpherenceThread $conpherence, array $policy_objects) { assert_instances_of($policy_objects, 'PhabricatorPolicy'); $viewer = $this->getViewer(); $header = null; if ($conpherence->getID()) { $data = $conpherence->getDisplayData($this->getViewer()); $header = id(new PHUIHeaderView()) ->setHeader($data['title']) ->setSubheader($data['topic']) ->setImage($data['image']); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $conpherence, PhabricatorPolicyCapability::CAN_EDIT); if ($can_edit) { $header->setImageURL( $this->getApplicationURI('picture/'.$conpherence->getID().'/')); } $participating = $conpherence->getParticipantIfExists($viewer->getPHID()); $can_join = PhabricatorPolicyFilter::hasCapability( $viewer, $conpherence, PhabricatorPolicyCapability::CAN_JOIN); $header->addActionItem( id(new PHUIIconCircleView()) ->setHref( $this->getApplicationURI('update/'.$conpherence->getID()).'/') ->setIcon('fa-pencil') ->addClass('hide-on-device') ->setColor('violet') ->setWorkflow(true)); $header->addActionItem( id(new PHUIIconCircleView()) ->setHref( $this->getApplicationURI('update/'.$conpherence->getID()).'/'. '?action='.ConpherenceUpdateActions::NOTIFICATIONS) ->setIcon('fa-gear') ->addClass('hide-on-device') ->setColor('pink') ->setWorkflow(true)); $widget_key = PhabricatorConpherenceWidgetVisibleSetting::SETTINGKEY; $widget_view = (bool)$viewer->getUserSetting($widget_key, false); Javelin::initBehavior( 'toggle-widget', array( 'show' => (int)$widget_view, 'settingsURI' => '/settings/adjust/?key='.$widget_key, )); $header->addActionItem( id(new PHUIIconCircleView()) ->addSigil('conpherence-widget-toggle') ->setIcon('fa-group') ->setHref('#') ->addClass('conpherence-participant-toggle')); + Javelin::initBehavior('conpherence-search'); + + $header->addActionItem( + id(new PHUIIconCircleView()) + ->addSigil('conpherence-search-toggle') + ->setIcon('fa-search') + ->setHref('#') + ->setColor('green') + ->addClass('conpherence-search-toggle')); + if ($can_join && !$participating) { $action = ConpherenceUpdateActions::JOIN_ROOM; $uri = $this->getApplicationURI('update/'.$conpherence->getID().'/'); $button = phutil_tag( 'button', array( 'type' => 'SUBMIT', 'class' => 'button green mlr', ), pht('Join Room')); $hidden = phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'action', 'value' => ConpherenceUpdateActions::JOIN_ROOM, )); $form = phabricator_form( $viewer, array( 'method' => 'POST', 'action' => (string)$uri, ), array( $hidden, $button, )); $header->addActionItem($form); } } return $header; } + public function buildSearchForm() { + $viewer = $this->getViewer(); + $conpherence = $this->conpherence; + $name = $conpherence->getTitle(); + + $bar = javelin_tag( + 'input', + array( + 'type' => 'text', + 'id' => 'conpherence-search-input', + 'name' => 'fulltext', + 'class' => 'conpherence-search-input', + 'sigil' => 'conpherence-search-input', + 'placeholder' => pht('Search %s...', $name), + )); + + $id = $conpherence->getID(); + $form = phabricator_form( + $viewer, + array( + 'method' => 'POST', + 'action' => '/conpherence/threadsearch/'.$id.'/', + 'sigil' => 'conpherence-search-form', + 'class' => 'conpherence-search-form', + 'id' => 'conpherence-search-form', + ), + array( + $bar, + )); + + $form_view = phutil_tag( + 'div', + array( + 'class' => 'conpherence-search-form-view', + ), + $form); + + $results = phutil_tag( + 'div', + array( + 'id' => 'conpherence-search-results', + 'class' => 'conpherence-search-results', + )); + + $view = phutil_tag( + 'div', + array( + 'class' => 'conpherence-search-window', + ), + array( + $form_view, + $results, + )); + + return $view; + } + } diff --git a/src/applications/conpherence/controller/ConpherenceNotificationPanelController.php b/src/applications/conpherence/controller/ConpherenceNotificationPanelController.php index c72490f60f..03f9c926ca 100644 --- a/src/applications/conpherence/controller/ConpherenceNotificationPanelController.php +++ b/src/applications/conpherence/controller/ConpherenceNotificationPanelController.php @@ -1,139 +1,139 @@ getUser(); $conpherences = array(); require_celerity_resource('conpherence-notification-css'); $unread_status = ConpherenceParticipationStatus::BEHIND; $participant_data = id(new ConpherenceParticipantQuery()) ->withParticipantPHIDs(array($user->getPHID())) ->setLimit(5) ->execute(); if ($participant_data) { $conpherences = id(new ConpherenceThreadQuery()) ->setViewer($user) ->withPHIDs(array_keys($participant_data)) ->needProfileImage(true) ->needTransactions(true) - ->setTransactionLimit(3 * 5) + ->setTransactionLimit(50) ->needParticipantCache(true) ->execute(); } if ($conpherences) { // re-order the conpherences based on participation data $conpherences = array_select_keys( $conpherences, array_keys($participant_data)); $view = new AphrontNullView(); foreach ($conpherences as $conpherence) { $p_data = $participant_data[$conpherence->getPHID()]; $d_data = $conpherence->getDisplayData($user); $classes = array( 'phabricator-notification', 'conpherence-notification', ); if ($p_data->getParticipationStatus() == $unread_status) { $classes[] = 'phabricator-notification-unread'; } $uri = $this->getApplicationURI($conpherence->getID().'/'); $title = $d_data['title']; $subtitle = $d_data['subtitle']; $unread_count = $d_data['unread_count']; $epoch = $d_data['epoch']; $image = $d_data['image']; $msg_view = id(new ConpherenceMenuItemView()) ->setUser($user) ->setTitle($title) ->setSubtitle($subtitle) ->setHref($uri) ->setEpoch($epoch) ->setImageURI($image) ->setUnreadCount($unread_count); $view->appendChild(javelin_tag( 'div', array( 'class' => implode(' ', $classes), 'sigil' => 'notification', 'meta' => array( 'href' => $uri, ), ), $msg_view)); } $content = $view->render(); } else { $rooms_uri = phutil_tag( 'a', array( 'href' => '/conpherence/', 'class' => 'no-room-notification', ), pht('You have joined no rooms.')); $content = phutil_tag_div( 'phabricator-notification no-notifications', $rooms_uri); } $content = hsprintf( '
%s%s
'. '%s', phutil_tag( 'a', array( 'href' => '/conpherence/', ), pht('Rooms')), $this->renderPersistentOption(), $content); $unread = id(new ConpherenceParticipantCountQuery()) ->withParticipantPHIDs(array($user->getPHID())) ->withParticipationStatus($unread_status) ->execute(); $unread_count = idx($unread, $user->getPHID(), 0); $json = array( 'content' => $content, 'number' => (int)$unread_count, ); return id(new AphrontAjaxResponse())->setContent($json); } private function renderPersistentOption() { $viewer = $this->getViewer(); $column_key = PhabricatorConpherenceColumnVisibleSetting::SETTINGKEY; $show = (bool)$viewer->getUserSetting($column_key, false); $view = phutil_tag( 'div', array( 'class' => 'persistent-option', ), array( javelin_tag( 'input', array( 'type' => 'checkbox', 'checked' => ($show) ? 'checked' : null, 'value' => !$show, 'sigil' => 'conpherence-persist-column', )), phutil_tag( 'span', array(), pht('Persistent Chat')), )); return $view; } } diff --git a/src/applications/conpherence/controller/ConpherenceThreadSearchController.php b/src/applications/conpherence/controller/ConpherenceThreadSearchController.php new file mode 100644 index 0000000000..155a61c234 --- /dev/null +++ b/src/applications/conpherence/controller/ConpherenceThreadSearchController.php @@ -0,0 +1,41 @@ +getViewer(); + $conpherence_id = $request->getURIData('id'); + $fulltext = $request->getStr('fulltext'); + + $conpherence = id(new ConpherenceThreadQuery()) + ->setViewer($viewer) + ->withIDs(array($conpherence_id)) + ->executeOne(); + + if (!$conpherence) { + return new Aphront404Response(); + } + + $engine = new ConpherenceThreadSearchEngine(); + $engine->setViewer($viewer); + $saved = $engine->buildSavedQueryFromBuiltin('all') + ->setParameter('phids', array($conpherence->getPHID())) + ->setParameter('fulltext', $fulltext); + + $pager = $engine->newPagerForSavedQuery($saved); + $pager->setPageSize(15); + + $query = $engine->buildQueryFromSavedQuery($saved); + + $results = $engine->executeQuery($query, $pager); + $view = $engine->renderResults($results, $saved); + + return id(new AphrontAjaxResponse()) + ->setContent($view->getContent()); + } +} diff --git a/src/applications/conpherence/controller/ConpherenceUpdateController.php b/src/applications/conpherence/controller/ConpherenceUpdateController.php index db21b3d02f..724b802566 100644 --- a/src/applications/conpherence/controller/ConpherenceUpdateController.php +++ b/src/applications/conpherence/controller/ConpherenceUpdateController.php @@ -1,606 +1,592 @@ getUser(); $conpherence_id = $request->getURIData('id'); if (!$conpherence_id) { return new Aphront404Response(); } $need_participants = false; $needed_capabilities = array(PhabricatorPolicyCapability::CAN_VIEW); $action = $request->getStr('action', ConpherenceUpdateActions::METADATA); switch ($action) { case ConpherenceUpdateActions::REMOVE_PERSON: $person_phid = $request->getStr('remove_person'); if ($person_phid != $user->getPHID()) { $needed_capabilities[] = PhabricatorPolicyCapability::CAN_EDIT; } break; case ConpherenceUpdateActions::ADD_PERSON: case ConpherenceUpdateActions::METADATA: $needed_capabilities[] = PhabricatorPolicyCapability::CAN_EDIT; break; case ConpherenceUpdateActions::JOIN_ROOM: $needed_capabilities[] = PhabricatorPolicyCapability::CAN_JOIN; break; case ConpherenceUpdateActions::NOTIFICATIONS: $need_participants = true; break; case ConpherenceUpdateActions::LOAD: break; } $conpherence = id(new ConpherenceThreadQuery()) ->setViewer($user) ->withIDs(array($conpherence_id)) ->needParticipants($need_participants) ->requireCapabilities($needed_capabilities) ->executeOne(); $latest_transaction_id = null; $response_mode = $request->isAjax() ? 'ajax' : 'redirect'; $error_view = null; $e_file = array(); $errors = array(); $delete_draft = false; $xactions = array(); if ($request->isFormPost() || ($action == ConpherenceUpdateActions::LOAD)) { $editor = id(new ConpherenceEditor()) ->setContinueOnNoEffect($request->isContinueRequest()) ->setContentSourceFromRequest($request) ->setActor($user); switch ($action) { case ConpherenceUpdateActions::DRAFT: $draft = PhabricatorDraft::newFromUserAndKey( $user, $conpherence->getPHID()); $draft->setDraft($request->getStr('text')); $draft->replaceOrDelete(); return new AphrontAjaxResponse(); case ConpherenceUpdateActions::JOIN_ROOM: $xactions[] = id(new ConpherenceTransaction()) ->setTransactionType( ConpherenceTransaction::TYPE_PARTICIPANTS) ->setNewValue(array('+' => array($user->getPHID()))); $delete_draft = true; $message = $request->getStr('text'); if ($message) { $message_xactions = $editor->generateTransactionsFromText( $user, $conpherence, $message); $xactions = array_merge($xactions, $message_xactions); } // for now, just redirect back to the conpherence so everything // will work okay...! $response_mode = 'redirect'; break; case ConpherenceUpdateActions::MESSAGE: $message = $request->getStr('text'); if (strlen($message)) { $xactions = $editor->generateTransactionsFromText( $user, $conpherence, $message); $delete_draft = true; } else { $action = ConpherenceUpdateActions::LOAD; $updated = false; $response_mode = 'ajax'; } break; case ConpherenceUpdateActions::ADD_PERSON: $person_phids = $request->getArr('add_person'); if (!empty($person_phids)) { $xactions[] = id(new ConpherenceTransaction()) ->setTransactionType( ConpherenceTransaction::TYPE_PARTICIPANTS) ->setNewValue(array('+' => $person_phids)); } break; case ConpherenceUpdateActions::REMOVE_PERSON: if (!$request->isContinueRequest()) { // do nothing; we'll display a confirmation dialog instead break; } $person_phid = $request->getStr('remove_person'); if ($person_phid) { $xactions[] = id(new ConpherenceTransaction()) ->setTransactionType( ConpherenceTransaction::TYPE_PARTICIPANTS) ->setNewValue(array('-' => array($person_phid))); $response_mode = 'go-home'; } break; case ConpherenceUpdateActions::NOTIFICATIONS: $notifications = $request->getStr('notifications'); $participant = $conpherence->getParticipantIfExists($user->getPHID()); if (!$participant) { return id(new Aphront404Response()); } $participant->setSettings(array('notifications' => $notifications)); $participant->save(); return id(new AphrontRedirectResponse()) ->setURI('/'.$conpherence->getMonogram()); break; case ConpherenceUpdateActions::METADATA: $title = $request->getStr('title'); $topic = $request->getStr('topic'); // all other metadata updates are continue requests if (!$request->isContinueRequest()) { break; } $title = $request->getStr('title'); $topic = $request->getStr('topic'); $xactions[] = id(new ConpherenceTransaction()) ->setTransactionType(ConpherenceTransaction::TYPE_TITLE) ->setNewValue($title); $xactions[] = id(new ConpherenceTransaction()) ->setTransactionType(ConpherenceTransaction::TYPE_TOPIC) ->setNewValue($topic); $xactions[] = id(new ConpherenceTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setNewValue($request->getStr('viewPolicy')); $xactions[] = id(new ConpherenceTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) ->setNewValue($request->getStr('editPolicy')); $xactions[] = id(new ConpherenceTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_JOIN_POLICY) ->setNewValue($request->getStr('joinPolicy')); if (!$request->getExists('force_ajax')) { $response_mode = 'redirect'; } break; case ConpherenceUpdateActions::LOAD: $updated = false; $response_mode = 'ajax'; break; default: throw new Exception(pht('Unknown action: %s', $action)); break; } if ($xactions) { try { $xactions = $editor->applyTransactions($conpherence, $xactions); if ($delete_draft) { $draft = PhabricatorDraft::newFromUserAndKey( $user, $conpherence->getPHID()); $draft->delete(); } } catch (PhabricatorApplicationTransactionNoEffectException $ex) { return id(new PhabricatorApplicationTransactionNoEffectResponse()) ->setCancelURI($this->getApplicationURI($conpherence_id.'/')) ->setException($ex); } // xactions had no effect...! if (empty($xactions)) { $errors[] = pht( 'That was a non-update. Try cancel.'); } } if ($xactions || ($action == ConpherenceUpdateActions::LOAD)) { switch ($response_mode) { case 'ajax': $latest_transaction_id = $request->getInt('latest_transaction_id'); $content = $this->loadAndRenderUpdates( $action, $conpherence_id, $latest_transaction_id); return id(new AphrontAjaxResponse()) ->setContent($content); break; case 'go-home': $content = array( 'href' => $this->getApplicationURI(), ); return id(new AphrontAjaxResponse()) ->setContent($content); break; case 'redirect': default: return id(new AphrontRedirectResponse()) ->setURI('/'.$conpherence->getMonogram()); break; } } } if ($errors) { $error_view = id(new PHUIInfoView()) ->setErrors($errors); } switch ($action) { case ConpherenceUpdateActions::NOTIFICATIONS: $dialog = $this->renderPreferencesDialog($conpherence); break; case ConpherenceUpdateActions::ADD_PERSON: $dialog = $this->renderAddPersonDialog($conpherence); break; case ConpherenceUpdateActions::REMOVE_PERSON: $dialog = $this->renderRemovePersonDialog($conpherence); break; case ConpherenceUpdateActions::METADATA: default: $dialog = $this->renderMetadataDialog($conpherence, $error_view); break; } return $dialog ->setUser($user) ->setWidth(AphrontDialogView::WIDTH_FORM) ->setSubmitURI($this->getApplicationURI('update/'.$conpherence_id.'/')) ->addSubmitButton() ->addCancelButton($this->getApplicationURI($conpherence->getID().'/')); } private function renderPreferencesDialog( ConpherenceThread $conpherence) { $request = $this->getRequest(); $user = $request->getUser(); $participant = $conpherence->getParticipantIfExists($user->getPHID()); if (!$participant) { $can_join = PhabricatorPolicyFilter::hasCapability( $user, $conpherence, PhabricatorPolicyCapability::CAN_JOIN); if ($can_join) { $text = pht( 'Notification settings are available after joining the room.'); } else if ($user->isLoggedIn()) { $text = pht( 'Notification settings not applicable to rooms you can not join.'); } else { $text = pht( 'Notification settings are available after logging in and joining '. 'the room.'); } return id(new AphrontDialogView()) ->setTitle(pht('Room Preferences')) ->appendParagraph($text); } $notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY; $notification_default = $user->getUserSetting($notification_key); $settings = $participant->getSettings(); $notifications = idx( $settings, 'notifications', $notification_default); $form = id(new AphrontFormView()) ->setUser($user) ->setFullWidth(true) ->appendControl( id(new AphrontFormRadioButtonControl()) ->addButton( PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL, PhabricatorConpherenceNotificationsSetting::getSettingLabel( PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL), '') ->addButton( PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY, PhabricatorConpherenceNotificationsSetting::getSettingLabel( PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY), '') ->setName('notifications') ->setValue($notifications)); return id(new AphrontDialogView()) ->setTitle(pht('Room Preferences')) ->addHiddenInput('action', 'notifications') ->addHiddenInput( 'latest_transaction_id', $request->getInt('latest_transaction_id')) ->appendForm($form); } private function renderAddPersonDialog( ConpherenceThread $conpherence) { $request = $this->getRequest(); $user = $request->getUser(); $add_person = $request->getStr('add_person'); $form = id(new AphrontFormView()) ->setUser($user) ->setFullWidth(true) ->appendControl( id(new AphrontFormTokenizerControl()) ->setName('add_person') ->setUser($user) ->setDatasource(new PhabricatorPeopleDatasource())); - require_celerity_resource('conpherence-update-css'); $view = id(new AphrontDialogView()) ->setTitle(pht('Add Participants')) ->addHiddenInput('action', 'add_person') ->addHiddenInput( 'latest_transaction_id', $request->getInt('latest_transaction_id')) ->appendForm($form); - if ($request->getExists('minimal_display')) { - $view->addHiddenInput('minimal_display', true); - } return $view; } private function renderRemovePersonDialog( ConpherenceThread $conpherence) { $request = $this->getRequest(); $viewer = $request->getUser(); $remove_person = $request->getStr('remove_person'); $participants = $conpherence->getParticipants(); $removed_user = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) ->withPHIDs(array($remove_person)) ->executeOne(); if (!$removed_user) { return new Aphront404Response(); } $is_self = ($viewer->getPHID() == $removed_user->getPHID()); $is_last = (count($participants) == 1); $test_conpherence = clone $conpherence; $test_conpherence->attachParticipants(array()); $still_visible = PhabricatorPolicyFilter::hasCapability( $removed_user, $test_conpherence, PhabricatorPolicyCapability::CAN_VIEW); $body = array(); if ($is_self) { $title = pht('Leave Room'); $body[] = pht( 'Are you sure you want to leave this room?'); } else { $title = pht('Banish User'); $body[] = pht( 'Banish %s from the realm?', phutil_tag('strong', array(), $removed_user->getUsername())); } if ($still_visible) { if ($is_self) { $body[] = pht( 'You will be able to rejoin the room later.'); } else { $body[] = pht( 'This user will be able to rejoin the room later.'); } } else { if ($is_self) { if ($is_last) { $body[] = pht( 'You are the last member, so you will never be able to rejoin '. 'the room.'); } else { $body[] = pht( 'You will not be able to rejoin the room on your own, but '. 'someone else can invite you later.'); } } else { $body[] = pht( 'This user will not be able to rejoin the room unless invited '. 'again.'); } } - require_celerity_resource('conpherence-update-css'); - $dialog = id(new AphrontDialogView()) ->setTitle($title) ->addHiddenInput('action', 'remove_person') ->addHiddenInput('remove_person', $remove_person) ->addHiddenInput( 'latest_transaction_id', $request->getInt('latest_transaction_id')) ->addHiddenInput('__continue__', true); foreach ($body as $paragraph) { $dialog->appendParagraph($paragraph); } return $dialog; } private function renderMetadataDialog( ConpherenceThread $conpherence, $error_view) { $request = $this->getRequest(); $user = $request->getUser(); $title = pht('Update Room'); $form = id(new PHUIFormLayoutView()) ->appendChild($error_view) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Title')) ->setName('title') ->setValue($conpherence->getTitle())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Topic')) ->setName('topic') ->setValue($conpherence->getTopic())); $policies = id(new PhabricatorPolicyQuery()) ->setViewer($user) ->setObject($conpherence) ->execute(); $form ->appendChild( id(new AphrontFormPolicyControl()) ->setName('viewPolicy') ->setPolicyObject($conpherence) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicies($policies)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('editPolicy') ->setPolicyObject($conpherence) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicies($policies)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('joinPolicy') ->setPolicyObject($conpherence) ->setCapability(PhabricatorPolicyCapability::CAN_JOIN) ->setPolicies($policies)); - require_celerity_resource('conpherence-update-css'); $view = id(new AphrontDialogView()) ->setTitle($title) ->addHiddenInput('action', 'metadata') ->addHiddenInput( 'latest_transaction_id', $request->getInt('latest_transaction_id')) ->addHiddenInput('__continue__', true) ->appendChild($form); - if ($request->getExists('minimal_display')) { - $view->addHiddenInput('minimal_display', true); - } if ($request->getExists('force_ajax')) { $view->addHiddenInput('force_ajax', true); } return $view; } private function loadAndRenderUpdates( $action, $conpherence_id, $latest_transaction_id) { - $minimal_display = $this->getRequest()->getExists('minimal_display'); $need_transactions = false; $need_participant_cache = true; switch ($action) { case ConpherenceUpdateActions::METADATA: case ConpherenceUpdateActions::LOAD: $need_transactions = true; break; case ConpherenceUpdateActions::MESSAGE: case ConpherenceUpdateActions::ADD_PERSON: $need_transactions = true; break; case ConpherenceUpdateActions::REMOVE_PERSON: case ConpherenceUpdateActions::NOTIFICATIONS: default: break; } $user = $this->getRequest()->getUser(); $conpherence = id(new ConpherenceThreadQuery()) ->setViewer($user) ->setAfterTransactionID($latest_transaction_id) ->needProfileImage(true) ->needParticipantCache($need_participant_cache) ->needParticipants(true) ->needTransactions($need_transactions) ->withIDs(array($conpherence_id)) ->executeOne(); $non_update = false; if ($need_transactions && $conpherence->getTransactions()) { $data = ConpherenceTransactionRenderer::renderTransactions( $user, - $conpherence, - !$minimal_display); + $conpherence); $key = PhabricatorConpherenceColumnMinimizeSetting::SETTINGKEY; $minimized = $user->getUserSetting($key); if (!$minimized) { $participant_obj = $conpherence->getParticipant($user->getPHID()); $participant_obj ->markUpToDate($conpherence, $data['latest_transaction']); } } else if ($need_transactions) { $non_update = true; $data = array(); } else { $data = array(); } $rendered_transactions = idx($data, 'transactions'); $new_latest_transaction_id = idx($data, 'latest_transaction_id'); $update_uri = $this->getApplicationURI('update/'.$conpherence->getID().'/'); $nav_item = null; $header = null; $people_widget = null; - if (!$minimal_display) { - switch ($action) { - case ConpherenceUpdateActions::METADATA: - $policy_objects = id(new PhabricatorPolicyQuery()) - ->setViewer($user) - ->setObject($conpherence) - ->execute(); - $header = $this->buildHeaderPaneContent( - $conpherence, - $policy_objects); - $header = hsprintf('%s', $header); - $nav_item = id(new ConpherenceThreadListView()) - ->setUser($user) - ->setBaseURI($this->getApplicationURI()) - ->renderSingleThread($conpherence, $policy_objects); - $nav_item = hsprintf('%s', $nav_item); - break; - case ConpherenceUpdateActions::ADD_PERSON: - $people_widget = id(new ConpherenceParticipantView()) - ->setUser($user) - ->setConpherence($conpherence) - ->setUpdateURI($update_uri); - $people_widget = hsprintf('%s', $people_widget->render()); - break; - case ConpherenceUpdateActions::REMOVE_PERSON: - case ConpherenceUpdateActions::NOTIFICATIONS: - default: - break; - } + switch ($action) { + case ConpherenceUpdateActions::METADATA: + $policy_objects = id(new PhabricatorPolicyQuery()) + ->setViewer($user) + ->setObject($conpherence) + ->execute(); + $header = $this->buildHeaderPaneContent( + $conpherence, + $policy_objects); + $header = hsprintf('%s', $header); + $nav_item = id(new ConpherenceThreadListView()) + ->setUser($user) + ->setBaseURI($this->getApplicationURI()) + ->renderSingleThread($conpherence, $policy_objects); + $nav_item = hsprintf('%s', $nav_item); + break; + case ConpherenceUpdateActions::ADD_PERSON: + $people_widget = id(new ConpherenceParticipantView()) + ->setUser($user) + ->setConpherence($conpherence) + ->setUpdateURI($update_uri); + $people_widget = hsprintf('%s', $people_widget->render()); + break; + case ConpherenceUpdateActions::REMOVE_PERSON: + case ConpherenceUpdateActions::NOTIFICATIONS: + default: + break; } $data = $conpherence->getDisplayData($user); $dropdown_query = id(new AphlictDropdownDataQuery()) ->setViewer($user); $dropdown_query->execute(); $content = array( 'non_update' => $non_update, 'transactions' => hsprintf('%s', $rendered_transactions), 'conpherence_title' => (string)$data['title'], 'latest_transaction_id' => $new_latest_transaction_id, 'nav_item' => $nav_item, 'conpherence_phid' => $conpherence->getPHID(), 'header' => $header, 'people_widget' => $people_widget, 'aphlictDropdownData' => array( $dropdown_query->getNotificationData(), $dropdown_query->getConpherenceData(), ), ); return $content; } } diff --git a/src/applications/conpherence/controller/ConpherenceViewController.php b/src/applications/conpherence/controller/ConpherenceViewController.php index 029a6115a2..8d93f03b7d 100644 --- a/src/applications/conpherence/controller/ConpherenceViewController.php +++ b/src/applications/conpherence/controller/ConpherenceViewController.php @@ -1,250 +1,252 @@ getUser(); $conpherence_id = $request->getURIData('id'); if (!$conpherence_id) { return new Aphront404Response(); } $query = id(new ConpherenceThreadQuery()) ->setViewer($user) ->withIDs(array($conpherence_id)) ->needProfileImage(true) ->needParticipantCache(true) ->needTransactions(true) ->setTransactionLimit($this->getMainQueryLimit()); $before_transaction_id = $request->getInt('oldest_transaction_id'); $after_transaction_id = $request->getInt('newest_transaction_id'); $old_message_id = $request->getURIData('messageID'); if ($before_transaction_id && ($old_message_id || $after_transaction_id)) { throw new Aphront400Response(); } if ($old_message_id && $after_transaction_id) { throw new Aphront400Response(); } $marker_type = 'older'; if ($before_transaction_id) { $query ->setBeforeTransactionID($before_transaction_id); } if ($old_message_id) { $marker_type = 'olderandnewer'; $query ->setAfterTransactionID($old_message_id - 1); } if ($after_transaction_id) { $marker_type = 'newer'; $query ->setAfterTransactionID($after_transaction_id); } $conpherence = $query->executeOne(); if (!$conpherence) { return new Aphront404Response(); } $this->setConpherence($conpherence); $transactions = $this->getNeededTransactions( $conpherence, $old_message_id); $latest_transaction = head($transactions); $participant = $conpherence->getParticipantIfExists($user->getPHID()); if ($participant) { if (!$participant->isUpToDate($conpherence)) { $write_guard = AphrontWriteGuard::beginScopedUnguardedWrites(); $participant->markUpToDate($conpherence, $latest_transaction); $user->clearCacheData(PhabricatorUserMessageCountCacheType::KEY_COUNT); unset($write_guard); } } $data = ConpherenceTransactionRenderer::renderTransactions( $user, $conpherence, - $full_display = true, $marker_type); $messages = ConpherenceTransactionRenderer::renderMessagePaneContent( $data['transactions'], $data['oldest_transaction_id'], $data['newest_transaction_id']); if ($before_transaction_id || $after_transaction_id) { $header = null; $form = null; $content = array('transactions' => $messages); } else { $policy_objects = id(new PhabricatorPolicyQuery()) ->setViewer($user) ->setObject($conpherence) ->execute(); $header = $this->buildHeaderPaneContent($conpherence, $policy_objects); + $search = $this->buildSearchForm(); $form = $this->renderFormContent(); $content = array( 'header' => $header, + 'search' => $search, 'transactions' => $messages, 'form' => $form, ); } $d_data = $conpherence->getDisplayData($user); $content['title'] = $title = $d_data['title']; if ($request->isAjax()) { $dropdown_query = id(new AphlictDropdownDataQuery()) ->setViewer($user); $dropdown_query->execute(); $content['threadID'] = $conpherence->getID(); $content['threadPHID'] = $conpherence->getPHID(); $content['latestTransactionID'] = $data['latest_transaction_id']; $content['canEdit'] = PhabricatorPolicyFilter::hasCapability( $user, $conpherence, PhabricatorPolicyCapability::CAN_EDIT); $content['aphlictDropdownData'] = array( $dropdown_query->getNotificationData(), $dropdown_query->getConpherenceData(), ); return id(new AphrontAjaxResponse())->setContent($content); } $can_join = PhabricatorPolicyFilter::hasCapability( $user, $conpherence, PhabricatorPolicyCapability::CAN_JOIN); $layout = id(new ConpherenceLayoutView()) ->setUser($user) ->setBaseURI($this->getApplicationURI()) ->setThread($conpherence) ->setHeader($header) + ->setSearch($search) ->setMessages($messages) ->setReplyForm($form) ->setLatestTransactionID($data['latest_transaction_id']) ->setRole('thread'); $participating = $conpherence->getParticipantIfExists($user->getPHID()); if (!$user->isLoggedIn()) { $layout->addClass('conpherence-no-pontificate'); } return $this->newPage() ->setTitle($title) ->setPageObjectPHIDs(array($conpherence->getPHID())) ->appendChild($layout); } private function renderFormContent() { $conpherence = $this->getConpherence(); $user = $this->getRequest()->getUser(); $can_join = PhabricatorPolicyFilter::hasCapability( $user, $conpherence, PhabricatorPolicyCapability::CAN_JOIN); $participating = $conpherence->getParticipantIfExists($user->getPHID()); if (!$can_join && !$participating && $user->isLoggedIn()) { return null; } $draft = PhabricatorDraft::newFromUserAndKey( $user, $conpherence->getPHID()); $update_uri = $this->getApplicationURI('update/'.$conpherence->getID().'/'); if ($user->isLoggedIn()) { $this->initBehavior('conpherence-pontificate'); if ($participating) { $action = ConpherenceUpdateActions::MESSAGE; $status = new PhabricatorNotificationStatusView(); } else { $action = ConpherenceUpdateActions::JOIN_ROOM; $status = pht('Sending a message will also join the room.'); } $form = id(new AphrontFormView()) ->setUser($user) ->setAction($update_uri) ->addSigil('conpherence-pontificate') ->setWorkflow(true) ->addHiddenInput('action', $action) ->appendChild( id(new PhabricatorRemarkupControl()) ->setUser($user) ->setName('text') ->setValue($draft->getDraft())); $status_view = phutil_tag( 'div', array( 'class' => 'conpherence-room-status', 'id' => 'conpherence-room-status', ), $status); $view = phutil_tag_div( 'pontificate-container', array($form, $status_view)); return $view; } else { // user not logged in so give them a login button. $login_href = id(new PhutilURI('/auth/start/')) ->setQueryParam('next', '/'.$conpherence->getMonogram()); return id(new PHUIFormLayoutView()) ->addClass('login-to-participate') ->appendInstructions(pht('Log in to join this room and participate.')) ->appendChild( id(new PHUIButtonView()) ->setTag('a') ->setText(pht('Login to Participate')) ->setHref((string)$login_href)); } } private function getNeededTransactions( ConpherenceThread $conpherence, $message_id) { if ($message_id) { $newer_transactions = $conpherence->getTransactions(); $query = id(new ConpherenceTransactionQuery()) ->setViewer($this->getRequest()->getUser()) ->withObjectPHIDs(array($conpherence->getPHID())) ->setAfterID($message_id) ->needHandles(true) ->setLimit(self::OLDER_FETCH_LIMIT); $older_transactions = $query->execute(); $handles = array(); foreach ($older_transactions as $transaction) { $handles += $transaction->getHandles(); } $conpherence->attachHandles($conpherence->getHandles() + $handles); $transactions = array_merge($newer_transactions, $older_transactions); $conpherence->attachTransactions($transactions); } else { $transactions = $conpherence->getTransactions(); } return $transactions; } private function getMainQueryLimit() { $request = $this->getRequest(); $base_limit = ConpherenceThreadQuery::TRANSACTION_LIMIT; if ($request->getURIData('messageID')) { $base_limit = $base_limit - self::OLDER_FETCH_LIMIT; } return $base_limit; } } diff --git a/src/applications/conpherence/query/ConpherenceThreadQuery.php b/src/applications/conpherence/query/ConpherenceThreadQuery.php index 640a19a612..48dc3323e0 100644 --- a/src/applications/conpherence/query/ConpherenceThreadQuery.php +++ b/src/applications/conpherence/query/ConpherenceThreadQuery.php @@ -1,290 +1,335 @@ needParticipantCache = $participant_cache; return $this; } public function needParticipants($need) { $this->needParticipants = $need; return $this; } public function needProfileImage($need) { $this->needProfileImage = $need; return $this; } public function needTransactions($need_transactions) { $this->needTransactions = $need_transactions; return $this; } public function withIDs(array $ids) { $this->ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withParticipantPHIDs(array $phids) { $this->participantPHIDs = $phids; return $this; } public function setAfterTransactionID($id) { $this->afterTransactionID = $id; return $this; } public function setBeforeTransactionID($id) { $this->beforeTransactionID = $id; return $this; } public function setTransactionLimit($transaction_limit) { $this->transactionLimit = $transaction_limit; return $this; } public function getTransactionLimit() { return $this->transactionLimit; } public function withFulltext($query) { $this->fulltext = $query; return $this; } + public function withTitleNgrams($ngrams) { + return $this->withNgramsConstraint( + id(new ConpherenceThreadTitleNgrams()), + $ngrams); + } + protected function loadPage() { $table = new ConpherenceThread(); $conn_r = $table->establishConnection('r'); $data = queryfx_all( $conn_r, 'SELECT thread.* FROM %T thread %Q %Q %Q %Q %Q', $table->getTableName(), $this->buildJoinClause($conn_r), $this->buildWhereClause($conn_r), $this->buildGroupClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); $conpherences = $table->loadAllFromArray($data); if ($conpherences) { $conpherences = mpull($conpherences, null, 'getPHID'); $this->loadParticipantsAndInitHandles($conpherences); if ($this->needParticipantCache) { $this->loadCoreHandles($conpherences, 'getRecentParticipantPHIDs'); } if ($this->needParticipants) { $this->loadCoreHandles($conpherences, 'getParticipantPHIDs'); } if ($this->needTransactions) { $this->loadTransactionsAndHandles($conpherences); } if ($this->needProfileImage) { $default = null; $file_phids = mpull($conpherences, 'getProfileImagePHID'); $file_phids = array_filter($file_phids); if ($file_phids) { $files = id(new PhabricatorFileQuery()) ->setParentQuery($this) ->setViewer($this->getViewer()) ->withPHIDs($file_phids) ->execute(); $files = mpull($files, null, 'getPHID'); } else { $files = array(); } foreach ($conpherences as $conpherence) { $file = idx($files, $conpherence->getProfileImagePHID()); if (!$file) { if (!$default) { $default = PhabricatorFile::loadBuiltin( $this->getViewer(), 'conpherence.png'); } $file = $default; } $conpherence->attachProfileImageFile($file); } } } return $conpherences; } protected function buildGroupClause(AphrontDatabaseConnection $conn_r) { if ($this->participantPHIDs !== null || strlen($this->fulltext)) { return 'GROUP BY thread.id'; } else { return $this->buildApplicationSearchGroupClause($conn_r); } } - protected function buildJoinClause(AphrontDatabaseConnection $conn_r) { - $joins = array(); + protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { + $joins = parent::buildJoinClauseParts($conn); if ($this->participantPHIDs !== null) { $joins[] = qsprintf( - $conn_r, + $conn, 'JOIN %T p ON p.conpherencePHID = thread.phid', id(new ConpherenceParticipant())->getTableName()); } if (strlen($this->fulltext)) { $joins[] = qsprintf( - $conn_r, + $conn, 'JOIN %T idx ON idx.threadPHID = thread.phid', id(new ConpherenceIndex())->getTableName()); } - $joins[] = $this->buildApplicationSearchJoinClause($conn_r); - return implode(' ', $joins); + // See note in buildWhereClauseParts() about this optimization. + $viewer = $this->getViewer(); + if (!$viewer->isOmnipotent() && $viewer->isLoggedIn()) { + $joins[] = qsprintf( + $conn, + 'LEFT JOIN %T vp ON vp.conpherencePHID = thread.phid + AND vp.participantPHID = %s', + id(new ConpherenceParticipant())->getTableName(), + $viewer->getPHID()); + } + + return $joins; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); + + // Optimize policy filtering of private rooms. If we are not looking for + // particular rooms by ID or PHID, we can just skip over any rooms with + // "View Policy: Room Participants" if the viewer isn't a participant: we + // know they won't be able to see the room. + // This avoids overheating browse/search queries, since it's common for + // a large number of rooms to be private and have this view policy. + $viewer = $this->getViewer(); - $where[] = $this->buildPagingClause($conn_r); + $can_optimize = + !$viewer->isOmnipotent() && + ($this->ids === null) && + ($this->phids === null); + + if ($can_optimize) { + $members_policy = id(new ConpherenceThreadMembersPolicyRule()) + ->getObjectPolicyFullKey(); + + if ($viewer->isLoggedIn()) { + $where[] = qsprintf( + $conn, + 'thread.viewPolicy != %s OR vp.participantPHID = %s', + $members_policy, + $viewer->getPHID()); + } else { + $where[] = qsprintf( + $conn, + 'thread.viewPolicy != %s', + $members_policy); + } + } if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'thread.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'thread.phid IN (%Ls)', $this->phids); } if ($this->participantPHIDs !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'p.participantPHID IN (%Ls)', $this->participantPHIDs); } if (strlen($this->fulltext)) { $where[] = qsprintf( - $conn_r, + $conn, 'MATCH(idx.corpus) AGAINST (%s IN BOOLEAN MODE)', $this->fulltext); } - return $this->formatWhereClause($where); + return $where; } private function loadParticipantsAndInitHandles(array $conpherences) { $participants = id(new ConpherenceParticipant()) ->loadAllWhere('conpherencePHID IN (%Ls)', array_keys($conpherences)); $map = mgroup($participants, 'getConpherencePHID'); foreach ($conpherences as $current_conpherence) { $conpherence_phid = $current_conpherence->getPHID(); $conpherence_participants = idx( $map, $conpherence_phid, array()); $conpherence_participants = mpull( $conpherence_participants, null, 'getParticipantPHID'); $current_conpherence->attachParticipants($conpherence_participants); $current_conpherence->attachHandles(array()); } return $this; } private function loadCoreHandles( array $conpherences, $method) { $handle_phids = array(); foreach ($conpherences as $conpherence) { $handle_phids[$conpherence->getPHID()] = $conpherence->$method(); } $flat_phids = array_mergev($handle_phids); $viewer = $this->getViewer(); $handles = $viewer->loadHandles($flat_phids); $handles = iterator_to_array($handles); foreach ($handle_phids as $conpherence_phid => $phids) { $conpherence = $conpherences[$conpherence_phid]; $conpherence->attachHandles( $conpherence->getHandles() + array_select_keys($handles, $phids)); } return $this; } private function loadTransactionsAndHandles(array $conpherences) { $query = id(new ConpherenceTransactionQuery()) ->setViewer($this->getViewer()) ->withObjectPHIDs(array_keys($conpherences)) ->needHandles(true); // We have to flip these for the underyling query class. The semantics of // paging are tricky business. if ($this->afterTransactionID) { $query->setBeforeID($this->afterTransactionID); } else if ($this->beforeTransactionID) { $query->setAfterID($this->beforeTransactionID); } if ($this->getTransactionLimit()) { // fetch an extra for "show older" scenarios $query->setLimit($this->getTransactionLimit() + 1); } $transactions = $query->execute(); $transactions = mgroup($transactions, 'getObjectPHID'); foreach ($conpherences as $phid => $conpherence) { $current_transactions = idx($transactions, $phid, array()); $handles = array(); foreach ($current_transactions as $transaction) { $handles += $transaction->getHandles(); } $conpherence->attachHandles($conpherence->getHandles() + $handles); $conpherence->attachTransactions($current_transactions); } return $this; } public function getQueryApplicationClass() { return 'PhabricatorConpherenceApplication'; } protected function getPrimaryTableAlias() { return 'thread'; } } diff --git a/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php b/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php index f2c172b0f2..3129028c2e 100644 --- a/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php +++ b/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php @@ -1,426 +1,454 @@ needParticipantCache(true); + ->needParticipantCache(true) + ->needProfileImage(true); } protected function buildCustomSearchFields() { return array( id(new PhabricatorUsersSearchField()) ->setLabel(pht('Participants')) ->setKey('participants') ->setAliases(array('participant')), + id(new PhabricatorSearchDatasourceField()) + ->setLabel(pht('Rooms')) + ->setKey('phids') + ->setDescription(pht('Search by room titles.')) + ->setDatasource(id(new ConpherenceThreadDatasource())), id(new PhabricatorSearchTextField()) - ->setLabel(pht('Contains Words')) + ->setLabel(pht('Room Contains Words')) ->setKey('fulltext'), ); } protected function getDefaultFieldOrder() { return array( 'participants', '...', ); } protected function shouldShowOrderField() { return false; } protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); if ($map['participants']) { $query->withParticipantPHIDs($map['participants']); } if ($map['fulltext']) { $query->withFulltext($map['fulltext']); } - + if ($map['phids']) { + $query->withPHIDs($map['phids']); + } return $query; } protected function getURI($path) { return '/conpherence/search/'.$path; } protected function getBuiltinQueryNames() { $names = array(); $names['all'] = pht('All Rooms'); if ($this->requireViewer()->isLoggedIn()) { $names['participant'] = pht('Joined Rooms'); } return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; case 'participant': return $query->setParameter( 'participants', array($this->requireViewer()->getPHID())); } return parent::buildSavedQueryFromBuiltin($query_key); } protected function getRequiredHandlePHIDsForResultList( array $conpherences, PhabricatorSavedQuery $query) { $recent = mpull($conpherences, 'getRecentParticipantPHIDs'); return array_unique(array_mergev($recent)); } protected function renderResultList( array $conpherences, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($conpherences, 'ConpherenceThread'); $viewer = $this->requireViewer(); $policy_objects = ConpherenceThread::loadViewPolicyObjects( $viewer, $conpherences); $engines = array(); $fulltext = $query->getParameter('fulltext'); if (strlen($fulltext) && $conpherences) { $context = $this->loadContextMessages($conpherences, $fulltext); $author_phids = array(); foreach ($context as $phid => $messages) { $conpherence = $conpherences[$phid]; $engine = id(new PhabricatorMarkupEngine()) ->setViewer($viewer) ->setContextObject($conpherence); foreach ($messages as $group) { foreach ($group as $message) { $xaction = $message['xaction']; if ($xaction) { $author_phids[] = $xaction->getAuthorPHID(); $engine->addObject( $xaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } } } $engine->process(); $engines[$phid] = $engine; } $handles = $viewer->loadHandles($author_phids); $handles = iterator_to_array($handles); } else { $context = array(); } + $content = array(); $list = new PHUIObjectItemListView(); $list->setUser($viewer); foreach ($conpherences as $conpherence_phid => $conpherence) { $created = phabricator_date($conpherence->getDateCreated(), $viewer); $title = $conpherence->getDisplayTitle($viewer); $monogram = $conpherence->getMonogram(); $icon_name = $conpherence->getPolicyIconName($policy_objects); $icon = id(new PHUIIconView()) ->setIcon($icon_name); - $item = id(new PHUIObjectItemView()) - ->setObjectName($conpherence->getMonogram()) - ->setHeader($title) - ->setHref('/'.$conpherence->getMonogram()) - ->setObject($conpherence) - ->addIcon('none', $created) - ->addIcon( - 'none', - pht('Messages: %d', $conpherence->getMessageCount())) - ->addAttribute( - array( - $icon, - ' ', - pht( - 'Last updated %s', - phabricator_datetime($conpherence->getDateModified(), $viewer)), - )); - - $messages = idx($context, $conpherence_phid); - if ($messages) { - foreach ($messages as $group) { - $rows = array(); - foreach ($group as $message) { - $xaction = $message['xaction']; - if (!$xaction) { - continue; - } - $view = id(new ConpherenceTransactionView()) - ->setUser($viewer) - ->setHandles($handles) - ->setMarkupEngine($engines[$conpherence_phid]) - ->setConpherenceThread($conpherence) - ->setConpherenceTransaction($xaction) - ->setFullDisplay(false) - ->addClass('conpherence-fulltext-result'); - - if ($message['match']) { - $view->addClass('conpherence-fulltext-match'); + if (!strlen($fulltext)) { + $item = id(new PHUIObjectItemView()) + ->setObjectName($conpherence->getMonogram()) + ->setHeader($title) + ->setHref('/'.$conpherence->getMonogram()) + ->setObject($conpherence) + ->setImageURI($conpherence->getProfileImageURI()) + ->addIcon('none', $created) + ->addIcon( + 'none', + pht('Messages: %d', $conpherence->getMessageCount())) + ->addAttribute( + array( + $icon, + ' ', + pht( + 'Last updated %s', + phabricator_datetime($conpherence->getDateModified(), $viewer)), + )); + $list->addItem($item); + } else { + $messages = idx($context, $conpherence_phid); + $box = array(); + $list = null; + if ($messages) { + foreach ($messages as $group) { + $rows = array(); + foreach ($group as $message) { + $xaction = $message['xaction']; + if (!$xaction) { + continue; + } + + $view = id(new ConpherenceTransactionView()) + ->setUser($viewer) + ->setHandles($handles) + ->setMarkupEngine($engines[$conpherence_phid]) + ->setConpherenceThread($conpherence) + ->setConpherenceTransaction($xaction) + ->setSearchResult(true) + ->addClass('conpherence-fulltext-result'); + + if ($message['match']) { + $view->addClass('conpherence-fulltext-match'); + } + + $rows[] = $view; } - - $rows[] = $view; + $box[] = id(new PHUIBoxView()) + ->appendChild($rows) + ->addClass('conpherence-fulltext-results'); } - - $box = id(new PHUIBoxView()) - ->appendChild($rows) - ->addClass('conpherence-fulltext-results'); - $item->appendChild($box); } + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setHeaderIcon($icon_name) + ->setHref('/'.$monogram); + + $content[] = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->appendChild($box); } + } - $list->addItem($item); + if ($list) { + $content = $list; + } else { + $content = id(new PHUIBoxView()) + ->addClass('conpherence-search-room-results') + ->appendChild($content); } $result = new PhabricatorApplicationSearchResultView(); - $result->setObjectList($list); - $result->setNoDataString(pht('No threads found.')); + $result->setContent($content); + $result->setNoDataString(pht('No results found.')); return $result; } private function loadContextMessages(array $threads, $fulltext) { $phids = mpull($threads, 'getPHID'); // We want to load a few messages for each thread in the result list, to // show some of the actual content hits to help the user find what they // are looking for. // This method is trying to batch this lookup in most cases, so we do // between one and "a handful" of queries instead of one per thread in // most cases. To do this: // // - Load a big block of results for all of the threads. // - If we didn't get a full block back, we have everything that matches // the query. Sort it out and exit. // - Otherwise, some threads had a ton of hits, so we might not be // getting everything we want (we could be getting back 1,000 hits for // the first thread). Remove any threads which we have enough results // for and try again. // - Repeat until we have everything or every thread has enough results. // // In the worst case, we could end up degrading to one query per thread, // but this is incredibly unlikely on real data. // Size of the result blocks we're going to load. $limit = 1000; // Number of messages we want for each thread. $want = 3; $need = $phids; $hits = array(); while ($need) { $rows = id(new ConpherenceFulltextQuery()) ->withThreadPHIDs($need) ->withFulltext($fulltext) ->setLimit($limit) ->execute(); foreach ($rows as $row) { $hits[$row['threadPHID']][] = $row; } if (count($rows) < $limit) { break; } foreach ($need as $key => $phid) { if (count($hits[$phid]) >= $want) { unset($need[$key]); } } } // Now that we have all the fulltext matches, throw away any extras that we // aren't going to render so we don't need to do lookups on them. foreach ($hits as $phid => $rows) { if (count($rows) > $want) { $hits[$phid] = array_slice($rows, 0, $want); } } // For each fulltext match, we want to render a message before and after // the match to give it some context. We already know the transactions // before each match because the rows have a "previousTransactionPHID", // but we need to do one more query to figure out the transactions after // each match. // Collect the transactions we want to find the next transactions for. $after = array(); foreach ($hits as $phid => $rows) { foreach ($rows as $row) { $after[] = $row['transactionPHID']; } } // Look up the next transactions. if ($after) { $after_rows = id(new ConpherenceFulltextQuery()) ->withPreviousTransactionPHIDs($after) ->execute(); } else { $after_rows = array(); } // Build maps from PHIDs to the previous and next PHIDs. $prev_map = array(); $next_map = array(); foreach ($after_rows as $row) { $next_map[$row['previousTransactionPHID']] = $row['transactionPHID']; } foreach ($hits as $phid => $rows) { foreach ($rows as $row) { $prev = $row['previousTransactionPHID']; if ($prev) { $prev_map[$row['transactionPHID']] = $prev; $next_map[$prev] = $row['transactionPHID']; } } } // Now we're going to collect the actual transaction PHIDs, in order, that // we want to show for each thread. $groups = array(); foreach ($hits as $thread_phid => $rows) { $rows = ipull($rows, null, 'transactionPHID'); $done = array(); foreach ($rows as $phid => $row) { if (isset($done[$phid])) { continue; } $done[$phid] = true; $group = array(); // Walk backward, finding all the previous results. We can just keep // going until we run out of results because we've only loaded things // that we want to show. $prev = $phid; while (true) { if (!isset($prev_map[$prev])) { // No previous transaction, so we're done. break; } $prev = $prev_map[$prev]; if (isset($rows[$prev])) { $match = true; $done[$prev] = true; } else { $match = false; } $group[] = array( 'phid' => $prev, 'match' => $match, ); } if (count($group) > 1) { $group = array_reverse($group); } $group[] = array( 'phid' => $phid, 'match' => true, ); $next = $phid; while (true) { if (!isset($next_map[$next])) { break; } $next = $next_map[$next]; if (isset($rows[$next])) { $match = true; $done[$next] = true; } else { $match = false; } $group[] = array( 'phid' => $next, 'match' => $match, ); } $groups[$thread_phid][] = $group; } } // Load all the actual transactions we need. $xaction_phids = array(); foreach ($groups as $thread_phid => $group) { foreach ($group as $list) { foreach ($list as $item) { $xaction_phids[] = $item['phid']; } } } if ($xaction_phids) { $xactions = id(new ConpherenceTransactionQuery()) ->setViewer($this->requireViewer()) ->withPHIDs($xaction_phids) ->needComments(true) ->execute(); $xactions = mpull($xactions, null, 'getPHID'); } else { $xactions = array(); } foreach ($groups as $thread_phid => $group) { foreach ($group as $key => $list) { foreach ($list as $lkey => $item) { $xaction = idx($xactions, $item['phid']); if ($xaction->shouldHide()) { continue; } $groups[$thread_phid][$key][$lkey]['xaction'] = $xaction; } } } // TODO: Sort the groups chronologically? return $groups; } } diff --git a/src/applications/conpherence/storage/ConpherenceThread.php b/src/applications/conpherence/storage/ConpherenceThread.php index 36930f6151..e912f52591 100644 --- a/src/applications/conpherence/storage/ConpherenceThread.php +++ b/src/applications/conpherence/storage/ConpherenceThread.php @@ -1,449 +1,458 @@ getObjectPolicyFullKey(); return id(new ConpherenceThread()) ->setMessageCount(0) ->setTitle('') ->setTopic('') ->attachParticipants(array()) ->setViewPolicy($default_policy) ->setEditPolicy($default_policy) ->setJoinPolicy($default_policy); } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'recentParticipantPHIDs' => self::SERIALIZATION_JSON, - 'imagePHIDs' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'title' => 'text255?', 'topic' => 'text255', 'messageCount' => 'uint64', 'mailKey' => 'text20', 'joinPolicy' => 'policy', 'profileImagePHID' => 'phid?', ), self::CONFIG_KEY_SCHEMA => array( 'key_phid' => null, 'phid' => array( 'columns' => array('phid'), 'unique' => true, ), ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorConpherenceThreadPHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getMonogram() { return 'Z'.$this->getID(); } public function attachParticipants(array $participants) { assert_instances_of($participants, 'ConpherenceParticipant'); $this->participants = $participants; return $this; } public function getParticipants() { return $this->assertAttached($this->participants); } public function getParticipant($phid) { $participants = $this->getParticipants(); return $participants[$phid]; } public function getParticipantIfExists($phid, $default = null) { $participants = $this->getParticipants(); return idx($participants, $phid, $default); } public function getParticipantPHIDs() { $participants = $this->getParticipants(); return array_keys($participants); } public function attachHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } public function getHandles() { return $this->assertAttached($this->handles); } public function attachTransactions(array $transactions) { assert_instances_of($transactions, 'ConpherenceTransaction'); $this->transactions = $transactions; return $this; } public function getTransactions($assert_attached = true) { return $this->assertAttached($this->transactions); } public function hasAttachedTransactions() { return $this->transactions !== self::ATTACHABLE; } public function getTransactionsFrom($begin = 0, $amount = null) { $length = count($this->transactions); return array_slice( $this->getTransactions(), $length - $begin - $amount, $amount); } public function getProfileImageURI() { return $this->getProfileImageFile()->getBestURI(); } public function attachProfileImageFile(PhabricatorFile $file) { $this->profileImageFile = $file; return $this; } public function getProfileImageFile() { return $this->assertAttached($this->profileImageFile); } /** * Get a thread title which doesn't require handles to be attached. * * This is a less rich title than @{method:getDisplayTitle}, but does not * require handles to be attached. We use it to build thread handles without * risking cycles or recursion while querying. * * @return string Lower quality human-readable title. */ public function getStaticTitle() { $title = $this->getTitle(); if (strlen($title)) { return $title; } return pht('Private Room'); } /** * Get the thread's display title for a user. * * If a thread doesn't have a title set, this will return a string describing * recent participants. * * @param PhabricatorUser Viewer. * @return string Thread title. */ public function getDisplayTitle(PhabricatorUser $viewer) { $title = $this->getTitle(); if (strlen($title)) { return $title; } return $this->getRecentParticipantsString($viewer); } /** * Get recent participants (other than the viewer) as a string. * * For example, this method might return "alincoln, htaft, gwashington...". * * @param PhabricatorUser Viewer. * @return string Description of other participants. */ private function getRecentParticipantsString(PhabricatorUser $viewer) { $handles = $this->getHandles(); $phids = $this->getOtherRecentParticipantPHIDs($viewer); if (count($phids) == 0) { $phids[] = $viewer->getPHID(); $more = false; } else { $limit = 3; $more = (count($phids) > $limit); $phids = array_slice($phids, 0, $limit); } $names = array_select_keys($handles, $phids); $names = mpull($names, 'getName'); $names = implode(', ', $names); if ($more) { $names = $names.'...'; } return $names; } /** * Get PHIDs for recent participants who are not the viewer. * * @param PhabricatorUser Viewer. * @return list Participants who are not the viewer. */ private function getOtherRecentParticipantPHIDs(PhabricatorUser $viewer) { $phids = $this->getRecentParticipantPHIDs(); $phids = array_fuse($phids); unset($phids[$viewer->getPHID()]); return array_values($phids); } public function getDisplayData(PhabricatorUser $viewer) { $handles = $this->getHandles(); if ($this->hasAttachedTransactions()) { $transactions = $this->getTransactions(); } else { $transactions = array(); } if ($transactions) { $subtitle_mode = 'message'; } else { $subtitle_mode = 'recent'; } $lucky_phid = head($this->getOtherRecentParticipantPHIDs($viewer)); if ($lucky_phid) { $lucky_handle = $handles[$lucky_phid]; } else { // This will be just the user talking to themselves. Weirdo. $lucky_handle = reset($handles); } $img_src = $this->getProfileImageURI(); $message_title = null; if ($subtitle_mode == 'message') { $message_transaction = null; $action_transaction = null; foreach ($transactions as $transaction) { if ($message_transaction || $action_transaction) { break; } switch ($transaction->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: $message_transaction = $transaction; break; case ConpherenceTransaction::TYPE_TITLE: case ConpherenceTransaction::TYPE_TOPIC: case ConpherenceTransaction::TYPE_PICTURE: case ConpherenceTransaction::TYPE_PARTICIPANTS: $action_transaction = $transaction; break; default: break; } } if ($message_transaction) { $message_handle = $handles[$message_transaction->getAuthorPHID()]; $message_title = sprintf( '%s: %s', $message_handle->getName(), id(new PhutilUTF8StringTruncator()) ->setMaximumGlyphs(60) ->truncateString( $message_transaction->getComment()->getContent())); } if ($action_transaction) { $message_title = id(clone $action_transaction) ->setRenderingTarget(PhabricatorApplicationTransaction::TARGET_TEXT) ->getTitle(); } } switch ($subtitle_mode) { case 'recent': $subtitle = $this->getRecentParticipantsString($viewer); break; case 'message': if ($message_title) { $subtitle = $message_title; } else { $subtitle = $this->getRecentParticipantsString($viewer); } break; } $user_participation = $this->getParticipantIfExists($viewer->getPHID()); if ($user_participation) { $user_seen_count = $user_participation->getSeenMessageCount(); } else { $user_seen_count = 0; } $unread_count = $this->getMessageCount() - $user_seen_count; $title = $this->getDisplayTitle($viewer); $topic = $this->getTopic(); return array( 'title' => $title, 'topic' => $topic, 'subtitle' => $subtitle, 'unread_count' => $unread_count, 'epoch' => $this->getDateModified(), 'image' => $img_src, ); } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_JOIN, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); case PhabricatorPolicyCapability::CAN_JOIN: return $this->getJoinPolicy(); } return PhabricatorPolicies::POLICY_NOONE; } public function hasAutomaticCapability($capability, PhabricatorUser $user) { // this bad boy isn't even created yet so go nuts $user if (!$this->getID()) { return true; } switch ($capability) { case PhabricatorPolicyCapability::CAN_EDIT: case PhabricatorPolicyCapability::CAN_JOIN: return false; } $participants = $this->getParticipants(); return isset($participants[$user->getPHID()]); } public function describeAutomaticCapability($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return pht('Participants in a room can always view it.'); break; } } public static function loadViewPolicyObjects( PhabricatorUser $viewer, array $conpherences) { assert_instances_of($conpherences, __CLASS__); $policies = array(); foreach ($conpherences as $room) { $policies[$room->getViewPolicy()] = 1; } $policy_objects = array(); if ($policies) { $policy_objects = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) ->withPHIDs(array_keys($policies)) ->execute(); } return $policy_objects; } public function getPolicyIconName(array $policy_objects) { assert_instances_of($policy_objects, 'PhabricatorPolicy'); $icon = $policy_objects[$this->getViewPolicy()]->getIcon(); return $icon; } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new ConpherenceEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new ConpherenceTransaction(); } public function willRenderTimeline( PhabricatorApplicationTransactionView $timeline, AphrontRequest $request) { return $timeline; } +/* -( PhabricatorNgramInterface )------------------------------------------ */ + + + public function newNgrams() { + return array( + id(new ConpherenceThreadTitleNgrams()) + ->setValue($this->getTitle()), + ); + } + /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $participants = id(new ConpherenceParticipant()) ->loadAllWhere('conpherencePHID = %s', $this->getPHID()); foreach ($participants as $participant) { $participant->delete(); } $this->saveTransaction(); } } diff --git a/src/applications/conpherence/storage/ConpherenceThreadTitleNgrams.php b/src/applications/conpherence/storage/ConpherenceThreadTitleNgrams.php new file mode 100644 index 0000000000..7f8ec99d02 --- /dev/null +++ b/src/applications/conpherence/storage/ConpherenceThreadTitleNgrams.php @@ -0,0 +1,17 @@ +getViewer(); + $raw_query = $this->getRawQuery(); + + $rooms = id(new ConpherenceThreadQuery()) + ->setViewer($viewer) + ->withTitleNgrams($raw_query) + ->needParticipants(true) + ->execute(); + + $results = array(); + foreach ($rooms as $room) { + if (strlen($room->getTopic())) { + $topic = $room->getTopic(); + } else { + $topic = phutil_tag('em', array(), pht('No topic set')); + } + + $token = id(new PhabricatorTypeaheadResult()) + ->setName($room->getTitle()) + ->setPHID($room->getPHID()) + ->addAttribute($topic); + + $results[] = $token; + } + + return $results; + } + +} diff --git a/src/applications/conpherence/view/ConpherenceDurableColumnView.php b/src/applications/conpherence/view/ConpherenceDurableColumnView.php index 786cbea174..e3240bc2e4 100644 --- a/src/applications/conpherence/view/ConpherenceDurableColumnView.php +++ b/src/applications/conpherence/view/ConpherenceDurableColumnView.php @@ -1,495 +1,494 @@ conpherences = $conpherences; return $this; } public function getConpherences() { return $this->conpherences; } public function setDraft(PhabricatorDraft $draft) { $this->draft = $draft; return $this; } public function getDraft() { return $this->draft; } public function setSelectedConpherence( ConpherenceThread $conpherence = null) { $this->selectedConpherence = $conpherence; return $this; } public function getSelectedConpherence() { return $this->selectedConpherence; } public function setTransactions(array $transactions) { assert_instances_of($transactions, 'ConpherenceTransaction'); $this->transactions = $transactions; return $this; } public function getTransactions() { return $this->transactions; } public function setVisible($visible) { $this->visible = $visible; return $this; } public function getVisible() { return $this->visible; } public function setMinimize($minimize) { $this->minimize = $minimize; return $this; } public function getMinimize() { return $this->minimize; } public function setInitialLoad($bool) { $this->initialLoad = $bool; return $this; } public function getInitialLoad() { return $this->initialLoad; } public function setPolicyObjects(array $objects) { assert_instances_of($objects, 'PhabricatorPolicy'); $this->policyObjects = $objects; return $this; } public function getPolicyObjects() { return $this->policyObjects; } public function setQuicksandConfig(array $config) { $this->quicksandConfig = $config; return $this; } public function getQuicksandConfig() { return $this->quicksandConfig; } protected function getTagAttributes() { if ($this->getVisible()) { $style = null; } else { $style = 'display: none;'; } $classes = array('conpherence-durable-column'); if ($this->getInitialLoad()) { $classes[] = 'loading'; } return array( 'id' => 'conpherence-durable-column', 'class' => implode(' ', $classes), 'style' => $style, 'sigil' => 'conpherence-durable-column', ); } protected function getTagContent() { $column_key = PhabricatorConpherenceColumnVisibleSetting::SETTINGKEY; $minimize_key = PhabricatorConpherenceColumnMinimizeSetting::SETTINGKEY; Javelin::initBehavior( 'durable-column', array( 'visible' => $this->getVisible(), 'minimize' => $this->getMinimize(), 'visibleURI' => '/settings/adjust/?key='.$column_key, 'minimizeURI' => '/settings/adjust/?key='.$minimize_key, 'quicksandConfig' => $this->getQuicksandConfig(), )); $policy_objects = ConpherenceThread::loadViewPolicyObjects( $this->getUser(), $this->getConpherences()); $this->setPolicyObjects($policy_objects); $classes = array(); $classes[] = 'conpherence-durable-column-header'; $classes[] = 'grouped'; $header = phutil_tag( 'div', array( 'class' => implode(' ', $classes), 'data-sigil' => 'conpherence-minimize-window', ), $this->buildHeader()); $icon_bar = null; if ($this->conpherences) { $icon_bar = $this->buildIconBar(); } $icon_bar = phutil_tag( 'div', array( 'class' => 'conpherence-durable-column-icon-bar', ), $icon_bar); $transactions = $this->buildTransactions(); $content = javelin_tag( 'div', array( 'class' => 'conpherence-durable-column-main', 'sigil' => 'conpherence-durable-column-main', ), phutil_tag( 'div', array( 'id' => 'conpherence-durable-column-content', 'class' => 'conpherence-durable-column-frame', ), javelin_tag( 'div', array( 'class' => 'conpherence-durable-column-transactions', 'sigil' => 'conpherence-durable-column-transactions', ), $transactions))); $input = $this->buildTextInput(); return array( $header, javelin_tag( 'div', array( 'class' => 'conpherence-durable-column-body', 'sigil' => 'conpherence-durable-column-body', ), array( $icon_bar, $content, $input, )), ); } private function buildIconBar() { $icons = array(); $selected_conpherence = $this->getSelectedConpherence(); $conpherences = $this->getConpherences(); foreach ($conpherences as $conpherence) { $classes = array('conpherence-durable-column-thread-icon'); if ($selected_conpherence->getID() == $conpherence->getID()) { $classes[] = 'selected'; } $data = $conpherence->getDisplayData($this->getUser()); $thread_title = phutil_tag( 'span', array(), array( $data['title'], )); $image = $data['image']; Javelin::initBehavior('phabricator-tooltips'); $icons[] = javelin_tag( 'a', array( 'href' => '/conpherence/columnview/', 'class' => implode(' ', $classes), 'sigil' => 'conpherence-durable-column-thread-icon has-tooltip', 'meta' => array( 'threadID' => $conpherence->getID(), 'threadTitle' => hsprintf('%s', $thread_title), 'tip' => $data['title'], 'align' => 'W', ), ), phutil_tag( 'span', array( 'style' => 'background-image: url('.$image.')', ), '')); } return $icons; } private function buildHeader() { $conpherence = $this->getSelectedConpherence(); $bubble_id = celerity_generate_unique_node_id(); $dropdown_id = celerity_generate_unique_node_id(); $settings_list = new PHUIListView(); $header_actions = $this->getHeaderActionsConfig($conpherence); foreach ($header_actions as $action) { $settings_list->addMenuItem( id(new PHUIListItemView()) ->setHref($action['href']) ->setName($action['name']) ->setIcon($action['icon']) ->setDisabled($action['disabled']) ->addSigil('conpherence-durable-column-header-action') ->setMetadata(array( 'action' => $action['key'], ))); } $settings_menu = phutil_tag( 'div', array( 'id' => $dropdown_id, 'class' => 'phabricator-main-menu-dropdown phui-list-sidenav '. 'conpherence-settings-dropdown', 'sigil' => 'phabricator-notification-menu', 'style' => 'display: none', ), $settings_list); Javelin::initBehavior( 'aphlict-dropdown', array( 'bubbleID' => $bubble_id, 'dropdownID' => $dropdown_id, 'local' => true, 'containerDivID' => 'conpherence-durable-column', )); $bars = id(new PHUIListItemView()) ->setName(pht('Room Actions')) ->setIcon('fa-gear') ->addClass('core-menu-item') ->addClass('conpherence-settings-icon') ->addSigil('conpherence-settings-menu') ->setID($bubble_id) ->setHref('#') ->setAural(pht('Room Actions')) ->setOrder(400); $minimize = id(new PHUIListItemView()) ->setName(pht('Minimize Window')) ->setIcon('fa-toggle-down') ->addClass('core-menu-item') ->addClass('conpherence-minimize-icon') ->addSigil('conpherence-minimize-window') ->setHref('#') ->setAural(pht('Minimize Window')) ->setOrder(300); $settings_button = id(new PHUIListView()) ->addMenuItem($bars) ->addMenuItem($minimize) ->addClass('phabricator-application-menu'); if ($conpherence) { $data = $conpherence->getDisplayData($this->getUser()); $header = phutil_tag( 'span', array(), $data['title']); } else { $header = phutil_tag( 'span', array(), pht('Conpherence')); } $status = new PhabricatorNotificationStatusView(); return phutil_tag( 'div', array( 'class' => 'conpherence-durable-column-header-inner', ), array( $status, javelin_tag( 'div', array( 'sigil' => 'conpherence-durable-column-header-text', 'class' => 'conpherence-durable-column-header-text', ), $header), $settings_button, $settings_menu, )); } private function getHeaderActionsConfig($conpherence) { $actions = array(); if ($conpherence) { $can_edit = PhabricatorPolicyFilter::hasCapability( $this->getUser(), $conpherence, PhabricatorPolicyCapability::CAN_EDIT); $actions[] = array( 'name' => pht('Add Participants'), 'disabled' => !$can_edit, 'href' => '/conpherence/update/'.$conpherence->getID().'/', 'icon' => 'fa-plus', 'key' => ConpherenceUpdateActions::ADD_PERSON, ); $actions[] = array( 'name' => pht('Edit Room'), 'disabled' => !$can_edit, 'href' => '/conpherence/update/'.$conpherence->getID().'/?nopic', 'icon' => 'fa-pencil', 'key' => ConpherenceUpdateActions::METADATA, ); $actions[] = array( 'name' => pht('View in Conpherence'), 'disabled' => false, 'href' => '/'.$conpherence->getMonogram(), 'icon' => 'fa-comments', 'key' => 'go_conpherence', ); } $actions[] = array( 'name' => pht('Hide Window'), 'disabled' => false, 'href' => '#', 'icon' => 'fa-times', 'key' => 'hide_column', ); return $actions; } private function buildTransactions() { $conpherence = $this->getSelectedConpherence(); if (!$conpherence) { if (!$this->getVisible() || $this->getInitialLoad()) { return pht('Loading...'); } $view = array( phutil_tag( 'div', array( 'class' => 'column-no-rooms-text', ), pht('You have not joined any rooms yet.')), javelin_tag( 'a', array( 'href' => '/conpherence/search/', 'class' => 'button grey', ), pht('Find Rooms')), ); return phutil_tag_div('column-no-rooms', $view); } $data = ConpherenceTransactionRenderer::renderTransactions( $this->getUser(), - $conpherence, - $full_display = false); + $conpherence); $messages = ConpherenceTransactionRenderer::renderMessagePaneContent( $data['transactions'], $data['oldest_transaction_id'], $data['newest_transaction_id']); return $messages; } private function buildTextInput() { $conpherence = $this->getSelectedConpherence(); if (!$conpherence) { return null; } $draft = $this->getDraft(); $draft_value = null; if ($draft) { $draft_value = $draft->getDraft(); } $textarea_id = celerity_generate_unique_node_id(); $textarea = javelin_tag( 'textarea', array( 'id' => $textarea_id, 'name' => 'text', 'class' => 'conpherence-durable-column-textarea', 'sigil' => 'conpherence-durable-column-textarea', 'placeholder' => pht('Send a message...'), ), $draft_value); Javelin::initBehavior( 'aphront-drag-and-drop-textarea', array( 'target' => $textarea_id, 'activatedClass' => 'aphront-textarea-drag-and-drop', 'uri' => '/file/dropupload/', )); $id = $conpherence->getID(); return phabricator_form( $this->getUser(), array( 'method' => 'POST', 'action' => '/conpherence/update/'.$id.'/', 'sigil' => 'conpherence-message-form', ), array( $textarea, phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'action', 'value' => ConpherenceUpdateActions::MESSAGE, )), )); } private function buildStatusText() { return null; } private function buildSendButton() { $conpherence = $this->getSelectedConpherence(); if (!$conpherence) { return null; } return javelin_tag( 'button', array( 'class' => 'grey', 'sigil' => 'conpherence-send-message', ), pht('Send')); } } diff --git a/src/applications/conpherence/view/ConpherenceFormDragAndDropUploadControl.php b/src/applications/conpherence/view/ConpherenceFormDragAndDropUploadControl.php deleted file mode 100644 index 3d9ea57cf9..0000000000 --- a/src/applications/conpherence/view/ConpherenceFormDragAndDropUploadControl.php +++ /dev/null @@ -1,40 +0,0 @@ -dropID = $drop_id; - return $this; - } - public function getDropID() { - return $this->dropID; - } - - protected function getCustomControlClass() { - return null; - } - - protected function renderInput() { - - $drop_id = celerity_generate_unique_node_id(); - Javelin::initBehavior('conpherence-drag-and-drop-photo', - array( - 'target' => $drop_id, - 'form_pane' => 'conpherence-form', - 'upload_uri' => '/file/dropupload/', - 'activated_class' => 'conpherence-dialogue-upload-photo', - )); - require_celerity_resource('conpherence-update-css'); - - return phutil_tag( - 'div', - array( - 'id' => $drop_id, - 'class' => 'conpherence-dialogue-drag-photo', - ), - pht('Drag and drop an image here to upload it.')); - } - -} diff --git a/src/applications/conpherence/view/ConpherenceLayoutView.php b/src/applications/conpherence/view/ConpherenceLayoutView.php index f0d94d9a06..6699d61994 100644 --- a/src/applications/conpherence/view/ConpherenceLayoutView.php +++ b/src/applications/conpherence/view/ConpherenceLayoutView.php @@ -1,256 +1,261 @@ messages = $messages; return $this; } public function setReplyForm($reply_form) { $this->replyForm = $reply_form; return $this; } public function setHeader($header) { $this->header = $header; return $this; } + public function setSearch($search) { + $this->search = $search; + return $this; + } + public function setRole($role) { $this->role = $role; return $this; } public function getThreadView() { return $this->threadView; } public function setBaseURI($base_uri) { $this->baseURI = $base_uri; return $this; } public function setThread(ConpherenceThread $thread) { $this->thread = $thread; return $this; } public function setThreadView(ConpherenceThreadListView $thead_view) { $this->threadView = $thead_view; return $this; } public function setLatestTransactionID($id) { $this->latestTransactionID = $id; return $this; } - public function getWidgetColumnVisible() { - $widget_key = PhabricatorConpherenceWidgetVisibleSetting::SETTINGKEY; - $user = $this->getUser(); - return (bool)$user->getUserSetting($widget_key, false); - } - protected function getTagAttributes() { $classes = array(); - if (!$this->getWidgetColumnVisible()) { - $classes[] = 'hide-widgets'; - } + $classes[] = 'conpherence-layout'; + $classes[] = 'hide-widgets'; + $classes[] = 'conpherence-role-'.$this->role; return array( - 'id' => 'conpherence-main-layout', - 'sigil' => 'conpherence-layout', - 'class' => 'conpherence-layout '. - implode(' ', $classes). - ' conpherence-role-'.$this->role, - ); - + 'id' => 'conpherence-main-layout', + 'sigil' => 'conpherence-layout', + 'class' => implode(' ', $classes), + ); } protected function getTagContent() { require_celerity_resource('conpherence-menu-css'); require_celerity_resource('conpherence-message-pane-css'); require_celerity_resource('conpherence-participant-pane-css'); $selected_id = null; $selected_thread_id = null; $selected_thread_phid = null; $can_edit_selected = null; $nux = null; if ($this->thread) { $selected_id = $this->thread->getPHID().'-nav-item'; $selected_thread_id = $this->thread->getID(); $selected_thread_phid = $this->thread->getPHID(); $can_edit_selected = PhabricatorPolicyFilter::hasCapability( $this->getUser(), $this->thread, PhabricatorPolicyCapability::CAN_EDIT); } else { $nux = $this->buildNUXView(); } $this->initBehavior('conpherence-menu', array( 'baseURI' => $this->baseURI, 'layoutID' => 'conpherence-main-layout', 'selectedID' => $selected_id, 'selectedThreadID' => $selected_thread_id, 'selectedThreadPHID' => $selected_thread_phid, 'canEditSelectedThread' => $can_edit_selected, 'latestTransactionID' => $this->latestTransactionID, 'role' => $this->role, 'hasThreadList' => (bool)$this->threadView, 'hasThread' => (bool)$this->messages, 'hasWidgets' => false, )); $this->initBehavior('conpherence-participant-pane'); return array( javelin_tag( 'div', array( 'id' => 'conpherence-menu-pane', 'class' => 'conpherence-menu-pane phabricator-side-menu', 'sigil' => 'conpherence-menu-pane', ), $this->threadView), javelin_tag( 'div', array( 'class' => 'conpherence-content-pane', ), array( + phutil_tag( + 'div', + array( + 'class' => 'conpherence-loading-mask', + ), + ''), javelin_tag( 'div', array( 'class' => 'conpherence-header-pane', 'id' => 'conpherence-header-pane', 'sigil' => 'conpherence-header-pane', ), nonempty($this->header, '')), javelin_tag( 'div', array( 'class' => 'conpherence-no-threads', 'sigil' => 'conpherence-no-threads', 'style' => 'display: none;', ), $nux), javelin_tag( 'div', array( 'class' => 'conpherence-participant-pane', 'id' => 'conpherence-participant-pane', 'sigil' => 'conpherence-participant-pane', ), array( phutil_tag( 'div', array( 'class' => 'widgets-loading-mask', ), ''), javelin_tag( 'div', array( 'sigil' => 'conpherence-widgets-holder', ), ''), )), javelin_tag( 'div', array( 'class' => 'conpherence-message-pane', 'id' => 'conpherence-message-pane', 'sigil' => 'conpherence-message-pane', ), array( javelin_tag( 'div', array( 'class' => 'conpherence-messages', 'id' => 'conpherence-messages', 'sigil' => 'conpherence-messages', ), nonempty($this->messages, '')), + javelin_tag( + 'div', + array( + 'class' => 'conpherence-search-main', + 'id' => 'conpherence-search-main', + 'sigil' => 'conpherence-search-main', + ), + nonempty($this->search, '')), phutil_tag( 'div', array( 'class' => 'messages-loading-mask', ), ''), javelin_tag( 'div', array( 'id' => 'conpherence-form', 'sigil' => 'conpherence-form', ), nonempty($this->replyForm, '')), )), )), ); } private function buildNUXView() { $viewer = $this->getViewer(); $engine = new ConpherenceThreadSearchEngine(); $engine->setViewer($viewer); $saved = $engine->buildSavedQueryFromBuiltin('all'); $query = $engine->buildQueryFromSavedQuery($saved); $pager = $engine->newPagerForSavedQuery($saved); $pager->setPageSize(10); $results = $engine->executeQuery($query, $pager); $view = $engine->renderResults($results, $saved); $create_button = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('New Room')) ->setHref('/conpherence/new/') ->setWorkflow(true) ->setColor(PHUIButtonView::GREEN); if ($results) { $create_button->setIcon('fa-comments'); $header = id(new PHUIHeaderView()) ->setHeader(pht('Joinable Rooms')) ->addActionLink($create_button); $box = id(new PHUIObjectBoxView()) ->setHeader($header) - ->setObjectList($view->getObjectList()); - if ($viewer->isLoggedIn()) { - $info = id(new PHUIInfoView()) - ->appendChild(pht('You have not joined any rooms yet.')) - ->setSeverity(PHUIInfoView::SEVERITY_NOTICE); - $box->setInfoView($info); - } + ->setObjectList($view->getContent()); return $box; } else { $view = id(new PHUIBigInfoView()) ->setIcon('fa-comments') ->setTitle(pht('Welcome to Conpherence')) ->setDescription( pht('Conpherence lets you create public or private rooms to '. 'communicate with others.')) ->addAction($create_button); return $view; } } } diff --git a/src/applications/conpherence/view/ConpherenceTransactionView.php b/src/applications/conpherence/view/ConpherenceTransactionView.php index 12123aafcd..c18a672ca2 100644 --- a/src/applications/conpherence/view/ConpherenceTransactionView.php +++ b/src/applications/conpherence/view/ConpherenceTransactionView.php @@ -1,263 +1,251 @@ conpherenceThread = $t; return $this; } private function getConpherenceThread() { return $this->conpherenceThread; } public function setConpherenceTransaction(ConpherenceTransaction $tx) { $this->conpherenceTransaction = $tx; return $this; } private function getConpherenceTransaction() { return $this->conpherenceTransaction; } public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } public function getHandles() { return $this->handles; } public function setMarkupEngine(PhabricatorMarkupEngine $markup_engine) { $this->markupEngine = $markup_engine; return $this; } private function getMarkupEngine() { return $this->markupEngine; } - public function setFullDisplay($bool) { - $this->fullDisplay = $bool; + public function addClass($class) { + $this->classes[] = $class; return $this; } - private function getFullDisplay() { - return $this->fullDisplay; - } - - public function addClass($class) { - $this->classes[] = $class; + public function setSearchResult($result) { + $this->searchResult = $result; return $this; } public function render() { $viewer = $this->getUser(); if (!$viewer) { throw new PhutilInvalidStateException('setUser'); } require_celerity_resource('conpherence-transaction-css'); $transaction = $this->getConpherenceTransaction(); switch ($transaction->getTransactionType()) { case ConpherenceTransaction::TYPE_DATE_MARKER: return javelin_tag( 'div', array( 'class' => 'conpherence-transaction-view date-marker', 'sigil' => 'conpherence-transaction-view', 'meta' => array( 'id' => $transaction->getID() + 0.5, ), ), array( phutil_tag( 'span', array( 'class' => 'date', ), phabricator_format_local_time( $transaction->getDateCreated(), $viewer, 'M jS, Y')), )); break; } $info = $this->renderTransactionInfo(); $actions = $this->renderTransactionActions(); $image = $this->renderTransactionImage(); $content = $this->renderTransactionContent(); $classes = implode(' ', $this->classes); - - $transaction_dom_id = null; - if ($this->getFullDisplay()) { - $transaction_dom_id = 'anchor-'.$transaction->getID(); - } + $transaction_dom_id = 'anchor-'.$transaction->getID(); $header = phutil_tag_div( 'conpherence-transaction-header grouped', array($actions, $info)); return javelin_tag( 'div', array( 'class' => 'conpherence-transaction-view '.$classes, 'id' => $transaction_dom_id, 'sigil' => 'conpherence-transaction-view', 'meta' => array( 'id' => $transaction->getID(), ), ), array( $image, phutil_tag_div('conpherence-transaction-detail grouped', array($header, $content)), )); } private function renderTransactionInfo() { $viewer = $this->getUser(); $thread = $this->getConpherenceThread(); $transaction = $this->getConpherenceTransaction(); $info = array(); Javelin::initBehavior('phabricator-tooltips'); $tip = phabricator_datetime($transaction->getDateCreated(), $viewer); $label = phabricator_time($transaction->getDateCreated(), $viewer); $width = 360; - if ($this->getFullDisplay()) { - Javelin::initBehavior('phabricator-watch-anchor'); - $anchor = id(new PhabricatorAnchorView()) - ->setAnchorName($transaction->getID()) - ->render(); + Javelin::initBehavior('phabricator-watch-anchor'); + $anchor = id(new PhabricatorAnchorView()) + ->setAnchorName($transaction->getID()) + ->render(); + + if ($this->searchResult) { + $uri = $thread->getMonogram(); + $info[] = hsprintf( + '%s', + javelin_tag( + 'a', + array( + 'href' => '/'.$uri.'#'.$transaction->getID(), + 'class' => 'transaction-date', + 'sigil' => 'conpherence-search-result-jump', + ), + $tip)); + } else { $info[] = hsprintf( '%s%s', $anchor, javelin_tag( 'a', array( 'href' => '#'.$transaction->getID(), - 'class' => 'anchor-link', + 'class' => 'transaction-date anchor-link', 'sigil' => 'has-tooltip', 'meta' => array( 'tip' => $tip, 'size' => $width, ), ), $label)); - } else { - $href = '/'.$thread->getMonogram().'#'.$transaction->getID(); - $info[] = javelin_tag( - 'a', - array( - 'href' => $href, - 'class' => 'epoch-link', - 'sigil' => 'has-tooltip', - 'meta' => array( - 'tip' => $tip, - 'size' => $width, - ), - ), - $label); } return phutil_tag( 'span', array( 'class' => 'conpherence-transaction-info', ), $info); } private function renderTransactionActions() { $transaction = $this->getConpherenceTransaction(); switch ($transaction->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: $handles = $this->getHandles(); $author = $handles[$transaction->getAuthorPHID()]; $actions = array($author->renderLink()); break; default: $actions = null; break; } return $actions; } private function renderTransactionImage() { $image = null; $transaction = $this->getConpherenceTransaction(); switch ($transaction->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: $handles = $this->getHandles(); $author = $handles[$transaction->getAuthorPHID()]; $image_uri = $author->getImageURI(); $image = phutil_tag( 'span', array( 'class' => 'conpherence-transaction-image', 'style' => 'background-image: url('.$image_uri.');', )); break; } return $image; } private function renderTransactionContent() { $transaction = $this->getConpherenceTransaction(); $content = null; $content_class = null; $content = null; $handles = $this->getHandles(); switch ($transaction->getTransactionType()) { case ConpherenceTransaction::TYPE_TITLE: case ConpherenceTransaction::TYPE_TOPIC: case ConpherenceTransaction::TYPE_PICTURE: case ConpherenceTransaction::TYPE_PARTICIPANTS: case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: case PhabricatorTransactions::TYPE_EDGE: $content = $transaction->getTitle(); $this->addClass('conpherence-edited'); break; case PhabricatorTransactions::TYPE_COMMENT: $this->addClass('conpherence-comment'); $author = $handles[$transaction->getAuthorPHID()]; $comment = $transaction->getComment(); $content = $this->getMarkupEngine()->getOutput( $comment, PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); $content_class = 'conpherence-message'; break; } - $this->appendChild( - phutil_tag( - 'div', - array( - 'class' => $content_class, - ), - $content)); + $view = phutil_tag( + 'div', + array( + 'class' => $content_class, + ), + $content); - return phutil_tag_div( - 'conpherence-transaction-content', - $this->renderChildren()); + return phutil_tag_div('conpherence-transaction-content', $view); } } diff --git a/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php b/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php index 1d7b646270..3eb1568a76 100644 --- a/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php +++ b/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php @@ -1,275 +1,282 @@ getFieldKey()] = array( 'disabled' => $field->shouldDisableByDefault(), ); } + $inline_description = $this->deformat( + pht(<<newOption( 'differential.fields', $custom_field_type, $default_fields) ->setCustomData( id(new DifferentialRevision())->getCustomFieldBaseClass()) ->setDescription( pht( "Select and reorder revision fields.\n\n". "NOTE: This feature is under active development and subject ". "to change.")), $this->newOption( 'differential.whitespace-matters', 'list', array( '/\.py$/', '/\.l?hs$/', )) ->setDescription( pht( "List of file regexps where whitespace is meaningful and should ". "not use 'ignore-all' by default")), $this->newOption('differential.require-test-plan-field', 'bool', true) ->setBoolOptions( array( pht("Require 'Test Plan' field"), pht("Make 'Test Plan' field optional"), )) ->setSummary(pht('Require "Test Plan" field?')) ->setDescription( pht( "Differential has a required 'Test Plan' field by default. You ". "can make it optional by setting this to false. You can also ". "completely remove it above, if you prefer.")), $this->newOption('differential.enable-email-accept', 'bool', false) ->setBoolOptions( array( pht('Enable Email "!accept" Action'), pht('Disable Email "!accept" Action'), )) ->setSummary(pht('Enable or disable "!accept" action via email.')) ->setDescription( pht( 'If inbound email is configured, users can interact with '. 'revisions by using "!actions" in email replies (for example, '. '"!resign" or "!rethink"). However, by default, users may not '. '"!accept" revisions via email: email authentication can be '. 'configured to be very weak, and email "!accept" is kind of '. 'sketchy and implies the revision may not actually be receiving '. 'thorough review. You can enable "!accept" by setting this '. 'option to true.')), $this->newOption('differential.generated-paths', 'list', array()) ->setSummary(pht('File regexps to treat as automatically generated.')) ->setDescription( pht( 'List of file regexps that should be treated as if they are '. 'generated by an automatic process, and thus be hidden by '. 'default in Differential.'. "\n\n". 'NOTE: This property is cached, so you will need to purge the '. 'cache after making changes if you want the new configuration '. 'to affect existing revisions. For instructions, see '. '**[[ %s | Managing Caches ]]** in the documentation.', $caches_href)) ->addExample("/config\.h$/\n#(^|/)autobuilt/#", pht('Valid Setting')), $this->newOption('differential.sticky-accept', 'bool', true) ->setBoolOptions( array( pht('Accepts persist across updates'), pht('Accepts are reset by updates'), )) ->setSummary( pht('Should "Accepted" revisions remain "Accepted" after updates?')) ->setDescription( pht( 'Normally, when revisions that have been "Accepted" are updated, '. 'they remain "Accepted". This allows reviewers to suggest minor '. 'alterations when accepting, and encourages authors to update '. 'if they make minor changes in response to this feedback.'. "\n\n". 'If you want updates to always require re-review, you can disable '. 'the "stickiness" of the "Accepted" status with this option. '. 'This may make the process for minor changes much more burdensome '. 'to both authors and reviewers.')), $this->newOption('differential.allow-self-accept', 'bool', false) ->setBoolOptions( array( pht('Allow self-accept'), pht('Disallow self-accept'), )) ->setSummary(pht('Allows users to accept their own revisions.')) ->setDescription( pht( "If you set this to true, users can accept their own revisions. ". "This action is disabled by default because it's most likely not ". "a behavior you want, but it proves useful if you are working ". "alone on a project and want to make use of all of ". "differential's features.")), $this->newOption('differential.always-allow-close', 'bool', false) ->setBoolOptions( array( pht('Allow any user'), pht('Restrict to submitter'), )) ->setSummary(pht('Allows any user to close accepted revisions.')) ->setDescription( pht( 'If you set this to true, any user can close any revision so '. 'long as it has been accepted. This can be useful depending on '. 'your development model. For example, github-style pull requests '. 'where the reviewer is often the actual committer can benefit '. 'from turning this option to true. If false, only the submitter '. 'can close a revision.')), $this->newOption('differential.always-allow-abandon', 'bool', false) ->setBoolOptions( array( pht('Allow any user'), pht('Restrict to submitter'), )) ->setSummary(pht('Allows any user to abandon revisions.')) ->setDescription( pht( 'If you set this to true, any user can abandon any revision. If '. 'false, only the submitter can abandon a revision.')), $this->newOption('differential.allow-reopen', 'bool', false) ->setBoolOptions( array( pht('Enable reopen'), pht('Disable reopen'), )) ->setSummary(pht('Allows any user to reopen a closed revision.')) ->setDescription( pht( 'If you set this to true, any user can reopen a revision so '. 'long as it has been closed. This can be useful if a revision '. 'is accidentally closed or if a developer changes his or her '. 'mind after closing a revision. If it is false, reopening '. 'is not allowed.')), $this->newOption('differential.close-on-accept', 'bool', false) ->setBoolOptions( array( pht('Treat Accepted Revisions as "Closed"'), pht('Treat Accepted Revisions as "Open"'), )) ->setSummary(pht('Allows "Accepted" to act as a closed status.')) ->setDescription( pht( 'Normally, Differential revisions remain on the dashboard when '. 'they are "Accepted", and the author then commits the changes '. 'to "Close" the revision and move it off the dashboard.'. "\n\n". 'If you have an unusual workflow where Differential is used for '. 'post-commit review (normally called "Audit", elsewhere in '. 'Phabricator), you can set this flag to treat the "Accepted" '. 'state as a "Closed" state and end the review workflow early.'. "\n\n". 'This sort of workflow is very unusual. Very few installs should '. 'need to change this option.')), $this->newOption( 'metamta.differential.subject-prefix', 'string', '[Differential]') ->setDescription(pht('Subject prefix for Differential mail.')), $this->newOption( 'metamta.differential.attach-patches', 'bool', false) ->setBoolOptions( array( pht('Attach Patches'), pht('Do Not Attach Patches'), )) ->setSummary(pht('Attach patches to email, as text attachments.')) ->setDescription( pht( 'If you set this to true, Phabricator will attach patches to '. 'Differential mail (as text attachments). This will not work if '. 'you are using SendGrid as your mail adapter.')), $this->newOption( 'metamta.differential.inline-patches', 'int', 0) ->setSummary(pht('Inline patches in email, as body text.')) - ->setDescription( - pht( - "To include patches inline in email bodies, set this to a ". - "positive integer. Patches will be inlined if they are at most ". - "that many lines. For instance, a value of 100 means 'inline ". - "patches if they are no longer than 100 lines'. By default, ". - "patches are not inlined.")), + ->setDescription($inline_description), $this->newOption( 'metamta.differential.patch-format', 'enum', 'unified') ->setDescription( pht('Format for inlined or attached patches.')) ->setEnumOptions( array('unified' => 'unified', 'git' => 'git')), ); } } diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php index 3e9fe2b99f..b4828494c0 100644 --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -1,1906 +1,1925 @@ getTransactionType() == $type_update) { return $xaction; } } return null; } public function setIsCloseByCommit($is_close_by_commit) { $this->isCloseByCommit = $is_close_by_commit; return $this; } public function getIsCloseByCommit() { return $this->isCloseByCommit; } public function setChangedPriorToCommitURI($uri) { $this->changedPriorToCommitURI = $uri; return $this; } public function getChangedPriorToCommitURI() { return $this->changedPriorToCommitURI; } public function setRepositoryPHIDOverride($phid_or_null) { $this->repositoryPHIDOverride = $phid_or_null; return $this; } public function getTransactionTypes() { $types = parent::getTransactionTypes(); $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = DifferentialTransaction::TYPE_ACTION; $types[] = DifferentialTransaction::TYPE_INLINE; $types[] = DifferentialTransaction::TYPE_STATUS; $types[] = DifferentialTransaction::TYPE_UPDATE; return $types; } protected function getCustomTransactionOldValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_ACTION: return null; case DifferentialTransaction::TYPE_INLINE: return null; case DifferentialTransaction::TYPE_UPDATE: if ($this->getIsNewObject()) { return null; } else { return $object->getActiveDiff()->getPHID(); } } return parent::getCustomTransactionOldValue($object, $xaction); } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_ACTION: case DifferentialTransaction::TYPE_UPDATE: return $xaction->getNewValue(); case DifferentialTransaction::TYPE_INLINE: return null; } return parent::getCustomTransactionNewValue($object, $xaction); } protected function transactionHasEffect( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $actor_phid = $this->getActingAsPHID(); switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_INLINE: return $xaction->hasComment(); case DifferentialTransaction::TYPE_ACTION: $status_closed = ArcanistDifferentialRevisionStatus::CLOSED; $status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED; $status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW; $status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION; $status_plan = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED; $action_type = $xaction->getNewValue(); switch ($action_type) { case DifferentialAction::ACTION_ACCEPT: case DifferentialAction::ACTION_REJECT: if ($action_type == DifferentialAction::ACTION_ACCEPT) { $new_status = DifferentialReviewerStatus::STATUS_ACCEPTED; } else { $new_status = DifferentialReviewerStatus::STATUS_REJECTED; } $actor = $this->getActor(); // These transactions can cause effects in two ways: by altering the // status of an existing reviewer; or by adding the actor as a new // reviewer. $will_add_reviewer = true; foreach ($object->getReviewerStatus() as $reviewer) { if ($reviewer->hasAuthority($actor)) { if ($reviewer->getStatus() != $new_status) { return true; } } if ($reviewer->getReviewerPHID() == $actor_phid) { $will_add_reviwer = false; } } return $will_add_reviewer; case DifferentialAction::ACTION_CLOSE: return ($object->getStatus() != $status_closed); case DifferentialAction::ACTION_ABANDON: return ($object->getStatus() != $status_abandoned); case DifferentialAction::ACTION_RECLAIM: return ($object->getStatus() == $status_abandoned); case DifferentialAction::ACTION_REOPEN: return ($object->getStatus() == $status_closed); case DifferentialAction::ACTION_RETHINK: return ($object->getStatus() != $status_plan); case DifferentialAction::ACTION_REQUEST: return ($object->getStatus() != $status_review); case DifferentialAction::ACTION_RESIGN: foreach ($object->getReviewerStatus() as $reviewer) { if ($reviewer->getReviewerPHID() == $actor_phid) { return true; } } return false; case DifferentialAction::ACTION_CLAIM: return ($actor_phid != $object->getAuthorPHID()); } } return parent::transactionHasEffect($object, $xaction); } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW; $status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION; $status_plan = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED; $status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED; $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED; switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_INLINE: return; case DifferentialTransaction::TYPE_UPDATE: if (!$this->getIsCloseByCommit()) { switch ($object->getStatus()) { case $status_revision: case $status_plan: case $status_abandoned: $object->setStatus($status_review); break; } } $diff = $this->requireDiff($xaction->getNewValue()); $object->setLineCount($diff->getLineCount()); if ($this->repositoryPHIDOverride !== false) { $object->setRepositoryPHID($this->repositoryPHIDOverride); } else { $object->setRepositoryPHID($diff->getRepositoryPHID()); } $object->attachActiveDiff($diff); // TODO: Update the `diffPHID` once we add that. return; case DifferentialTransaction::TYPE_ACTION: switch ($xaction->getNewValue()) { case DifferentialAction::ACTION_RESIGN: case DifferentialAction::ACTION_ACCEPT: case DifferentialAction::ACTION_REJECT: // These have no direct effects, and affect review status only // indirectly by altering reviewers with TYPE_EDGE transactions. return; case DifferentialAction::ACTION_ABANDON: $object->setStatus(ArcanistDifferentialRevisionStatus::ABANDONED); return; case DifferentialAction::ACTION_RETHINK: $object->setStatus($status_plan); return; case DifferentialAction::ACTION_RECLAIM: $object->setStatus($status_review); return; case DifferentialAction::ACTION_REOPEN: $object->setStatus($status_review); return; case DifferentialAction::ACTION_REQUEST: $object->setStatus($status_review); return; case DifferentialAction::ACTION_CLOSE: $old_status = $object->getStatus(); $object->setStatus(ArcanistDifferentialRevisionStatus::CLOSED); $was_accepted = ($old_status == $status_accepted); $object->setProperty( DifferentialRevision::PROPERTY_CLOSED_FROM_ACCEPTED, $was_accepted); return; case DifferentialAction::ACTION_CLAIM: $object->setAuthorPHID($this->getActingAsPHID()); return; default: throw new Exception( pht( 'Differential action "%s" is not a valid action!', $xaction->getNewValue())); } break; } return parent::applyCustomInternalTransaction($object, $xaction); } protected function expandTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $results = parent::expandTransaction($object, $xaction); $actor = $this->getActor(); $actor_phid = $this->getActingAsPHID(); $type_edge = PhabricatorTransactions::TYPE_EDGE; $status_plan = ArcanistDifferentialRevisionStatus::CHANGES_PLANNED; $edge_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST; $edge_ref_task = DifferentialRevisionHasTaskEdgeType::EDGECONST; $is_sticky_accept = PhabricatorEnv::getEnvConfig( 'differential.sticky-accept'); $downgrade_rejects = false; $downgrade_accepts = false; if ($this->getIsCloseByCommit()) { // Never downgrade reviewers when we're closing a revision after a // commit. } else { switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_UPDATE: $downgrade_rejects = true; if (!$is_sticky_accept) { // If "sticky accept" is disabled, also downgrade the accepts. $downgrade_accepts = true; } break; case DifferentialTransaction::TYPE_ACTION: switch ($xaction->getNewValue()) { case DifferentialAction::ACTION_REQUEST: $downgrade_rejects = true; if ((!$is_sticky_accept) || ($object->getStatus() != $status_plan)) { // If the old state isn't "changes planned", downgrade the // accepts. This exception allows an accepted revision to // go through Plan Changes -> Request Review to return to // "accepted" if the author didn't update the revision. $downgrade_accepts = true; } break; } break; } } $new_accept = DifferentialReviewerStatus::STATUS_ACCEPTED; $new_reject = DifferentialReviewerStatus::STATUS_REJECTED; $old_accept = DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER; $old_reject = DifferentialReviewerStatus::STATUS_REJECTED_OLDER; if ($downgrade_rejects || $downgrade_accepts) { // When a revision is updated, change all "reject" to "rejected older // revision". This means we won't immediately push the update back into // "needs review", but outstanding rejects will still block it from // moving to "accepted". // We also do this for "Request Review", even though the diff is not // updated directly. Essentially, this acts like an update which doesn't // actually change the diff text. $edits = array(); foreach ($object->getReviewerStatus() as $reviewer) { if ($downgrade_rejects) { if ($reviewer->getStatus() == $new_reject) { $edits[$reviewer->getReviewerPHID()] = array( 'data' => array( 'status' => $old_reject, ), ); } } if ($downgrade_accepts) { if ($reviewer->getStatus() == $new_accept) { $edits[$reviewer->getReviewerPHID()] = array( 'data' => array( 'status' => $old_accept, ), ); } } } if ($edits) { $results[] = id(new DifferentialTransaction()) ->setTransactionType($type_edge) ->setMetadataValue('edge:type', $edge_reviewer) ->setIgnoreOnNoEffect(true) ->setNewValue(array('+' => $edits)); } } switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_UPDATE: if ($this->getIsCloseByCommit()) { // Don't bother with any of this if this update is a side effect of // commit detection. break; } // When a revision is updated and the diff comes from a branch named // "T123" or similar, automatically associate the commit with the // task that the branch names. $maniphest = 'PhabricatorManiphestApplication'; if (PhabricatorApplication::isClassInstalled($maniphest)) { $diff = $this->requireDiff($xaction->getNewValue()); $branch = $diff->getBranch(); // No "$", to allow for branches like T123_demo. $match = null; if (preg_match('/^T(\d+)/i', $branch, $match)) { $task_id = $match[1]; $tasks = id(new ManiphestTaskQuery()) ->setViewer($this->getActor()) ->withIDs(array($task_id)) ->execute(); if ($tasks) { $task = head($tasks); $task_phid = $task->getPHID(); $results[] = id(new DifferentialTransaction()) ->setTransactionType($type_edge) ->setMetadataValue('edge:type', $edge_ref_task) ->setIgnoreOnNoEffect(true) ->setNewValue(array('+' => array($task_phid => $task_phid))); } } } break; case PhabricatorTransactions::TYPE_COMMENT: // When a user leaves a comment, upgrade their reviewer status from // "added" to "commented" if they're also a reviewer. We may further // upgrade this based on other actions in the transaction group. $status_added = DifferentialReviewerStatus::STATUS_ADDED; $status_commented = DifferentialReviewerStatus::STATUS_COMMENTED; $data = array( 'status' => $status_commented, ); $edits = array(); foreach ($object->getReviewerStatus() as $reviewer) { if ($reviewer->getReviewerPHID() == $actor_phid) { if ($reviewer->getStatus() == $status_added) { $edits[$actor_phid] = array( 'data' => $data, ); } } } if ($edits) { $results[] = id(new DifferentialTransaction()) ->setTransactionType($type_edge) ->setMetadataValue('edge:type', $edge_reviewer) ->setIgnoreOnNoEffect(true) ->setNewValue(array('+' => $edits)); } break; case DifferentialTransaction::TYPE_ACTION: $action_type = $xaction->getNewValue(); switch ($action_type) { case DifferentialAction::ACTION_ACCEPT: case DifferentialAction::ACTION_REJECT: if ($action_type == DifferentialAction::ACTION_ACCEPT) { $data = array( 'status' => DifferentialReviewerStatus::STATUS_ACCEPTED, ); } else { $data = array( 'status' => DifferentialReviewerStatus::STATUS_REJECTED, ); } $edits = array(); foreach ($object->getReviewerStatus() as $reviewer) { if ($reviewer->hasAuthority($actor)) { $edits[$reviewer->getReviewerPHID()] = array( 'data' => $data, ); } } // Also either update or add the actor themselves as a reviewer. $edits[$actor_phid] = array( 'data' => $data, ); $results[] = id(new DifferentialTransaction()) ->setTransactionType($type_edge) ->setMetadataValue('edge:type', $edge_reviewer) ->setIgnoreOnNoEffect(true) ->setNewValue(array('+' => $edits)); break; case DifferentialAction::ACTION_CLAIM: // If the user is commandeering, add the previous owner as a // reviewer and remove the actor. $edits = array( '-' => array( $actor_phid => $actor_phid, ), ); $owner_phid = $object->getAuthorPHID(); if ($owner_phid) { $reviewer = new DifferentialReviewer( $owner_phid, array( 'status' => DifferentialReviewerStatus::STATUS_ADDED, )); $edits['+'] = array( $owner_phid => array( 'data' => $reviewer->getEdgeData(), ), ); } // NOTE: We're setting setIsCommandeerSideEffect() on this because // normally you can't add a revision's author as a reviewer, but // this action swaps them after validation executes. $results[] = id(new DifferentialTransaction()) ->setTransactionType($type_edge) ->setMetadataValue('edge:type', $edge_reviewer) ->setIgnoreOnNoEffect(true) ->setIsCommandeerSideEffect(true) ->setNewValue($edits); break; case DifferentialAction::ACTION_RESIGN: // If the user is resigning, add a separate reviewer edit // transaction which removes them as a reviewer. $results[] = id(new DifferentialTransaction()) ->setTransactionType($type_edge) ->setMetadataValue('edge:type', $edge_reviewer) ->setIgnoreOnNoEffect(true) ->setNewValue( array( '-' => array( $actor_phid => $actor_phid, ), )); break; } break; } if (!$this->didExpandInlineState) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: case DifferentialTransaction::TYPE_ACTION: case DifferentialTransaction::TYPE_UPDATE: case DifferentialTransaction::TYPE_INLINE: $this->didExpandInlineState = true; $actor_phid = $this->getActingAsPHID(); $actor_is_author = ($object->getAuthorPHID() == $actor_phid); if (!$actor_is_author) { break; } $state_map = PhabricatorTransactions::getInlineStateMap(); $inlines = id(new DifferentialDiffInlineCommentQuery()) ->setViewer($this->getActor()) ->withRevisionPHIDs(array($object->getPHID())) ->withFixedStates(array_keys($state_map)) ->execute(); if (!$inlines) { break; } $old_value = mpull($inlines, 'getFixedState', 'getPHID'); $new_value = array(); foreach ($old_value as $key => $state) { $new_value[$key] = $state_map[$state]; } $results[] = id(new DifferentialTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_INLINESTATE) ->setIgnoreOnNoEffect(true) ->setOldValue($old_value) ->setNewValue($new_value); break; } } return $results; } protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_ACTION: return; case DifferentialTransaction::TYPE_INLINE: $reply = $xaction->getComment()->getReplyToComment(); if ($reply && !$reply->getHasReplies()) { $reply->setHasReplies(1)->save(); } return; case DifferentialTransaction::TYPE_UPDATE: // Now that we're inside the transaction, do a final check. $diff = $this->requireDiff($xaction->getNewValue()); // TODO: It would be slightly cleaner to just revalidate this // transaction somehow using the same validation code, but that's // not easy to do at the moment. $revision_id = $diff->getRevisionID(); if ($revision_id && ($revision_id != $object->getID())) { throw new Exception( pht( 'Diff is already attached to another revision. You lost '. 'a race?')); } // TODO: This can race with diff updates, particularly those from // Harbormaster. See discussion in T8650. $diff->setRevisionID($object->getID()); $diff->save(); // Update Harbormaster to set the containerPHID correctly for any // existing buildables. We may otherwise have buildables stuck with // the old (`null`) container. // TODO: This is a bit iffy, maybe we can find a cleaner approach? // In particular, this could (rarely) be overwritten by Harbormaster // workers. $table = new HarbormasterBuildable(); $conn_w = $table->establishConnection('w'); queryfx( $conn_w, 'UPDATE %T SET containerPHID = %s WHERE buildablePHID = %s', $table->getTableName(), $object->getPHID(), $diff->getPHID()); return; } return parent::applyCustomExternalTransaction($object, $xaction); } protected function applyBuiltinExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_INLINESTATE: $table = new DifferentialTransactionComment(); $conn_w = $table->establishConnection('w'); foreach ($xaction->getNewValue() as $phid => $state) { queryfx( $conn_w, 'UPDATE %T SET fixedState = %s WHERE phid = %s', $table->getTableName(), $state, $phid); } break; } return parent::applyBuiltinExternalTransaction($object, $xaction); } protected function mergeEdgeData($type, array $u, array $v) { $result = parent::mergeEdgeData($type, $u, $v); switch ($type) { case DifferentialRevisionHasReviewerEdgeType::EDGECONST: // When the same reviewer has their status updated by multiple // transactions, we want the strongest status to win. An example of // this is when a user adds a comment and also accepts a revision which // they are a reviewer on. The comment creates a "commented" status, // while the accept creates an "accepted" status. Since accept is // stronger, it should win and persist. $u_status = idx($u, 'status'); $v_status = idx($v, 'status'); $u_str = DifferentialReviewerStatus::getStatusStrength($u_status); $v_str = DifferentialReviewerStatus::getStatusStrength($v_status); if ($u_str > $v_str) { $result['status'] = $u_status; } else { $result['status'] = $v_status; } break; } return $result; } protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { // Load the most up-to-date version of the revision and its reviewers, // so we don't need to try to deduce the state of reviewers by examining // all the changes made by the transactions. Then, update the reviewers // on the object to make sure we're acting on the current reviewer set // (and, for example, sending mail to the right people). $new_revision = id(new DifferentialRevisionQuery()) ->setViewer($this->getActor()) ->needReviewerStatus(true) ->needActiveDiffs(true) ->withIDs(array($object->getID())) ->executeOne(); if (!$new_revision) { throw new Exception( pht('Failed to load revision from transaction finalization.')); } $object->attachReviewerStatus($new_revision->getReviewerStatus()); $object->attachActiveDiff($new_revision->getActiveDiff()); $object->attachRepository($new_revision->getRepository()); foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_UPDATE: $diff = $this->requireDiff($xaction->getNewValue(), true); // Update these denormalized index tables when we attach a new // diff to a revision. $this->updateRevisionHashTable($object, $diff); $this->updateAffectedPathTable($object, $diff); break; } } $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED; $status_revision = ArcanistDifferentialRevisionStatus::NEEDS_REVISION; $status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW; $old_status = $object->getStatus(); switch ($old_status) { case $status_accepted: case $status_revision: case $status_review: // Try to move a revision to "accepted". We look for: // // - at least one accepting reviewer who is a user; and // - no rejects; and // - no rejects of older diffs; and // - no blocking reviewers. $has_accepting_user = false; $has_rejecting_reviewer = false; $has_rejecting_older_reviewer = false; $has_blocking_reviewer = false; foreach ($object->getReviewerStatus() as $reviewer) { $reviewer_status = $reviewer->getStatus(); switch ($reviewer_status) { case DifferentialReviewerStatus::STATUS_REJECTED: $has_rejecting_reviewer = true; break; case DifferentialReviewerStatus::STATUS_REJECTED_OLDER: $has_rejecting_older_reviewer = true; break; case DifferentialReviewerStatus::STATUS_BLOCKING: $has_blocking_reviewer = true; break; case DifferentialReviewerStatus::STATUS_ACCEPTED: if ($reviewer->isUser()) { $has_accepting_user = true; } break; } } $new_status = null; if ($has_accepting_user && !$has_rejecting_reviewer && !$has_rejecting_older_reviewer && !$has_blocking_reviewer) { $new_status = $status_accepted; } else if ($has_rejecting_reviewer) { // This isn't accepted, and there's at least one rejecting reviewer, // so the revision needs changes. This usually happens after a // "reject". $new_status = $status_revision; } else if ($old_status == $status_accepted) { // This revision was accepted, but it no longer satisfies the // conditions for acceptance. This usually happens after an accepting // reviewer resigns or is removed. $new_status = $status_review; } if ($new_status !== null && ($new_status != $old_status)) { $xaction = id(new DifferentialTransaction()) ->setTransactionType(DifferentialTransaction::TYPE_STATUS) ->setOldValue($old_status) ->setNewValue($new_status); $xaction = $this->populateTransaction($object, $xaction)->save(); $xactions[] = $xaction; $object->setStatus($new_status)->save(); } break; default: // Revisions can't transition out of other statuses (like closed or // abandoned) as a side effect of reviewer status changes. break; } return $xactions; } protected function validateTransaction( PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); $config_self_accept_key = 'differential.allow-self-accept'; $allow_self_accept = PhabricatorEnv::getEnvConfig($config_self_accept_key); foreach ($xactions as $xaction) { switch ($type) { case PhabricatorTransactions::TYPE_EDGE: switch ($xaction->getMetadataValue('edge:type')) { case DifferentialRevisionHasReviewerEdgeType::EDGECONST: // Prevent the author from becoming a reviewer. // NOTE: This is pretty gross, but this restriction is unusual. // If we end up with too much more of this, we should try to clean // this up -- maybe by moving validation to after transactions // are adjusted (so we can just examine the final value) or adding // a second phase there? $author_phid = $object->getAuthorPHID(); $new = $xaction->getNewValue(); $add = idx($new, '+', array()); $eq = idx($new, '=', array()); $phids = array_keys($add + $eq); foreach ($phids as $phid) { if (($phid == $author_phid) && !$allow_self_accept && !$xaction->getIsCommandeerSideEffect()) { $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), pht('The author of a revision can not be a reviewer.'), $xaction); } } break; } break; case DifferentialTransaction::TYPE_UPDATE: $diff = $this->loadDiff($xaction->getNewValue()); if (!$diff) { $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), pht('The specified diff does not exist.'), $xaction); } else if (($diff->getRevisionID()) && ($diff->getRevisionID() != $object->getID())) { $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), pht( 'You can not update this revision to the specified diff, '. 'because the diff is already attached to another revision.'), $xaction); } break; case DifferentialTransaction::TYPE_ACTION: $error = $this->validateDifferentialAction( $object, $type, $xaction, $xaction->getNewValue()); if ($error) { $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), $error, $xaction); } break; } } return $errors; } private function validateDifferentialAction( DifferentialRevision $revision, $type, DifferentialTransaction $xaction, $action) { $author_phid = $revision->getAuthorPHID(); $actor_phid = $this->getActingAsPHID(); $actor_is_author = ($author_phid == $actor_phid); $config_abandon_key = 'differential.always-allow-abandon'; $always_allow_abandon = PhabricatorEnv::getEnvConfig($config_abandon_key); $config_close_key = 'differential.always-allow-close'; $always_allow_close = PhabricatorEnv::getEnvConfig($config_close_key); $config_reopen_key = 'differential.allow-reopen'; $allow_reopen = PhabricatorEnv::getEnvConfig($config_reopen_key); $config_self_accept_key = 'differential.allow-self-accept'; $allow_self_accept = PhabricatorEnv::getEnvConfig($config_self_accept_key); $revision_status = $revision->getStatus(); $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED; $status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED; $status_closed = ArcanistDifferentialRevisionStatus::CLOSED; switch ($action) { case DifferentialAction::ACTION_ACCEPT: if ($actor_is_author && !$allow_self_accept) { return pht( 'You can not accept this revision because you are the owner.'); } if ($revision_status == $status_abandoned) { return pht( 'You can not accept this revision because it has been '. 'abandoned.'); } if ($revision_status == $status_closed) { return pht( 'You can not accept this revision because it has already been '. 'closed.'); } // TODO: It would be nice to make this generic at some point. $signatures = DifferentialRequiredSignaturesField::loadForRevision( $revision); foreach ($signatures as $phid => $signed) { if (!$signed) { return pht( 'You can not accept this revision because the author has '. 'not signed all of the required legal documents.'); } } break; case DifferentialAction::ACTION_REJECT: if ($actor_is_author) { return pht('You can not request changes to your own revision.'); } if ($revision_status == $status_abandoned) { return pht( 'You can not request changes to this revision because it has been '. 'abandoned.'); } if ($revision_status == $status_closed) { return pht( 'You can not request changes to this revision because it has '. 'already been closed.'); } break; case DifferentialAction::ACTION_RESIGN: // You can always resign from a revision if you're a reviewer. If you // aren't, this is a no-op rather than invalid. break; case DifferentialAction::ACTION_CLAIM: // You can claim a revision if you're not the owner. If you are, this // is a no-op rather than invalid. if ($revision_status == $status_closed) { return pht( 'You can not commandeer this revision because it has already been '. 'closed.'); } break; case DifferentialAction::ACTION_ABANDON: if (!$actor_is_author && !$always_allow_abandon) { return pht( 'You can not abandon this revision because you do not own it. '. 'You can only abandon revisions you own.'); } if ($revision_status == $status_closed) { return pht( 'You can not abandon this revision because it has already been '. 'closed.'); } // NOTE: Abandons of already-abandoned revisions are treated as no-op // instead of invalid. Other abandons are OK. break; case DifferentialAction::ACTION_RECLAIM: if (!$actor_is_author) { return pht( 'You can not reclaim this revision because you do not own '. 'it. You can only reclaim revisions you own.'); } if ($revision_status == $status_closed) { return pht( 'You can not reclaim this revision because it has already been '. 'closed.'); } // NOTE: Reclaims of other non-abandoned revisions are treated as no-op // instead of invalid. break; case DifferentialAction::ACTION_REOPEN: if (!$allow_reopen) { return pht( 'The reopen action is not enabled on this Phabricator install. '. 'Adjust your configuration to enable it.'); } // NOTE: If the revision is not closed, this is caught as a no-op // instead of an invalid transaction. break; case DifferentialAction::ACTION_RETHINK: if (!$actor_is_author) { return pht( 'You can not plan changes to this revision because you do not '. 'own it. To plan changes to a revision, you must be its owner.'); } switch ($revision_status) { case ArcanistDifferentialRevisionStatus::ACCEPTED: case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: // These are OK. break; case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED: // Let this through, it's a no-op. break; case ArcanistDifferentialRevisionStatus::ABANDONED: return pht( 'You can not plan changes to this revision because it has '. 'been abandoned.'); case ArcanistDifferentialRevisionStatus::CLOSED: return pht( 'You can not plan changes to this revision because it has '. 'already been closed.'); default: throw new Exception( pht( 'Encountered unexpected revision status ("%s") when '. 'validating "%s" action.', $revision_status, $action)); } break; case DifferentialAction::ACTION_REQUEST: if (!$actor_is_author) { return pht( 'You can not request review of this revision because you do '. 'not own it. To request review of a revision, you must be its '. 'owner.'); } switch ($revision_status) { case ArcanistDifferentialRevisionStatus::ACCEPTED: case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED: // These are OK. break; case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: // This will be caught as "no effect" later on. break; case ArcanistDifferentialRevisionStatus::ABANDONED: return pht( 'You can not request review of this revision because it has '. 'been abandoned. Instead, reclaim it.'); case ArcanistDifferentialRevisionStatus::CLOSED: return pht( 'You can not request review of this revision because it has '. 'already been closed.'); default: throw new Exception( pht( 'Encountered unexpected revision status ("%s") when '. 'validating "%s" action.', $revision_status, $action)); } break; case DifferentialAction::ACTION_CLOSE: // We force revisions closed when we discover a corresponding commit. // In this case, revisions are allowed to transition to closed from // any state. This is an automated action taken by the daemons. if (!$this->getIsCloseByCommit()) { if (!$actor_is_author && !$always_allow_close) { return pht( 'You can not close this revision because you do not own it. To '. 'close a revision, you must be its owner.'); } if ($revision_status != $status_accepted) { return pht( 'You can not close this revision because it has not been '. 'accepted. You can only close accepted revisions.'); } } break; } return null; } protected function sortTransactions(array $xactions) { $xactions = parent::sortTransactions($xactions); $head = array(); $tail = array(); foreach ($xactions as $xaction) { $type = $xaction->getTransactionType(); if ($type == DifferentialTransaction::TYPE_INLINE) { $tail[] = $xaction; } else { $head[] = $xaction; } } return array_values(array_merge($head, $tail)); } protected function requireCapabilities( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) {} return parent::requireCapabilities($object, $xaction); } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function getMailTo(PhabricatorLiskDAO $object) { $phids = array(); $phids[] = $object->getAuthorPHID(); foreach ($object->getReviewerStatus() as $reviewer) { $phids[] = $reviewer->getReviewerPHID(); } return $phids; } protected function getMailAction( PhabricatorLiskDAO $object, array $xactions) { $action = parent::getMailAction($object, $xactions); $strongest = $this->getStrongestAction($object, $xactions); switch ($strongest->getTransactionType()) { case DifferentialTransaction::TYPE_UPDATE: $count = new PhutilNumber($object->getLineCount()); $action = pht('%s, %s line(s)', $action, $count); break; } return $action; } protected function getMailSubjectPrefix() { return PhabricatorEnv::getEnvConfig('metamta.differential.subject-prefix'); } protected function getMailThreadID(PhabricatorLiskDAO $object) { // This is nonstandard, but retains threading with older messages. $phid = $object->getPHID(); return "differential-rev-{$phid}-req"; } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new DifferentialReplyHandler()) ->setMailReceiver($object); } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $id = $object->getID(); $title = $object->getTitle(); $original_title = $object->getOriginalTitle(); $subject = "D{$id}: {$title}"; $thread_topic = "D{$id}: {$original_title}"; return id(new PhabricatorMetaMTAMail()) ->setSubject($subject) ->addHeader('Thread-Topic', $thread_topic); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $body = new PhabricatorMetaMTAMailBody(); $body->setViewer($this->requireActor()); $revision_uri = PhabricatorEnv::getProductionURI('/D'.$object->getID()); $this->addHeadersAndCommentsToMailBody( $body, $xactions, pht('View Revision'), $revision_uri); $type_inline = DifferentialTransaction::TYPE_INLINE; $inlines = array(); foreach ($xactions as $xaction) { if ($xaction->getTransactionType() == $type_inline) { $inlines[] = $xaction; } } if ($inlines) { $this->appendInlineCommentsForMail($object, $inlines, $body); } $changed_uri = $this->getChangedPriorToCommitURI(); if ($changed_uri) { $body->addLinkSection( pht('CHANGED PRIOR TO COMMIT'), $changed_uri); } $this->addCustomFieldsToMailBody($body, $object, $xactions); $body->addLinkSection( pht('REVISION DETAIL'), $revision_uri); $update_xaction = null; foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_UPDATE: $update_xaction = $xaction; break; } } if ($update_xaction) { $diff = $this->requireDiff($update_xaction->getNewValue(), true); $body->addTextSection( pht('AFFECTED FILES'), $this->renderAffectedFilesForMail($diff)); $config_key_inline = 'metamta.differential.inline-patches'; $config_inline = PhabricatorEnv::getEnvConfig($config_key_inline); $config_key_attach = 'metamta.differential.attach-patches'; $config_attach = PhabricatorEnv::getEnvConfig($config_key_attach); if ($config_inline || $config_attach) { - $patch = $this->buildPatchForMail($diff); - $lines = substr_count($patch, "\n"); + $body_limit = PhabricatorEnv::getEnvConfig('metamta.email-body-limit'); - if ($config_inline && ($lines <= $config_inline)) { - $this->appendChangeDetailsForMail($object, $diff, $patch, $body); + $patch = $this->buildPatchForMail($diff); + if ($config_inline) { + $lines = substr_count($patch, "\n"); + $bytes = strlen($patch); + + // Limit the patch size to the smaller of 256 bytes per line or + // the mail body limit. This prevents degenerate behavior for patches + // with one line that is 10MB long. See T11748. + $byte_limits = array(); + $byte_limits[] = (256 * $config_inline); + $byte_limits[] = $body_limit; + $byte_limit = min($byte_limits); + + $lines_ok = ($lines <= $config_inline); + $bytes_ok = ($bytes <= $byte_limit); + + if ($lines_ok && $bytes_ok) { + $this->appendChangeDetailsForMail($object, $diff, $patch, $body); + } else { + // TODO: Provide a helpful message about the patch being too + // large or lengthy here. + } } if ($config_attach) { $name = pht('D%s.%s.patch', $object->getID(), $diff->getID()); $mime_type = 'text/x-patch; charset=utf-8'; $body->addAttachment( new PhabricatorMetaMTAAttachment($patch, $name, $mime_type)); } } } return $body; } public function getMailTagsMap() { return array( DifferentialTransaction::MAILTAG_REVIEW_REQUEST => pht('A revision is created.'), DifferentialTransaction::MAILTAG_UPDATED => pht('A revision is updated.'), DifferentialTransaction::MAILTAG_COMMENT => pht('Someone comments on a revision.'), DifferentialTransaction::MAILTAG_CLOSED => pht('A revision is closed.'), DifferentialTransaction::MAILTAG_REVIEWERS => pht("A revision's reviewers change."), DifferentialTransaction::MAILTAG_CC => pht("A revision's CCs change."), DifferentialTransaction::MAILTAG_OTHER => pht('Other revision activity not listed above occurs.'), ); } protected function supportsSearch() { return true; } protected function expandCustomRemarkupBlockTransactions( PhabricatorLiskDAO $object, array $xactions, array $changes, PhutilMarkupEngine $engine) { $flat_blocks = mpull($changes, 'getNewValue'); $huge_block = implode("\n\n", $flat_blocks); $task_map = array(); $task_refs = id(new ManiphestCustomFieldStatusParser()) ->parseCorpus($huge_block); foreach ($task_refs as $match) { foreach ($match['monograms'] as $monogram) { $task_id = (int)trim($monogram, 'tT'); $task_map[$task_id] = true; } } $rev_map = array(); $rev_refs = id(new DifferentialCustomFieldDependsOnParser()) ->parseCorpus($huge_block); foreach ($rev_refs as $match) { foreach ($match['monograms'] as $monogram) { $rev_id = (int)trim($monogram, 'dD'); $rev_map[$rev_id] = true; } } $edges = array(); $task_phids = array(); $rev_phids = array(); if ($task_map) { $tasks = id(new ManiphestTaskQuery()) ->setViewer($this->getActor()) ->withIDs(array_keys($task_map)) ->execute(); if ($tasks) { $task_phids = mpull($tasks, 'getPHID', 'getPHID'); $edge_related = DifferentialRevisionHasTaskEdgeType::EDGECONST; $edges[$edge_related] = $task_phids; } } if ($rev_map) { $revs = id(new DifferentialRevisionQuery()) ->setViewer($this->getActor()) ->withIDs(array_keys($rev_map)) ->execute(); $rev_phids = mpull($revs, 'getPHID', 'getPHID'); // NOTE: Skip any write attempts if a user cleverly implies a revision // depends upon itself. unset($rev_phids[$object->getPHID()]); if ($revs) { $depends = DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST; $edges[$depends] = $rev_phids; } } $this->setUnmentionablePHIDMap(array_merge($task_phids, $rev_phids)); $result = array(); foreach ($edges as $type => $specs) { $result[] = id(new DifferentialTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $type) ->setNewValue(array('+' => $specs)); } return $result; } private function appendInlineCommentsForMail( PhabricatorLiskDAO $object, array $inlines, PhabricatorMetaMTAMailBody $body) { $section = id(new DifferentialInlineCommentMailView()) ->setViewer($this->getActor()) ->setInlines($inlines) ->buildMailSection(); $header = pht('INLINE COMMENTS'); $section_text = "\n".$section->getPlaintext(); $style = array( 'margin: 6px 0 12px 0;', ); $section_html = phutil_tag( 'div', array( 'style' => implode(' ', $style), ), $section->getHTML()); $body->addPlaintextSection($header, $section_text, false); $body->addHTMLSection($header, $section_html); } private function appendChangeDetailsForMail( PhabricatorLiskDAO $object, DifferentialDiff $diff, $patch, PhabricatorMetaMTAMailBody $body) { $section = id(new DifferentialChangeDetailMailView()) ->setViewer($this->getActor()) ->setDiff($diff) ->setPatch($patch) ->buildMailSection(); $header = pht('CHANGE DETAILS'); $section_text = "\n".$section->getPlaintext(); $style = array( 'margin: 6px 0 12px 0;', ); $section_html = phutil_tag( 'div', array( 'style' => implode(' ', $style), ), $section->getHTML()); $body->addPlaintextSection($header, $section_text, false); $body->addHTMLSection($header, $section_html); } private function loadDiff($phid, $need_changesets = false) { $query = id(new DifferentialDiffQuery()) ->withPHIDs(array($phid)) ->setViewer($this->getActor()); if ($need_changesets) { $query->needChangesets(true); } return $query->executeOne(); } private function requireDiff($phid, $need_changesets = false) { $diff = $this->loadDiff($phid, $need_changesets); if (!$diff) { throw new Exception(pht('Diff "%s" does not exist!', $phid)); } return $diff; } /* -( Herald Integration )------------------------------------------------- */ protected function shouldApplyHeraldRules( PhabricatorLiskDAO $object, array $xactions) { if ($this->getIsNewObject()) { return true; } foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_UPDATE: if (!$this->getIsCloseByCommit()) { return true; } break; case DifferentialTransaction::TYPE_ACTION: switch ($xaction->getNewValue()) { case DifferentialAction::ACTION_CLAIM: // When users commandeer revisions, we may need to trigger // signatures or author-based rules. return true; } break; } } return parent::shouldApplyHeraldRules($object, $xactions); } protected function didApplyHeraldRules( PhabricatorLiskDAO $object, HeraldAdapter $adapter, HeraldTranscript $transcript) { $repository = $object->getRepository(); if (!$repository) { return array(); } if (!$this->affectedPaths) { return array(); } $packages = PhabricatorOwnersPackage::loadAffectedPackages( $repository, $this->affectedPaths); if (!$packages) { return array(); } // Remove packages that the revision author is an owner of. If you own // code, you don't need another owner to review it. $authority = id(new PhabricatorOwnersPackageQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs(mpull($packages, 'getPHID')) ->withAuthorityPHIDs(array($object->getAuthorPHID())) ->execute(); $authority = mpull($authority, null, 'getPHID'); foreach ($packages as $key => $package) { $package_phid = $package->getPHID(); if (isset($authority[$package_phid])) { unset($packages[$key]); continue; } } if (!$packages) { return array(); } $auto_subscribe = array(); $auto_review = array(); $auto_block = array(); foreach ($packages as $package) { switch ($package->getAutoReview()) { case PhabricatorOwnersPackage::AUTOREVIEW_SUBSCRIBE: $auto_subscribe[] = $package; break; case PhabricatorOwnersPackage::AUTOREVIEW_REVIEW: $auto_review[] = $package; break; case PhabricatorOwnersPackage::AUTOREVIEW_BLOCK: $auto_block[] = $package; break; case PhabricatorOwnersPackage::AUTOREVIEW_NONE: default: break; } } $owners_phid = id(new PhabricatorOwnersApplication()) ->getPHID(); $xactions = array(); if ($auto_subscribe) { $xactions[] = $object->getApplicationTransactionTemplate() ->setAuthorPHID($owners_phid) ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) ->setNewValue( array( '+' => mpull($auto_subscribe, 'getPHID'), )); } $specs = array( array($auto_review, false), array($auto_block, true), ); foreach ($specs as $spec) { list($reviewers, $blocking) = $spec; if (!$reviewers) { continue; } $phids = mpull($reviewers, 'getPHID'); $xaction = $this->newAutoReviewTransaction($object, $phids, $blocking); if ($xaction) { $xactions[] = $xaction; } } return $xactions; } private function newAutoReviewTransaction( PhabricatorLiskDAO $object, array $phids, $is_blocking) { // TODO: This is substantially similar to DifferentialReviewersHeraldAction // and both are needlessly complex. This logic should live in the normal // transaction application pipeline. See T10967. $reviewers = $object->getReviewerStatus(); $reviewers = mpull($reviewers, null, 'getReviewerPHID'); if ($is_blocking) { $new_status = DifferentialReviewerStatus::STATUS_BLOCKING; } else { $new_status = DifferentialReviewerStatus::STATUS_ADDED; } $new_strength = DifferentialReviewerStatus::getStatusStrength( $new_status); $current = array(); foreach ($phids as $phid) { if (!isset($reviewers[$phid])) { continue; } // If we're applying a stronger status (usually, upgrading a reviewer // into a blocking reviewer), skip this check so we apply the change. $old_strength = DifferentialReviewerStatus::getStatusStrength( $reviewers[$phid]->getStatus()); if ($old_strength <= $new_strength) { continue; } $current[] = $phid; } $phids = array_diff($phids, $current); if (!$phids) { return null; } $phids = array_fuse($phids); $value = array(); foreach ($phids as $phid) { $value[$phid] = array( 'data' => array( 'status' => $new_status, ), ); } $edgetype_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST; $owners_phid = id(new PhabricatorOwnersApplication()) ->getPHID(); return $object->getApplicationTransactionTemplate() ->setAuthorPHID($owners_phid) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $edgetype_reviewer) ->setNewValue( array( '+' => $value, )); } protected function buildHeraldAdapter( PhabricatorLiskDAO $object, array $xactions) { $revision = id(new DifferentialRevisionQuery()) ->setViewer($this->getActor()) ->withPHIDs(array($object->getPHID())) ->needActiveDiffs(true) ->needReviewerStatus(true) ->executeOne(); if (!$revision) { throw new Exception( pht('Failed to load revision for Herald adapter construction!')); } $adapter = HeraldDifferentialRevisionAdapter::newLegacyAdapter( $revision, $revision->getActiveDiff()); return $adapter; } /** * Update the table which links Differential revisions to paths they affect, * so Diffusion can efficiently find pending revisions for a given file. */ private function updateAffectedPathTable( DifferentialRevision $revision, DifferentialDiff $diff) { $repository = $revision->getRepository(); if (!$repository) { // The repository where the code lives is untracked. return; } $path_prefix = null; $local_root = $diff->getSourceControlPath(); if ($local_root) { // We're in a working copy which supports subdirectory checkouts (e.g., // SVN) so we need to figure out what prefix we should add to each path // (e.g., trunk/projects/example/) to get the absolute path from the // root of the repository. DVCS systems like Git and Mercurial are not // affected. // Normalize both paths and check if the repository root is a prefix of // the local root. If so, throw it away. Note that this correctly handles // the case where the remote path is "/". $local_root = id(new PhutilURI($local_root))->getPath(); $local_root = rtrim($local_root, '/'); $repo_root = id(new PhutilURI($repository->getRemoteURI()))->getPath(); $repo_root = rtrim($repo_root, '/'); if (!strncmp($repo_root, $local_root, strlen($repo_root))) { $path_prefix = substr($local_root, strlen($repo_root)); } } $changesets = $diff->getChangesets(); $paths = array(); foreach ($changesets as $changeset) { $paths[] = $path_prefix.'/'.$changeset->getFilename(); } // Save the affected paths; we'll use them later to query Owners. This // uses the un-expanded paths. $this->affectedPaths = $paths; // Mark this as also touching all parent paths, so you can see all pending // changes to any file within a directory. $all_paths = array(); foreach ($paths as $local) { foreach (DiffusionPathIDQuery::expandPathToRoot($local) as $path) { $all_paths[$path] = true; } } $all_paths = array_keys($all_paths); $path_ids = PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( $all_paths); $table = new DifferentialAffectedPath(); $conn_w = $table->establishConnection('w'); $sql = array(); foreach ($path_ids as $path_id) { $sql[] = qsprintf( $conn_w, '(%d, %d, %d, %d)', $repository->getID(), $path_id, time(), $revision->getID()); } queryfx( $conn_w, 'DELETE FROM %T WHERE revisionID = %d', $table->getTableName(), $revision->getID()); foreach (array_chunk($sql, 256) as $chunk) { queryfx( $conn_w, 'INSERT INTO %T (repositoryID, pathID, epoch, revisionID) VALUES %Q', $table->getTableName(), implode(', ', $chunk)); } } /** * Update the table connecting revisions to DVCS local hashes, so we can * identify revisions by commit/tree hashes. */ private function updateRevisionHashTable( DifferentialRevision $revision, DifferentialDiff $diff) { $vcs = $diff->getSourceControlSystem(); if ($vcs == DifferentialRevisionControlSystem::SVN) { // Subversion has no local commit or tree hash information, so we don't // have to do anything. return; } $property = id(new DifferentialDiffProperty())->loadOneWhere( 'diffID = %d AND name = %s', $diff->getID(), 'local:commits'); if (!$property) { return; } $hashes = array(); $data = $property->getData(); switch ($vcs) { case DifferentialRevisionControlSystem::GIT: foreach ($data as $commit) { $hashes[] = array( ArcanistDifferentialRevisionHash::HASH_GIT_COMMIT, $commit['commit'], ); $hashes[] = array( ArcanistDifferentialRevisionHash::HASH_GIT_TREE, $commit['tree'], ); } break; case DifferentialRevisionControlSystem::MERCURIAL: foreach ($data as $commit) { $hashes[] = array( ArcanistDifferentialRevisionHash::HASH_MERCURIAL_COMMIT, $commit['rev'], ); } break; } $conn_w = $revision->establishConnection('w'); $sql = array(); foreach ($hashes as $info) { list($type, $hash) = $info; $sql[] = qsprintf( $conn_w, '(%d, %s, %s)', $revision->getID(), $type, $hash); } queryfx( $conn_w, 'DELETE FROM %T WHERE revisionID = %d', ArcanistDifferentialRevisionHash::TABLE_NAME, $revision->getID()); if ($sql) { queryfx( $conn_w, 'INSERT INTO %T (revisionID, type, hash) VALUES %Q', ArcanistDifferentialRevisionHash::TABLE_NAME, implode(', ', $sql)); } } private function renderAffectedFilesForMail(DifferentialDiff $diff) { $changesets = $diff->getChangesets(); $filenames = mpull($changesets, 'getDisplayFilename'); sort($filenames); $count = count($filenames); $max = 250; if ($count > $max) { $filenames = array_slice($filenames, 0, $max); $filenames[] = pht('(%d more files...)', ($count - $max)); } return implode("\n", $filenames); } private function renderPatchHTMLForMail($patch) { return phutil_tag('pre', array('style' => 'font-family: monospace;'), $patch); } private function buildPatchForMail(DifferentialDiff $diff) { $format = PhabricatorEnv::getEnvConfig('metamta.differential.patch-format'); return id(new DifferentialRawDiffRenderer()) ->setViewer($this->getActor()) ->setFormat($format) ->setChangesets($diff->getChangesets()) ->buildPatch(); } protected function willPublish(PhabricatorLiskDAO $object, array $xactions) { // Reload to pick up the active diff and reviewer status. return id(new DifferentialRevisionQuery()) ->setViewer($this->getActor()) ->needReviewerStatus(true) ->needActiveDiffs(true) ->withIDs(array($object->getID())) ->executeOne(); } protected function getCustomWorkerState() { return array( 'changedPriorToCommitURI' => $this->changedPriorToCommitURI, ); } protected function loadCustomWorkerState(array $state) { $this->changedPriorToCommitURI = idx($state, 'changedPriorToCommitURI'); return $this; } } diff --git a/src/applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php b/src/applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php index 33b21b2ffe..754bafd850 100644 --- a/src/applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php +++ b/src/applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php @@ -1,66 +1,89 @@ setName('git-upload-pack'); $this->setArguments( array( array( 'name' => 'dir', 'wildcard' => true, ), )); } protected function executeRepositoryOperations() { $repository = $this->getRepository(); $viewer = $this->getUser(); $device = AlmanacKeys::getLiveDevice(); $skip_sync = $this->shouldSkipReadSynchronization(); + $is_proxy = $this->shouldProxy(); - if ($this->shouldProxy()) { + if ($is_proxy) { $command = $this->getProxyCommand(); if ($device) { $this->writeClusterEngineLogMessage( pht( "# Fetch received by \"%s\", forwarding to cluster host.\n", $device->getName())); } } else { $command = csprintf('git-upload-pack -- %s', $repository->getLocalPath()); if (!$skip_sync) { $cluster_engine = id(new DiffusionRepositoryClusterEngine()) ->setViewer($viewer) ->setRepository($repository) ->setLog($this) ->synchronizeWorkingCopyBeforeRead(); if ($device) { $this->writeClusterEngineLogMessage( pht( "# Cleared to fetch on cluster host \"%s\".\n", $device->getName())); } } } $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); + $pull_event = $this->newPullEvent(); + $future = id(new ExecFuture('%C', $command)) ->setEnv($this->getEnvironment()); $err = $this->newPassthruCommand() ->setIOChannel($this->getIOChannel()) ->setCommandChannelFromExecFuture($future) ->execute(); + if ($err) { + $pull_event + ->setResultType('error') + ->setResultCode($err); + } else { + $pull_event + ->setResultType('pull') + ->setResultCode(0); + } + + // TODO: Currently, when proxying, we do not write a log on the proxy. + // Perhaps we should write a "proxy log". This is not very useful for + // statistics or auditing, but could be useful for diagnostics. Marking + // the proxy logs as proxied (and recording devicePHID on all logs) would + // make differentiating between these use cases easier. + + if (!$is_proxy) { + $pull_event->save(); + } + if (!$err) { $this->waitForGitClient(); } return $err; } } diff --git a/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php index 78252fb8d9..20a6a251a7 100644 --- a/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php +++ b/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php @@ -1,263 +1,273 @@ repository) { throw new Exception(pht('Repository is not available yet!')); } return $this->repository; } private function setRepository(PhabricatorRepository $repository) { $this->repository = $repository; return $this; } public function getArgs() { return $this->args; } public function getEnvironment() { $env = array( DiffusionCommitHookEngine::ENV_USER => $this->getUser()->getUsername(), DiffusionCommitHookEngine::ENV_REMOTE_PROTOCOL => 'ssh', ); - $ssh_client = getenv('SSH_CLIENT'); - if ($ssh_client) { - // This has the format " ". Grab the IP. - $remote_address = head(explode(' ', $ssh_client)); + $remote_address = $this->getSSHRemoteAddress(); + if ($remote_address !== null) { $env[DiffusionCommitHookEngine::ENV_REMOTE_ADDRESS] = $remote_address; } return $env; } /** * Identify and load the affected repository. */ abstract protected function identifyRepository(); abstract protected function executeRepositoryOperations(); protected function getBaseRequestPath() { return $this->baseRequestPath; } protected function writeError($message) { $this->getErrorChannel()->write($message); return $this; } protected function getCurrentDeviceName() { $device = AlmanacKeys::getLiveDevice(); if ($device) { return $device->getName(); } return php_uname('n'); } protected function getTargetDeviceName() { // TODO: This should use the correct device identity. $uri = new PhutilURI($this->proxyURI); return $uri->getDomain(); } protected function shouldProxy() { return (bool)$this->proxyURI; } protected function getProxyCommand() { $uri = new PhutilURI($this->proxyURI); $username = AlmanacKeys::getClusterSSHUser(); if ($username === null) { throw new Exception( pht( 'Unable to determine the username to connect with when trying '. 'to proxy an SSH request within the Phabricator cluster.')); } $port = $uri->getPort(); $host = $uri->getDomain(); $key_path = AlmanacKeys::getKeyPath('device.key'); if (!Filesystem::pathExists($key_path)) { throw new Exception( pht( 'Unable to proxy this SSH request within the cluster: this device '. 'is not registered and has a missing device key (expected to '. 'find key at "%s").', $key_path)); } $options = array(); $options[] = '-o'; $options[] = 'StrictHostKeyChecking=no'; $options[] = '-o'; $options[] = 'UserKnownHostsFile=/dev/null'; // This is suppressing "added
to the list of known hosts" // messages, which are confusing and irrelevant when they arise from // proxied requests. It might also be suppressing lots of useful errors, // of course. Ideally, we would enforce host keys eventually. $options[] = '-o'; $options[] = 'LogLevel=quiet'; // NOTE: We prefix the command with "@username", which the far end of the // connection will parse in order to act as the specified user. This // behavior is only available to cluster requests signed by a trusted // device key. return csprintf( 'ssh %Ls -l %s -i %s -p %s %s -- %s %Ls', $options, $username, $key_path, $port, $host, '@'.$this->getUser()->getUsername(), $this->getOriginalArguments()); } final public function execute(PhutilArgumentParser $args) { $this->args = $args; $viewer = $this->getUser(); $have_diffusion = PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorDiffusionApplication', $viewer); if (!$have_diffusion) { throw new Exception( pht( 'You do not have permission to access the Diffusion application, '. 'so you can not interact with repositories over SSH.')); } $repository = $this->identifyRepository(); $this->setRepository($repository); $is_cluster_request = $this->getIsClusterRequest(); $uri = $repository->getAlmanacServiceURI( $viewer, $is_cluster_request, array( 'ssh', )); if ($uri) { $this->proxyURI = $uri; } try { return $this->executeRepositoryOperations(); } catch (Exception $ex) { $this->writeError(get_class($ex).': '.$ex->getMessage()); return 1; } } protected function loadRepositoryWithPath($path) { $viewer = $this->getUser(); $info = PhabricatorRepository::parseRepositoryServicePath($path); if ($info === null) { throw new Exception( pht( 'Unrecognized repository path "%s". Expected a path like "%s" '. 'or "%s".', $path, '/diffusion/X/', '/diffusion/123/')); } $identifier = $info['identifier']; $base = $info['base']; $this->baseRequestPath = $base; $repository = id(new PhabricatorRepositoryQuery()) ->setViewer($viewer) ->withIdentifiers(array($identifier)) ->needURIs(true) ->executeOne(); if (!$repository) { throw new Exception( pht('No repository "%s" exists!', $identifier)); } $protocol = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH; if (!$repository->canServeProtocol($protocol, false)) { throw new Exception( pht( 'This repository ("%s") is not available over SSH.', $repository->getDisplayName())); } return $repository; } protected function requireWriteAccess($protocol_command = null) { if ($this->hasWriteAccess === true) { return; } $repository = $this->getRepository(); $viewer = $this->getUser(); if ($viewer->isOmnipotent()) { throw new Exception( pht( 'This request is authenticated as a cluster device, but is '. 'performing a write. Writes must be performed with a real '. 'user account.')); } $protocol = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH; if ($repository->canServeProtocol($protocol, true)) { $can_push = PhabricatorPolicyFilter::hasCapability( $viewer, $repository, DiffusionPushCapability::CAPABILITY); if (!$can_push) { throw new Exception( pht('You do not have permission to push to this repository.')); } } else { if ($protocol_command !== null) { throw new Exception( pht( 'This repository is read-only over SSH (tried to execute '. 'protocol command "%s").', $protocol_command)); } else { throw new Exception( pht('This repository is read-only over SSH.')); } } $this->hasWriteAccess = true; return $this->hasWriteAccess; } protected function shouldSkipReadSynchronization() { $viewer = $this->getUser(); // Currently, the only case where devices interact over SSH without // assuming user credentials is when synchronizing before a read. These // synchronizing reads do not themselves need to be synchronized. if ($viewer->isOmnipotent()) { return true; } return false; } + protected function newPullEvent() { + $viewer = $this->getViewer(); + $repository = $this->getRepository(); + $remote_address = $this->getSSHRemoteAddress(); + + return id(new PhabricatorRepositoryPullEvent()) + ->setEpoch(PhabricatorTime::getNow()) + ->setRemoteAddress($remote_address) + ->setRemoteProtocol('ssh') + ->setPullerPHID($viewer->getPHID()) + ->setRepositoryPHID($repository->getPHID()); + } } diff --git a/src/applications/drydock/conduit/DrydockAuthorizationSearchConduitAPIMethod.php b/src/applications/drydock/conduit/DrydockAuthorizationSearchConduitAPIMethod.php new file mode 100644 index 0000000000..7c90639bcc --- /dev/null +++ b/src/applications/drydock/conduit/DrydockAuthorizationSearchConduitAPIMethod.php @@ -0,0 +1,18 @@ +blueprint = $blueprint; return $this; } public function getBlueprint() { return $this->blueprint; } public function getResultTypeDescription() { return pht('Drydock Authorizations'); } public function getApplicationClassName() { return 'PhabricatorDrydockApplication'; } public function canUseInPanelContext() { return false; } public function newQuery() { $query = new DrydockAuthorizationQuery(); $blueprint = $this->getBlueprint(); - $query->withBlueprintPHIDs(array($blueprint->getPHID())); + if ($blueprint) { + $query->withBlueprintPHIDs(array($blueprint->getPHID())); + } return $query; } protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); + if ($map['blueprintPHIDs']) { + $query->withBlueprintPHIDs($map['blueprintPHIDs']); + } + + if ($map['objectPHIDs']) { + $query->withObjectPHIDs($map['objectPHIDs']); + } + return $query; } protected function buildCustomSearchFields() { - return array(); + return array( + id(new PhabricatorSearchDatasourceField()) + ->setLabel(pht('Blueprints')) + ->setKey('blueprintPHIDs') + ->setConduitParameterType(new ConduitPHIDListParameterType()) + ->setDescription(pht('Search authorizations for specific blueprints.')) + ->setAliases(array('blueprint', 'blueprints')) + ->setDatasource(new DrydockBlueprintDatasource()), + id(new PhabricatorPHIDsSearchField()) + ->setLabel(pht('Objects')) + ->setKey('objectPHIDs') + ->setDescription(pht('Search authorizations from specific objects.')) + ->setAliases(array('object', 'objects')), + ); + } + + protected function getHiddenFields() { + return array( + 'blueprintPHIDs', + 'objectPHIDs', + ); } protected function getURI($path) { $blueprint = $this->getBlueprint(); + if (!$blueprint) { + throw new PhutilInvalidStateException('setBlueprint'); + } $id = $blueprint->getID(); return "/drydock/blueprint/{$id}/authorizations/".$path; } protected function getBuiltinQueryNames() { return array( 'all' => pht('All Authorizations'), ); } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } protected function renderResultList( array $authorizations, PhabricatorSavedQuery $query, array $handles) { $list = id(new DrydockAuthorizationListView()) ->setUser($this->requireViewer()) ->setAuthorizations($authorizations); $result = new PhabricatorApplicationSearchResultView(); $result->setTable($list); return $result; } } diff --git a/src/applications/drydock/storage/DrydockAuthorization.php b/src/applications/drydock/storage/DrydockAuthorization.php index 9503a03767..cfd186c9d3 100644 --- a/src/applications/drydock/storage/DrydockAuthorization.php +++ b/src/applications/drydock/storage/DrydockAuthorization.php @@ -1,207 +1,256 @@ true, self::CONFIG_COLUMN_SCHEMA => array( 'blueprintAuthorizationState' => 'text32', 'objectAuthorizationState' => 'text32', ), self::CONFIG_KEY_SCHEMA => array( 'key_unique' => array( 'columns' => array('objectPHID', 'blueprintPHID'), 'unique' => true, ), 'key_blueprint' => array( 'columns' => array('blueprintPHID', 'blueprintAuthorizationState'), ), 'key_object' => array( 'columns' => array('objectPHID', 'objectAuthorizationState'), ), ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( DrydockAuthorizationPHIDType::TYPECONST); } public function attachBlueprint(DrydockBlueprint $blueprint) { $this->blueprint = $blueprint; return $this; } public function getBlueprint() { return $this->assertAttached($this->blueprint); } public function attachObject($object) { $this->object = $object; return $this; } public function getObject() { return $this->assertAttached($this->object); } public static function getBlueprintStateIcon($state) { $map = array( self::BLUEPRINTAUTH_REQUESTED => 'fa-exclamation-circle pink', self::BLUEPRINTAUTH_AUTHORIZED => 'fa-check-circle green', self::BLUEPRINTAUTH_DECLINED => 'fa-times red', ); return idx($map, $state, null); } public static function getBlueprintStateName($state) { $map = array( self::BLUEPRINTAUTH_REQUESTED => pht('Requested'), self::BLUEPRINTAUTH_AUTHORIZED => pht('Authorized'), self::BLUEPRINTAUTH_DECLINED => pht('Declined'), ); return idx($map, $state, pht('', $state)); } public static function getObjectStateName($state) { $map = array( self::OBJECTAUTH_ACTIVE => pht('Active'), self::OBJECTAUTH_INACTIVE => pht('Inactive'), ); return idx($map, $state, pht('', $state)); } public function isAuthorized() { $state = $this->getBlueprintAuthorizationState(); return ($state == self::BLUEPRINTAUTH_AUTHORIZED); } /** * Apply external authorization effects after a user chagnes the value of a * blueprint selector control an object. * * @param PhabricatorUser User applying the change. * @param phid Object PHID change is being applied to. * @param list Old blueprint PHIDs. * @param list New blueprint PHIDs. * @return void */ public static function applyAuthorizationChanges( PhabricatorUser $viewer, $object_phid, array $old, array $new) { $old_phids = array_fuse($old); $new_phids = array_fuse($new); $rem_phids = array_diff_key($old_phids, $new_phids); $add_phids = array_diff_key($new_phids, $old_phids); $altered_phids = $rem_phids + $add_phids; if (!$altered_phids) { return; } $authorizations = id(new DrydockAuthorizationQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withObjectPHIDs(array($object_phid)) ->withBlueprintPHIDs($altered_phids) ->execute(); $authorizations = mpull($authorizations, null, 'getBlueprintPHID'); $state_active = self::OBJECTAUTH_ACTIVE; $state_inactive = self::OBJECTAUTH_INACTIVE; $state_requested = self::BLUEPRINTAUTH_REQUESTED; // Disable the object side of the authorization for any existing // authorizations. foreach ($rem_phids as $rem_phid) { $authorization = idx($authorizations, $rem_phid); if (!$authorization) { continue; } $authorization ->setObjectAuthorizationState($state_inactive) ->save(); } // For new authorizations, either add them or reactivate them depending // on the current state. foreach ($add_phids as $add_phid) { $needs_update = false; $authorization = idx($authorizations, $add_phid); if (!$authorization) { $authorization = id(new DrydockAuthorization()) ->setObjectPHID($object_phid) ->setObjectAuthorizationState($state_active) ->setBlueprintPHID($add_phid) ->setBlueprintAuthorizationState($state_requested); $needs_update = true; } else { $current_state = $authorization->getObjectAuthorizationState(); if ($current_state != $state_active) { $authorization->setObjectAuthorizationState($state_active); $needs_update = true; } } if ($needs_update) { $authorization->save(); } } } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return $this->getBlueprint()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBlueprint()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( 'An authorization inherits the policies of the blueprint it '. 'authorizes access to.'); } +/* -( PhabricatorConduitResultInterface )---------------------------------- */ + + + public function getFieldSpecificationsForConduit() { + return array( + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('blueprintPHID') + ->setType('phid') + ->setDescription(pht( + 'PHID of the blueprint this request was made for.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('blueprintAuthorizationState') + ->setType('map') + ->setDescription(pht('Authorization state of this request.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('objectPHID') + ->setType('phid') + ->setDescription(pht( + 'PHID of the object which requested authorization.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('objectAuthorizationState') + ->setType('map') + ->setDescription(pht('Authorization state of the requesting object.')), + ); + } + + public function getFieldValuesForConduit() { + $blueprint_state = $this->getBlueprintAuthorizationState(); + $object_state = $this->getObjectAuthorizationState(); + return array( + 'blueprintPHID' => $this->getBlueprintPHID(), + 'blueprintAuthorizationState' => array( + 'value' => $blueprint_state, + 'name' => self::getBlueprintStateName($blueprint_state), + ), + 'objectPHID' => $this->getObjectPHID(), + 'objectAuthorizationState' => array( + 'value' => $object_state, + 'name' => self::getObjectStateName($object_state), + ), + ); + } + + public function getConduitSearchAttachments() { + return array( + ); + } + } diff --git a/src/applications/drydock/storage/DrydockBlueprint.php b/src/applications/drydock/storage/DrydockBlueprint.php index 87ea777f72..afd3b771ca 100644 --- a/src/applications/drydock/storage/DrydockBlueprint.php +++ b/src/applications/drydock/storage/DrydockBlueprint.php @@ -1,363 +1,393 @@ setViewer($actor) ->withClasses(array('PhabricatorDrydockApplication')) ->executeOne(); $view_policy = $app->getPolicy( DrydockDefaultViewCapability::CAPABILITY); $edit_policy = $app->getPolicy( DrydockDefaultEditCapability::CAPABILITY); return id(new DrydockBlueprint()) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) ->setBlueprintName('') ->setIsDisabled(0); } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'className' => 'text255', 'blueprintName' => 'sort255', 'isDisabled' => 'bool', ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( DrydockBlueprintPHIDType::TYPECONST); } public function getImplementation() { return $this->assertAttached($this->implementation); } public function attachImplementation(DrydockBlueprintImplementation $impl) { $this->implementation = $impl; return $this; } public function hasImplementation() { return ($this->implementation !== self::ATTACHABLE); } public function getDetail($key, $default = null) { return idx($this->details, $key, $default); } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } public function getFieldValue($key) { $key = "std:drydock:core:{$key}"; $fields = $this->loadCustomFields(); $field = idx($fields, $key); if (!$field) { throw new Exception( pht( 'Unknown blueprint field "%s"!', $key)); } return $field->getBlueprintFieldValue(); } private function loadCustomFields() { if ($this->fields === null) { $field_list = PhabricatorCustomField::getObjectFields( $this, PhabricatorCustomField::ROLE_VIEW); $field_list->readFieldsFromStorage($this); $this->fields = $field_list->getFields(); } return $this->fields; } public function logEvent($type, array $data = array()) { $log = id(new DrydockLog()) ->setEpoch(PhabricatorTime::getNow()) ->setType($type) ->setData($data); $log->setBlueprintPHID($this->getPHID()); return $log->save(); } public function getURI() { $id = $this->getID(); return "/drydock/blueprint/{$id}/"; } /* -( Allocating Resources )----------------------------------------------- */ /** * @task resource */ public function canEverAllocateResourceForLease(DrydockLease $lease) { return $this->getImplementation()->canEverAllocateResourceForLease( $this, $lease); } /** * @task resource */ public function canAllocateResourceForLease(DrydockLease $lease) { return $this->getImplementation()->canAllocateResourceForLease( $this, $lease); } /** * @task resource */ public function allocateResource(DrydockLease $lease) { return $this->getImplementation()->allocateResource( $this, $lease); } /** * @task resource */ public function activateResource(DrydockResource $resource) { return $this->getImplementation()->activateResource( $this, $resource); } /** * @task resource */ public function destroyResource(DrydockResource $resource) { $this->getImplementation()->destroyResource( $this, $resource); return $this; } /** * @task resource */ public function getResourceName(DrydockResource $resource) { return $this->getImplementation()->getResourceName( $this, $resource); } /* -( Acquiring Leases )--------------------------------------------------- */ /** * @task lease */ public function canAcquireLeaseOnResource( DrydockResource $resource, DrydockLease $lease) { return $this->getImplementation()->canAcquireLeaseOnResource( $this, $resource, $lease); } /** * @task lease */ public function acquireLease( DrydockResource $resource, DrydockLease $lease) { return $this->getImplementation()->acquireLease( $this, $resource, $lease); } /** * @task lease */ public function activateLease( DrydockResource $resource, DrydockLease $lease) { return $this->getImplementation()->activateLease( $this, $resource, $lease); } /** * @task lease */ public function didReleaseLease( DrydockResource $resource, DrydockLease $lease) { $this->getImplementation()->didReleaseLease( $this, $resource, $lease); return $this; } /** * @task lease */ public function destroyLease( DrydockResource $resource, DrydockLease $lease) { $this->getImplementation()->destroyLease( $this, $resource, $lease); return $this; } public function getInterface( DrydockResource $resource, DrydockLease $lease, $type) { $interface = $this->getImplementation() ->getInterface($this, $resource, $lease, $type); if (!$interface) { throw new Exception( pht( 'Unable to build resource interface of type "%s".', $type)); } return $interface; } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new DrydockBlueprintEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new DrydockBlueprintTransaction(); } public function willRenderTimeline( PhabricatorApplicationTransactionView $timeline, AphrontRequest $request) { return $timeline; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return array(); } public function getCustomFieldBaseClass() { return 'DrydockBlueprintCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } /* -( PhabricatorNgramsInterface )----------------------------------------- */ public function newNgrams() { return array( id(new DrydockBlueprintNameNgrams()) ->setValue($this->getBlueprintName()), ); } + +/* -( PhabricatorConduitResultInterface )---------------------------------- */ + + + public function getFieldSpecificationsForConduit() { + return array( + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('name') + ->setType('string') + ->setDescription(pht('The name of this blueprint.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('type') + ->setType('string') + ->setDescription(pht('The type of resource this blueprint provides.')), + ); + } + + public function getFieldValuesForConduit() { + return array( + 'name' => $this->getBlueprintName(), + 'type' => $this->getImplementation()->getType(), + ); + } + + public function getConduitSearchAttachments() { + return array( + ); + } + } diff --git a/src/applications/files/view/PhabricatorGlobalUploadTargetView.php b/src/applications/files/view/PhabricatorGlobalUploadTargetView.php index 3e0690815c..76aacbe36f 100644 --- a/src/applications/files/view/PhabricatorGlobalUploadTargetView.php +++ b/src/applications/files/view/PhabricatorGlobalUploadTargetView.php @@ -1,62 +1,106 @@ showIfSupportedID = $show_if_supported_id; return $this; } public function getShowIfSupportedID() { return $this->showIfSupportedID; } + public function setHintText($hint_text) { + $this->hintText = $hint_text; + return $this; + } + + public function getHintText() { + return $this->hintText; + } + + public function setViewPolicy($view_policy) { + $this->viewPolicy = $view_policy; + return $this; + } + + public function getViewPolicy() { + return $this->viewPolicy; + } + + public function setSubmitURI($submit_uri) { + $this->submitURI = $submit_uri; + return $this; + } + + public function getSubmitURI() { + return $this->submitURI; + } + + + public function render() { - $viewer = $this->getUser(); + $viewer = $this->getViewer(); if (!$viewer->isLoggedIn()) { return null; } $instructions_id = 'phabricator-global-drag-and-drop-upload-instructions'; require_celerity_resource('global-drag-and-drop-css'); + $hint_text = $this->getHintText(); + if (!strlen($hint_text)) { + $hint_text = "\xE2\x87\xAA ".pht('Drop Files to Upload'); + } + // Use the configured default view policy. Drag and drop uploads use // a more restrictive view policy if we don't specify a policy explicitly, // as the more restrictive policy is correct for most drop targets (like // Pholio uploads and Remarkup text areas). - $view_policy = PhabricatorFile::initializeNewFile()->getViewPolicy(); + $view_policy = $this->getViewPolicy(); + if ($view_policy === null) { + $view_policy = PhabricatorFile::initializeNewFile()->getViewPolicy(); + } + + $submit_uri = $this->getSubmitURI(); + $done_uri = '/file/query/authored/'; Javelin::initBehavior('global-drag-and-drop', array( 'ifSupported' => $this->showIfSupportedID, 'instructions' => $instructions_id, 'uploadURI' => '/file/dropupload/', - 'browseURI' => '/file/query/authored/', + 'submitURI' => $submit_uri, + 'browseURI' => $done_uri, 'viewPolicy' => $view_policy, 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(), )); return phutil_tag( 'div', array( 'id' => $instructions_id, 'class' => 'phabricator-global-upload-instructions', 'style' => 'display: none;', ), - "\xE2\x87\xAA ".pht('Drop Files to Upload')); + $hint_text); } } diff --git a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php index 54068e1e71..709558eaa2 100644 --- a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php +++ b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php @@ -1,210 +1,208 @@ getViewer(); $application = $request->getURIData('application'); $selected = id(new PhabricatorApplicationQuery()) ->setViewer($viewer) ->withClasses(array($application)) ->executeOne(); if (!$selected) { return new Aphront404Response(); } $title = $selected->getName(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($selected->getName()); $crumbs->setBorder(true); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setUser($viewer) ->setPolicyObject($selected) ->setHeaderIcon($selected->getIcon()); if ($selected->isInstalled()) { $header->setStatus('fa-check', 'bluegrey', pht('Installed')); } else { $header->setStatus('fa-ban', 'dark', pht('Uninstalled')); } $curtain = $this->buildCurtain($selected); $details = $this->buildPropertySectionView($selected); $policies = $this->buildPolicyView($selected); $configs = PhabricatorApplicationConfigurationPanel::loadAllPanelsForApplication( $selected); $panels = array(); foreach ($configs as $config) { $config->setViewer($viewer); $config->setApplication($selected); $panel = $config->buildConfigurationPagePanel(); $panel->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); $panels[] = $panel; - } $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) ->setMainColumn(array( $policies, $panels, )) ->addPropertySection(pht('Details'), $details); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild( array( $view, )); } private function buildPropertySectionView( PhabricatorApplication $application) { $viewer = $this->getViewer(); $properties = id(new PHUIPropertyListView()); $properties->addProperty( pht('Description'), $application->getShortDescription()); if ($application->getFlavorText()) { $properties->addProperty( null, phutil_tag('em', array(), $application->getFlavorText())); } if ($application->isPrototype()) { $proto_href = PhabricatorEnv::getDoclink( 'User Guide: Prototype Applications'); $learn_more = phutil_tag( 'a', array( 'href' => $proto_href, 'target' => '_blank', ), pht('Learn More')); $properties->addProperty( pht('Prototype'), pht( 'This application is a prototype. %s', $learn_more)); } $overview = $application->getOverview(); if (strlen($overview)) { $overview = new PHUIRemarkupView($viewer, $overview); $properties->addSectionHeader( pht('Overview'), PHUIPropertyListView::ICON_SUMMARY); $properties->addTextContent($overview); } return $properties; } private function buildPolicyView( PhabricatorApplication $application) { $viewer = $this->getViewer(); $properties = id(new PHUIPropertyListView()); $header = id(new PHUIHeaderView()) - ->setHeader(pht('POLICIES')) - ->setHeaderIcon('fa-lock'); + ->setHeader(pht('Policies')); $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( $viewer, $application); foreach ($application->getCapabilities() as $capability) { $properties->addProperty( $application->getCapabilityLabel($capability), idx($descriptions, $capability)); } return id(new PHUIObjectBoxView()) ->setHeader($header) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($properties); } private function buildCurtain(PhabricatorApplication $application) { $viewer = $this->getViewer(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $application, PhabricatorPolicyCapability::CAN_EDIT); $key = get_class($application); $edit_uri = $this->getApplicationURI("edit/{$key}/"); $install_uri = $this->getApplicationURI("{$key}/install/"); $uninstall_uri = $this->getApplicationURI("{$key}/uninstall/"); $curtain = $this->newCurtainView($application); $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Policies')) ->setIcon('fa-pencil') ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit) ->setHref($edit_uri)); if ($application->canUninstall()) { if ($application->isInstalled()) { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Uninstall')) ->setIcon('fa-times') ->setDisabled(!$can_edit) ->setWorkflow(true) ->setHref($uninstall_uri)); } else { $action = id(new PhabricatorActionView()) ->setName(pht('Install')) ->setIcon('fa-plus') ->setDisabled(!$can_edit) ->setWorkflow(true) ->setHref($install_uri); $prototypes_enabled = PhabricatorEnv::getEnvConfig( 'phabricator.show-prototypes'); if ($application->isPrototype() && !$prototypes_enabled) { $action->setDisabled(true); } $curtain->addAction($action); } } else { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Uninstall')) ->setIcon('fa-times') ->setWorkflow(true) ->setDisabled(true) ->setHref($uninstall_uri)); } return $curtain; } } diff --git a/src/applications/owners/controller/PhabricatorOwnersArchiveController.php b/src/applications/owners/controller/PhabricatorOwnersArchiveController.php index 2ef618a2d5..47f9d87d23 100644 --- a/src/applications/owners/controller/PhabricatorOwnersArchiveController.php +++ b/src/applications/owners/controller/PhabricatorOwnersArchiveController.php @@ -1,65 +1,66 @@ getViewer(); $id = $request->getURIData('id'); $package = id(new PhabricatorOwnersPackageQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$package) { return new Aphront404Response(); } $view_uri = $this->getApplicationURI('package/'.$package->getID().'/'); if ($request->isFormPost()) { if ($package->isArchived()) { $new_status = PhabricatorOwnersPackage::STATUS_ACTIVE; } else { $new_status = PhabricatorOwnersPackage::STATUS_ARCHIVED; } $xactions = array(); + $type = PhabricatorOwnersPackageStatusTransaction::TRANSACTIONTYPE; $xactions[] = id(new PhabricatorOwnersPackageTransaction()) - ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_STATUS) + ->setTransactionType($type) ->setNewValue($new_status); id(new PhabricatorOwnersPackageTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) ->applyTransactions($package, $xactions); return id(new AphrontRedirectResponse())->setURI($view_uri); } if ($package->isArchived()) { $title = pht('Activate Package'); $body = pht('This package will become active again.'); $button = pht('Activate Package'); } else { $title = pht('Archive Package'); $body = pht('This package will be marked as archived.'); $button = pht('Archive Package'); } return $this->newDialog() ->setTitle($title) ->appendChild($body) ->addCancelButton($view_uri) ->addSubmitButton($button); } } diff --git a/src/applications/owners/controller/PhabricatorOwnersPathsController.php b/src/applications/owners/controller/PhabricatorOwnersPathsController.php index 7f911d29d9..b69faf5648 100644 --- a/src/applications/owners/controller/PhabricatorOwnersPathsController.php +++ b/src/applications/owners/controller/PhabricatorOwnersPathsController.php @@ -1,177 +1,177 @@ getUser(); $package = id(new PhabricatorOwnersPackageQuery()) ->setViewer($viewer) ->withIDs(array($request->getURIData('id'))) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->needPaths(true) ->executeOne(); if (!$package) { return new Aphront404Response(); } if ($request->isFormPost()) { $paths = $request->getArr('path'); $repos = $request->getArr('repo'); $excludes = $request->getArr('exclude'); $path_refs = array(); foreach ($paths as $key => $path) { if (!isset($repos[$key])) { throw new Exception( pht( 'No repository PHID for path "%s"!', $key)); } if (!isset($excludes[$key])) { throw new Exception( pht( 'No exclusion value for path "%s"!', $key)); } $path_refs[] = array( 'repositoryPHID' => $repos[$key], 'path' => $path, 'excluded' => (int)$excludes[$key], ); } - $type_paths = PhabricatorOwnersPackageTransaction::TYPE_PATHS; + $type_paths = PhabricatorOwnersPackagePathsTransaction::TRANSACTIONTYPE; $xactions = array(); $xactions[] = id(new PhabricatorOwnersPackageTransaction()) ->setTransactionType($type_paths) ->setNewValue($path_refs); $editor = id(new PhabricatorOwnersPackageTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true); $editor->applyTransactions($package, $xactions); return id(new AphrontRedirectResponse()) ->setURI($package->getURI()); } else { $paths = $package->getPaths(); $path_refs = mpull($paths, 'getRef'); } $repos = id(new PhabricatorRepositoryQuery()) ->setViewer($viewer) ->execute(); $default_paths = array(); foreach ($repos as $repo) { $default_path = $repo->getDetail('default-owners-path'); if ($default_path) { $default_paths[$repo->getPHID()] = $default_path; } } $repo_map = array(); foreach ($repos as $key => $repo) { $monogram = $repo->getMonogram(); $name = $repo->getName(); $repo_map[$repo->getPHID()] = "{$monogram} {$name}"; } asort($repos); $template = new AphrontTypeaheadTemplateView(); $template = $template->render(); Javelin::initBehavior( 'owners-path-editor', array( 'root' => 'path-editor', 'table' => 'paths', 'add_button' => 'addpath', 'repositories' => $repo_map, 'input_template' => $template, 'pathRefs' => $path_refs, 'completeURI' => '/diffusion/services/path/complete/', 'validateURI' => '/diffusion/services/path/validate/', 'repositoryDefaultPaths' => $default_paths, )); require_celerity_resource('owners-path-editor-css'); $cancel_uri = $package->getURI(); $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new PHUIFormInsetView()) ->setTitle(pht('Paths')) ->addDivAttributes(array('id' => 'path-editor')) ->setRightButton(javelin_tag( 'a', array( 'href' => '#', 'class' => 'button green', 'sigil' => 'addpath', 'mustcapture' => true, ), pht('Add New Path'))) ->setDescription( pht( 'Specify the files and directories which comprise '. 'this package.')) ->setContent(javelin_tag( 'table', array( 'class' => 'owners-path-editor-table', 'sigil' => 'paths', ), ''))) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue(pht('Save Paths'))); $box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Paths')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb( $package->getName(), $this->getApplicationURI('package/'.$package->getID().'/')); $crumbs->addTextCrumb(pht('Edit Paths')); $crumbs->setBorder(true); $header = id(new PHUIHeaderView()) ->setHeader(pht('Edit Paths: %s', $package->getName())) ->setHeaderIcon('fa-pencil'); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setFooter($box); $title = array($package->getName(), pht('Edit Paths')); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild($view); } } diff --git a/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php b/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php index b20613c92e..4adaebc582 100644 --- a/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php +++ b/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php @@ -1,174 +1,179 @@ getViewer()); } protected function newObjectQuery() { return id(new PhabricatorOwnersPackageQuery()) ->needPaths(true); } protected function getObjectCreateTitleText($object) { return pht('Create New Package'); } protected function getObjectEditTitleText($object) { return pht('Edit Package: %s', $object->getName()); } protected function getObjectEditShortText($object) { return pht('Package %d', $object->getID()); } protected function getObjectCreateShortText() { return pht('Create Package'); } protected function getObjectName() { return pht('Package'); } protected function getObjectViewURI($object) { return $object->getURI(); } protected function buildCustomEditFields($object) { $paths_help = pht(<<setKey('name') ->setLabel(pht('Name')) ->setDescription(pht('Name of the package.')) - ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_NAME) + ->setTransactionType( + PhabricatorOwnersPackageNameTransaction::TRANSACTIONTYPE) ->setIsRequired(true) ->setValue($object->getName()), id(new PhabricatorDatasourceEditField()) ->setKey('owners') ->setLabel(pht('Owners')) ->setDescription(pht('Users and projects which own the package.')) - ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_OWNERS) + ->setTransactionType( + PhabricatorOwnersPackageOwnersTransaction::TRANSACTIONTYPE) ->setDatasource(new PhabricatorProjectOrUserDatasource()) ->setIsCopyable(true) ->setValue($object->getOwnerPHIDs()), id(new PhabricatorSelectEditField()) ->setKey('dominion') ->setLabel(pht('Dominion')) ->setDescription( pht('Change package dominion rules.')) ->setTransactionType( - PhabricatorOwnersPackageTransaction::TYPE_DOMINION) + PhabricatorOwnersPackageDominionTransaction::TRANSACTIONTYPE) ->setIsCopyable(true) ->setValue($object->getDominion()) ->setOptions($dominion_map), id(new PhabricatorSelectEditField()) ->setKey('autoReview') ->setLabel(pht('Auto Review')) ->setDescription( pht( 'Automatically trigger reviews for commits affecting files in '. 'this package.')) ->setTransactionType( - PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW) + PhabricatorOwnersPackageAutoreviewTransaction::TRANSACTIONTYPE) ->setIsCopyable(true) ->setValue($object->getAutoReview()) ->setOptions($autoreview_map), id(new PhabricatorSelectEditField()) ->setKey('auditing') ->setLabel(pht('Auditing')) ->setDescription( pht( 'Automatically trigger audits for commits affecting files in '. 'this package.')) - ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_AUDITING) + ->setTransactionType( + PhabricatorOwnersPackageAuditingTransaction::TRANSACTIONTYPE) ->setIsCopyable(true) ->setValue($object->getAuditingEnabled()) ->setOptions( array( '' => pht('Disabled'), '1' => pht('Enabled'), )), id(new PhabricatorRemarkupEditField()) ->setKey('description') ->setLabel(pht('Description')) ->setDescription(pht('Human-readable description of the package.')) ->setTransactionType( - PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION) + PhabricatorOwnersPackageDescriptionTransaction::TRANSACTIONTYPE) ->setValue($object->getDescription()), id(new PhabricatorSelectEditField()) ->setKey('status') ->setLabel(pht('Status')) ->setDescription(pht('Archive or enable the package.')) - ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_STATUS) + ->setTransactionType( + PhabricatorOwnersPackageStatusTransaction::TRANSACTIONTYPE) ->setIsConduitOnly(true) ->setValue($object->getStatus()) ->setOptions($object->getStatusNameMap()), id(new PhabricatorConduitEditField()) ->setKey('paths.set') ->setLabel(pht('Paths')) ->setIsConduitOnly(true) - ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_PATHS) + ->setTransactionType( + PhabricatorOwnersPackagePathsTransaction::TRANSACTIONTYPE) ->setConduitDescription( pht('Overwrite existing package paths with new paths.')) ->setConduitTypeDescription( pht('List of dictionaries, each describing a path.')) ->setConduitDocumentation($paths_help), ); } } diff --git a/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php b/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php index 5fb4a9af8a..40657abd57 100644 --- a/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php +++ b/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php @@ -1,418 +1,76 @@ getTransactionType()) { - case PhabricatorOwnersPackageTransaction::TYPE_NAME: - return $object->getName(); - case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: - $phids = mpull($object->getOwners(), 'getUserPHID'); - $phids = array_values($phids); - return $phids; - case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: - return (int)$object->getAuditingEnabled(); - case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: - return $object->getDescription(); - case PhabricatorOwnersPackageTransaction::TYPE_PATHS: - $paths = $object->getPaths(); - return mpull($paths, 'getRef'); - case PhabricatorOwnersPackageTransaction::TYPE_STATUS: - return $object->getStatus(); - case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW: - return $object->getAutoReview(); - case PhabricatorOwnersPackageTransaction::TYPE_DOMINION: - return $object->getDominion(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorOwnersPackageTransaction::TYPE_NAME: - case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: - case PhabricatorOwnersPackageTransaction::TYPE_STATUS: - case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW: - case PhabricatorOwnersPackageTransaction::TYPE_DOMINION: - return $xaction->getNewValue(); - case PhabricatorOwnersPackageTransaction::TYPE_PATHS: - $new = $xaction->getNewValue(); - foreach ($new as $key => $info) { - $new[$key]['excluded'] = (int)idx($info, 'excluded'); - } - return $new; - case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: - return (int)$xaction->getNewValue(); - case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: - $phids = $xaction->getNewValue(); - $phids = array_unique($phids); - $phids = array_values($phids); - return $phids; - } - } - - protected function transactionHasEffect( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorOwnersPackageTransaction::TYPE_PATHS: - $old = $xaction->getOldValue(); - $new = $xaction->getNewValue(); - - $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); - list($rem, $add) = $diffs; - - return ($rem || $add); - } - - return parent::transactionHasEffect($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorOwnersPackageTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - return; - case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: - $object->setDescription($xaction->getNewValue()); - return; - case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: - $object->setAuditingEnabled($xaction->getNewValue()); - return; - case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: - case PhabricatorOwnersPackageTransaction::TYPE_PATHS: - return; - case PhabricatorOwnersPackageTransaction::TYPE_STATUS: - $object->setStatus($xaction->getNewValue()); - return; - case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW: - $object->setAutoReview($xaction->getNewValue()); - return; - case PhabricatorOwnersPackageTransaction::TYPE_DOMINION: - $object->setDominion($xaction->getNewValue()); - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorOwnersPackageTransaction::TYPE_NAME: - case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: - case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: - case PhabricatorOwnersPackageTransaction::TYPE_STATUS: - case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW: - case PhabricatorOwnersPackageTransaction::TYPE_DOMINION: - return; - case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: - $old = $xaction->getOldValue(); - $new = $xaction->getNewValue(); - - $owners = $object->getOwners(); - $owners = mpull($owners, null, 'getUserPHID'); - - $rem = array_diff($old, $new); - foreach ($rem as $phid) { - if (isset($owners[$phid])) { - $owners[$phid]->delete(); - unset($owners[$phid]); - } - } - - $add = array_diff($new, $old); - foreach ($add as $phid) { - $owners[$phid] = id(new PhabricatorOwnersOwner()) - ->setPackageID($object->getID()) - ->setUserPHID($phid) - ->save(); - } - - // TODO: Attach owners here - return; - case PhabricatorOwnersPackageTransaction::TYPE_PATHS: - $old = $xaction->getOldValue(); - $new = $xaction->getNewValue(); - - $paths = $object->getPaths(); - - $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); - list($rem, $add) = $diffs; - - $set = PhabricatorOwnersPath::getSetFromTransactionValue($rem); - foreach ($paths as $path) { - $ref = $path->getRef(); - if (PhabricatorOwnersPath::isRefInSet($ref, $set)) { - $path->delete(); - } - } - - foreach ($add as $ref) { - $path = PhabricatorOwnersPath::newFromRef($ref) - ->setPackageID($object->getID()) - ->save(); - } - - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case PhabricatorOwnersPackageTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Package name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - - foreach ($xactions as $xaction) { - $new = $xaction->getNewValue(); - if (preg_match('([,!])', $new)) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Package names may not contain commas (",") or exclamation '. - 'marks ("!"). These characters are ambiguous when package '. - 'names are parsed from the command line.'), - $xaction); - } - } - - break; - case PhabricatorOwnersPackageTransaction::TYPE_AUTOREVIEW: - $map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); - foreach ($xactions as $xaction) { - $new = $xaction->getNewValue(); - - if (empty($map[$new])) { - $valid = array_keys($map); - - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Autoreview setting "%s" is not valid. '. - 'Valid settings are: %s.', - $new, - implode(', ', $valid)), - $xaction); - } - } - break; - case PhabricatorOwnersPackageTransaction::TYPE_DOMINION: - $map = PhabricatorOwnersPackage::getDominionOptionsMap(); - foreach ($xactions as $xaction) { - $new = $xaction->getNewValue(); - - if (empty($map[$new])) { - $valid = array_keys($map); - - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Dominion setting "%s" is not valid. '. - 'Valid settings are: %s.', - $new, - implode(', ', $valid)), - $xaction); - } - } - break; - case PhabricatorOwnersPackageTransaction::TYPE_PATHS: - if (!$xactions) { - continue; - } - - $old = mpull($object->getPaths(), 'getRef'); - foreach ($xactions as $xaction) { - $new = $xaction->getNewValue(); - - // Check that we have a list of paths. - if (!is_array($new)) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht('Path specification must be a list of paths.'), - $xaction); - continue; - } - - // Check that each item in the list is formatted properly. - $type_exception = null; - foreach ($new as $key => $value) { - try { - PhutilTypeSpec::checkMap( - $value, - array( - 'repositoryPHID' => 'string', - 'path' => 'string', - 'excluded' => 'optional wild', - )); - } catch (PhutilTypeCheckException $ex) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Path specification list contains invalid value '. - 'in key "%s": %s.', - $key, - $ex->getMessage()), - $xaction); - $type_exception = $ex; - } - } - - if ($type_exception) { - continue; - } - - // Check that any new paths reference legitimate repositories which - // the viewer has permission to see. - list($rem, $add) = PhabricatorOwnersPath::getTransactionValueChanges( - $old, - $new); - - if ($add) { - $repository_phids = ipull($add, 'repositoryPHID'); - - $repositories = id(new PhabricatorRepositoryQuery()) - ->setViewer($this->getActor()) - ->withPHIDs($repository_phids) - ->execute(); - $repositories = mpull($repositories, null, 'getPHID'); - - foreach ($add as $ref) { - $repository_phid = $ref['repositoryPHID']; - if (isset($repositories[$repository_phid])) { - continue; - } - - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Path specification list references repository PHID "%s", '. - 'but that is not a valid, visible repository.', - $repository_phid)); - } - } - } - break; - } - - return $errors; - } - protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function getMailSubjectPrefix() { return PhabricatorEnv::getEnvConfig('metamta.package.subject-prefix'); } protected function getMailTo(PhabricatorLiskDAO $object) { return array( $this->requireActor()->getPHID(), ); } protected function getMailCC(PhabricatorLiskDAO $object) { return mpull($object->getOwners(), 'getUserPHID'); } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new OwnersPackageReplyHandler()) ->setMailReceiver($object); } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $id = $object->getID(); $name = $object->getName(); return id(new PhabricatorMetaMTAMail()) ->setSubject($name) ->addHeader('Thread-Topic', $object->getPHID()); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $body = parent::buildMailBody($object, $xactions); $detail_uri = PhabricatorEnv::getProductionURI($object->getURI()); $body->addLinkSection( pht('PACKAGE DETAIL'), $detail_uri); return $body; } protected function supportsSearch() { return true; } } diff --git a/src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php b/src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php index 359a1fcb8a..66e15b634a 100644 --- a/src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php +++ b/src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php @@ -1,266 +1,18 @@ getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_OWNERS: - if (!is_array($old)) { - $old = array(); - } - - if (!is_array($new)) { - $new = array(); - } - - $add = array_diff($new, $old); - foreach ($add as $phid) { - $phids[] = $phid; - } - $rem = array_diff($old, $new); - foreach ($rem as $phid) { - $phids[] = $phid; - } - break; - } - - return $phids; - } - - public function shouldHide() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - if ($old === null) { - return true; - } - break; - case self::TYPE_PRIMARY: - // TODO: Eventually, remove these transactions entirely. - return true; - } - - return parent::shouldHide(); - } - - public function getTitle() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - $author_phid = $this->getAuthorPHID(); - - switch ($this->getTransactionType()) { - case PhabricatorTransactions::TYPE_CREATE: - return pht( - '%s created this package.', - $this->renderHandleLink($author_phid)); - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created this package.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s renamed this package from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - case self::TYPE_OWNERS: - $add = array_diff($new, $old); - $rem = array_diff($old, $new); - if ($add && !$rem) { - return pht( - '%s added %s owner(s): %s.', - $this->renderHandleLink($author_phid), - count($add), - $this->renderHandleList($add)); - } else if ($rem && !$add) { - return pht( - '%s removed %s owner(s): %s.', - $this->renderHandleLink($author_phid), - count($rem), - $this->renderHandleList($rem)); - } else { - return pht( - '%s changed %s package owner(s), added %s: %s; removed %s: %s.', - $this->renderHandleLink($author_phid), - count($add) + count($rem), - count($add), - $this->renderHandleList($add), - count($rem), - $this->renderHandleList($rem)); - } - case self::TYPE_AUDITING: - if ($new) { - return pht( - '%s enabled auditing for this package.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s disabled auditing for this package.', - $this->renderHandleLink($author_phid)); - } - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the description for this package.', - $this->renderHandleLink($author_phid)); - case self::TYPE_PATHS: - // TODO: Flesh this out. - return pht( - '%s updated paths for this package.', - $this->renderHandleLink($author_phid)); - case self::TYPE_STATUS: - if ($new == PhabricatorOwnersPackage::STATUS_ACTIVE) { - return pht( - '%s activated this package.', - $this->renderHandleLink($author_phid)); - } else if ($new == PhabricatorOwnersPackage::STATUS_ARCHIVED) { - return pht( - '%s archived this package.', - $this->renderHandleLink($author_phid)); - } - case self::TYPE_AUTOREVIEW: - $map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); - $map = ipull($map, 'name'); - - $old = idx($map, $old, $old); - $new = idx($map, $new, $new); - - return pht( - '%s adjusted autoreview from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - case self::TYPE_DOMINION: - $map = PhabricatorOwnersPackage::getDominionOptionsMap(); - $map = ipull($map, 'short'); - - $old = idx($map, $old, $old); - $new = idx($map, $new, $new); - - return pht( - '%s adjusted package dominion rules from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - - return parent::getTitle(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - return ($this->getOldValue() !== null); - case self::TYPE_PATHS: - return true; - } - - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - return $this->renderTextCorpusChangeDetails( - $viewer, - $old, - $new); - case self::TYPE_PATHS: - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); - list($rem, $add) = $diffs; - - $rows = array(); - foreach ($rem as $ref) { - $rows[] = array( - 'class' => 'diff-removed', - 'change' => '-', - ) + $ref; - } - - foreach ($add as $ref) { - $rows[] = array( - 'class' => 'diff-added', - 'change' => '+', - ) + $ref; - } - - $rowc = array(); - foreach ($rows as $key => $row) { - $rowc[] = $row['class']; - $rows[$key] = array( - $row['change'], - $row['excluded'] ? pht('Exclude') : pht('Include'), - $viewer->renderHandle($row['repositoryPHID']), - $row['path'], - ); - } - - $table = id(new AphrontTableView($rows)) - ->setRowClasses($rowc) - ->setHeaders( - array( - null, - pht('Type'), - pht('Repository'), - pht('Path'), - )) - ->setColumnClasses( - array( - null, - null, - null, - 'wide', - )); - - return $table; - } - - return parent::renderChangeDetails($viewer); - } - - public function getRemarkupBlocks() { - $blocks = parent::getRemarkupBlocks(); - - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - $blocks[] = $this->getNewValue(); - break; - } - - return $blocks; + public function getBaseTransactionClass() { + return 'PhabricatorOwnersPackageTransactionType'; } } diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackageAuditingTransaction.php b/src/applications/owners/xaction/PhabricatorOwnersPackageAuditingTransaction.php new file mode 100644 index 0000000000..df4f0feb01 --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackageAuditingTransaction.php @@ -0,0 +1,32 @@ +getAuditingEnabled(); + } + + public function generateNewValue($object, $value) { + return (int)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setAuditingEnabled($value); + } + + public function getTitle() { + if ($this->getNewValue()) { + return pht( + '%s enabled auditing for this package.', + $this->renderAuthor()); + } else { + return pht( + '%s disabled auditing for this package.', + $this->renderAuthor()); + } + } + +} diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackageAutoreviewTransaction.php b/src/applications/owners/xaction/PhabricatorOwnersPackageAutoreviewTransaction.php new file mode 100644 index 0000000000..03ec4f7af1 --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackageAutoreviewTransaction.php @@ -0,0 +1,56 @@ +getAutoReview(); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + + if (empty($map[$new])) { + $valid = array_keys($map); + + $errors[] = $this->newInvalidError( + pht( + 'Autoreview setting "%s" is not valid. '. + 'Valid settings are: %s.', + $new, + implode(', ', $valid)), + $xaction); + } + } + + return $errors; + } + + public function applyInternalEffects($object, $value) { + $object->setAutoReview($value); + } + + public function getTitle() { + $map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); + $map = ipull($map, 'name'); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $old = idx($map, $old, $old); + $new = idx($map, $new, $new); + + return pht( + '%s adjusted autoreview from %s to %s.', + $this->renderAuthor(), + $this->renderValue($old), + $this->renderValue($new)); + } + +} diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackageDescriptionTransaction.php b/src/applications/owners/xaction/PhabricatorOwnersPackageDescriptionTransaction.php new file mode 100644 index 0000000000..8b2effe80c --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackageDescriptionTransaction.php @@ -0,0 +1,29 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function getTitle() { + return pht( + '%s updated the description for this package.', + $this->renderAuthor()); + } + + public function newChangeDetailView() { + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($this->getViewer()) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + +} diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackageDominionTransaction.php b/src/applications/owners/xaction/PhabricatorOwnersPackageDominionTransaction.php new file mode 100644 index 0000000000..0c1ff0a916 --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackageDominionTransaction.php @@ -0,0 +1,56 @@ +getDominion(); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $map = PhabricatorOwnersPackage::getDominionOptionsMap(); + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + + if (empty($map[$new])) { + $valid = array_keys($map); + + $errors[] = $this->newInvalidError( + pht( + 'Dominion setting "%s" is not valid. '. + 'Valid settings are: %s.', + $new, + implode(', ', $valid)), + $xaction); + } + } + + return $errors; + } + + public function applyInternalEffects($object, $value) { + $object->setDominion($value); + } + + public function getTitle() { + $map = PhabricatorOwnersPackage::getDominionOptionsMap(); + $map = ipull($map, 'short'); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $old = idx($map, $old, $old); + $new = idx($map, $new, $new); + + return pht( + '%s adjusted package dominion rules from %s to %s.', + $this->renderAuthor(), + $this->renderValue($old), + $this->renderValue($new)); + } + +} diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackageNameTransaction.php b/src/applications/owners/xaction/PhabricatorOwnersPackageNameTransaction.php new file mode 100644 index 0000000000..b4e50daec2 --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackageNameTransaction.php @@ -0,0 +1,52 @@ +getName(); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $missing = $this->isEmptyTextTransaction( + $object->getName(), + $xactions); + + if ($missing) { + $errors[] = $this->newRequiredError( + pht('Package name is required.'), + nonempty(last($xactions), null)); + } + + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + if (preg_match('([,!])', $new)) { + $errors[] = $this->newInvalidError( + pht( + 'Package names may not contain commas (",") or exclamation '. + 'marks ("!"). These characters are ambiguous when package '. + 'names are parsed from the command line.'), + $xaction); + } + } + + return $errors; + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + return pht( + '%s renamed this package from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + +} diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackageOwnersTransaction.php b/src/applications/owners/xaction/PhabricatorOwnersPackageOwnersTransaction.php new file mode 100644 index 0000000000..7fef0d5e6c --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackageOwnersTransaction.php @@ -0,0 +1,76 @@ +getOwners(), 'getUserPHID'); + $phids = array_values($phids); + return $phids; + } + + public function generateNewValue($object, $value) { + $phids = array_unique($value); + $phids = array_values($phids); + return $phids; + } + + public function applyExternalEffects($object, $value) { + $old = $this->generateOldValue($object); + $new = $value; + + $owners = $object->getOwners(); + $owners = mpull($owners, null, 'getUserPHID'); + + $rem = array_diff($old, $new); + foreach ($rem as $phid) { + if (isset($owners[$phid])) { + $owners[$phid]->delete(); + unset($owners[$phid]); + } + } + + $add = array_diff($new, $old); + foreach ($add as $phid) { + $owners[$phid] = id(new PhabricatorOwnersOwner()) + ->setPackageID($object->getID()) + ->setUserPHID($phid) + ->save(); + } + + // TODO: Attach owners here + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $add = array_diff($new, $old); + $rem = array_diff($old, $new); + if ($add && !$rem) { + return pht( + '%s added %s owner(s): %s.', + $this->renderAuthor(), + count($add), + $this->renderHandleList($add)); + } else if ($rem && !$add) { + return pht( + '%s removed %s owner(s): %s.', + $this->renderAuthor(), + count($rem), + $this->renderHandleList($rem)); + } else { + return pht( + '%s changed %s package owner(s), added %s: %s; removed %s: %s.', + $this->renderAuthor(), + count($add) + count($rem), + count($add), + $this->renderHandleList($add), + count($rem), + $this->renderHandleList($rem)); + } + } + +} diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackagePathsTransaction.php b/src/applications/owners/xaction/PhabricatorOwnersPackagePathsTransaction.php new file mode 100644 index 0000000000..5952b78aed --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackagePathsTransaction.php @@ -0,0 +1,189 @@ +getPaths(); + return mpull($paths, 'getRef'); + } + + public function generateNewValue($object, $value) { + $new = $value; + foreach ($new as $key => $info) { + $new[$key]['excluded'] = (int)idx($info, 'excluded'); + } + return $new; + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if (!$xactions) { + return $errors; + } + + $old = mpull($object->getPaths(), 'getRef'); + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + + // Check that we have a list of paths. + if (!is_array($new)) { + $errors[] = $this->newInvalidError( + pht('Path specification must be a list of paths.'), + $xaction); + continue; + } + + // Check that each item in the list is formatted properly. + $type_exception = null; + foreach ($new as $key => $value) { + try { + PhutilTypeSpec::checkMap( + $value, + array( + 'repositoryPHID' => 'string', + 'path' => 'string', + 'excluded' => 'optional wild', + )); + } catch (PhutilTypeCheckException $ex) { + $errors[] = $this->newInvalidError( + pht( + 'Path specification list contains invalid value '. + 'in key "%s": %s.', + $key, + $ex->getMessage()), + $xaction); + $type_exception = $ex; + } + } + + if ($type_exception) { + continue; + } + + // Check that any new paths reference legitimate repositories which + // the viewer has permission to see. + list($rem, $add) = PhabricatorOwnersPath::getTransactionValueChanges( + $old, + $new); + + if ($add) { + $repository_phids = ipull($add, 'repositoryPHID'); + + $repositories = id(new PhabricatorRepositoryQuery()) + ->setViewer($this->getActor()) + ->withPHIDs($repository_phids) + ->execute(); + $repositories = mpull($repositories, null, 'getPHID'); + + foreach ($add as $ref) { + $repository_phid = $ref['repositoryPHID']; + if (isset($repositories[$repository_phid])) { + continue; + } + + $errors[] = $this->newInvalidError( + pht( + 'Path specification list references repository PHID "%s", '. + 'but that is not a valid, visible repository.', + $repository_phid)); + } + } + } + + return $errors; + } + + public function applyExternalEffects($object, $value) { + $old = $this->generateOldValue($object); + $new = $value; + + $paths = $object->getPaths(); + + $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); + list($rem, $add) = $diffs; + + $set = PhabricatorOwnersPath::getSetFromTransactionValue($rem); + foreach ($paths as $path) { + $ref = $path->getRef(); + if (PhabricatorOwnersPath::isRefInSet($ref, $set)) { + $path->delete(); + } + } + + foreach ($add as $ref) { + $path = PhabricatorOwnersPath::newFromRef($ref) + ->setPackageID($object->getID()) + ->save(); + } + } + + public function getTitle() { + // TODO: Flesh this out. + return pht( + '%s updated paths for this package.', + $this->renderAuthor()); + } + + public function hasChangeDetailView() { + return true; + } + + public function newChangeDetailView() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); + list($rem, $add) = $diffs; + + $rows = array(); + foreach ($rem as $ref) { + $rows[] = array( + 'class' => 'diff-removed', + 'change' => '-', + ) + $ref; + } + + foreach ($add as $ref) { + $rows[] = array( + 'class' => 'diff-added', + 'change' => '+', + ) + $ref; + } + + $rowc = array(); + foreach ($rows as $key => $row) { + $rowc[] = $row['class']; + $rows[$key] = array( + $row['change'], + $row['excluded'] ? pht('Exclude') : pht('Include'), + $this->renderHandle($row['repositoryPHID']), + $row['path'], + ); + } + + $table = id(new AphrontTableView($rows)) + ->setViewer($this->getViewer()) + ->setRowClasses($rowc) + ->setHeaders( + array( + null, + pht('Type'), + pht('Repository'), + pht('Path'), + )) + ->setColumnClasses( + array( + null, + null, + null, + 'wide', + )); + + return $table; + } + +} diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackagePrimaryTransaction.php b/src/applications/owners/xaction/PhabricatorOwnersPackagePrimaryTransaction.php new file mode 100644 index 0000000000..76d3c2f10f --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackagePrimaryTransaction.php @@ -0,0 +1,15 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + if ($new == PhabricatorOwnersPackage::STATUS_ACTIVE) { + return pht( + '%s activated this package.', + $this->renderAuthor()); + } else if ($new == PhabricatorOwnersPackage::STATUS_ARCHIVED) { + return pht( + '%s archived this package.', + $this->renderAuthor()); + } + } + +} diff --git a/src/applications/owners/xaction/PhabricatorOwnersPackageTransactionType.php b/src/applications/owners/xaction/PhabricatorOwnersPackageTransactionType.php new file mode 100644 index 0000000000..5faaa79a17 --- /dev/null +++ b/src/applications/owners/xaction/PhabricatorOwnersPackageTransactionType.php @@ -0,0 +1,4 @@ +getViewer(); $document = id(new PhrictionDocumentQuery()) ->setViewer($viewer) ->withIDs(array($request->getURIData('id'))) ->needContent(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$document) { return new Aphront404Response(); } $slug = $document->getSlug(); $cancel_uri = PhrictionDocument::getSlugURI($slug); $v_slug = $slug; $e_slug = null; $v_note = ''; $validation_exception = null; if ($request->isFormPost()) { $v_note = $request->getStr('description'); $v_slug = $request->getStr('slug'); + $normal_slug = PhabricatorSlug::normalize($v_slug); // If what the user typed isn't what we're actually using, warn them // about it. if (strlen($v_slug)) { - $normal_slug = PhabricatorSlug::normalize($v_slug); $no_slash_slug = rtrim($normal_slug, '/'); if ($normal_slug !== $v_slug && $no_slash_slug !== $v_slug) { return $this->newDialog() ->setTitle(pht('Adjust Path')) ->appendParagraph( pht( 'The path you entered (%s) is not a valid wiki document '. 'path. Paths may not contain spaces or special characters.', phutil_tag('strong', array(), $v_slug))) ->appendParagraph( pht( 'Would you like to use the path %s instead?', phutil_tag('strong', array(), $normal_slug))) ->addHiddenInput('slug', $normal_slug) ->addHiddenInput('description', $v_note) ->addCancelButton($cancel_uri) ->addSubmitButton(pht('Accept Path')); } } $editor = id(new PhrictionTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setDescription($v_note); $xactions = array(); $xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhrictionTransaction::TYPE_MOVE_TO) ->setNewValue($document); - $target_document = PhrictionDocument::initializeNewDocument( - $viewer, - $v_slug); + $target_document = id(new PhrictionDocumentQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withSlugs(array($normal_slug)) + ->needContent(true) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$target_document) { + $target_document = PhrictionDocument::initializeNewDocument( + $viewer, + $v_slug); + } try { $editor->applyTransactions($target_document, $xactions); $redir_uri = PhrictionDocument::getSlugURI( $target_document->getSlug()); return id(new AphrontRedirectResponse())->setURI($redir_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_slug = $ex->getShortMessage(PhrictionTransaction::TYPE_MOVE_TO); } } $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Title')) ->setValue($document->getContent()->getTitle())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Current Path')) ->setDisabled(true) ->setValue($slug)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('New Path')) ->setValue($v_slug) ->setError($e_slug) ->setName('slug')) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Edit Notes')) ->setValue($v_note) ->setName('description')); return $this->newDialog() ->setTitle(pht('Move Document')) ->setValidationException($validation_exception) ->appendForm($form) ->addSubmitButton(pht('Move Document')) ->addCancelButton($cancel_uri); } } diff --git a/src/applications/phriction/editor/PhrictionTransactionEditor.php b/src/applications/phriction/editor/PhrictionTransactionEditor.php index f0606c65a4..af238dfcf9 100644 --- a/src/applications/phriction/editor/PhrictionTransactionEditor.php +++ b/src/applications/phriction/editor/PhrictionTransactionEditor.php @@ -1,819 +1,821 @@ description = $description; return $this; } private function getDescription() { return $this->description; } private function setOldContent(PhrictionContent $content) { $this->oldContent = $content; return $this; } private function getOldContent() { return $this->oldContent; } private function setNewContent(PhrictionContent $content) { $this->newContent = $content; return $this; } private function getNewContent() { return $this->newContent; } public function setSkipAncestorCheck($bool) { $this->skipAncestorCheck = $bool; return $this; } public function getSkipAncestorCheck() { return $this->skipAncestorCheck; } public function setContentVersion($version) { $this->contentVersion = $version; return $this; } public function getContentVersion() { return $this->contentVersion; } public function setProcessContentVersionError($process) { $this->processContentVersionError = $process; return $this; } public function getProcessContentVersionError() { return $this->processContentVersionError; } public function getEditorApplicationClass() { return 'PhabricatorPhrictionApplication'; } public function getEditorObjectsDescription() { return pht('Phriction Documents'); } public function getTransactionTypes() { $types = parent::getTransactionTypes(); $types[] = PhrictionTransaction::TYPE_TITLE; $types[] = PhrictionTransaction::TYPE_CONTENT; $types[] = PhrictionTransaction::TYPE_DELETE; $types[] = PhrictionTransaction::TYPE_MOVE_TO; $types[] = PhrictionTransaction::TYPE_MOVE_AWAY; $types[] = PhabricatorTransactions::TYPE_EDGE; $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; return $types; } protected function getCustomTransactionOldValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: if ($this->getIsNewObject()) { return null; } return $this->getOldContent()->getTitle(); case PhrictionTransaction::TYPE_CONTENT: if ($this->getIsNewObject()) { return null; } return $this->getOldContent()->getContent(); case PhrictionTransaction::TYPE_DELETE: case PhrictionTransaction::TYPE_MOVE_TO: case PhrictionTransaction::TYPE_MOVE_AWAY: return null; } } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: case PhrictionTransaction::TYPE_CONTENT: case PhrictionTransaction::TYPE_DELETE: return $xaction->getNewValue(); case PhrictionTransaction::TYPE_MOVE_TO: $document = $xaction->getNewValue(); // grab the real object now for the sub-editor to come $this->moveAwayDocument = $document; $dict = array( 'id' => $document->getID(), 'phid' => $document->getPHID(), 'content' => $document->getContent()->getContent(), 'title' => $document->getContent()->getTitle(), ); return $dict; case PhrictionTransaction::TYPE_MOVE_AWAY: $document = $xaction->getNewValue(); $dict = array( 'id' => $document->getID(), 'phid' => $document->getPHID(), 'content' => $document->getContent()->getContent(), 'title' => $document->getContent()->getTitle(), ); return $dict; } } protected function shouldApplyInitialEffects( PhabricatorLiskDAO $object, array $xactions) { foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: case PhrictionTransaction::TYPE_CONTENT: case PhrictionTransaction::TYPE_DELETE: case PhrictionTransaction::TYPE_MOVE_TO: case PhrictionTransaction::TYPE_MOVE_AWAY: return true; } } return parent::shouldApplyInitialEffects($object, $xactions); } protected function applyInitialEffects( PhabricatorLiskDAO $object, array $xactions) { $this->setOldContent($object->getContent()); $this->setNewContent($this->buildNewContentTemplate($object)); } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: case PhrictionTransaction::TYPE_CONTENT: case PhrictionTransaction::TYPE_MOVE_TO: $object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS); return; case PhrictionTransaction::TYPE_MOVE_AWAY: $object->setStatus(PhrictionDocumentStatus::STATUS_MOVED); return; case PhrictionTransaction::TYPE_DELETE: $object->setStatus(PhrictionDocumentStatus::STATUS_DELETED); return; } } protected function expandTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $xactions = parent::expandTransaction($object, $xaction); switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_CONTENT: if ($this->getIsNewObject()) { break; } $content = $xaction->getNewValue(); if ($content === '') { $xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhrictionTransaction::TYPE_DELETE) ->setNewValue(true) ->setMetadataValue('contentDelete', true); } break; case PhrictionTransaction::TYPE_MOVE_TO: $document = $xaction->getNewValue(); $xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setNewValue($document->getViewPolicy()); $xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) ->setNewValue($document->getEditPolicy()); break; default: break; } return $xactions; } protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: $this->getNewContent()->setTitle($xaction->getNewValue()); break; case PhrictionTransaction::TYPE_CONTENT: $this->getNewContent()->setContent($xaction->getNewValue()); break; case PhrictionTransaction::TYPE_DELETE: $this->getNewContent()->setContent(''); $this->getNewContent()->setChangeType( PhrictionChangeType::CHANGE_DELETE); break; case PhrictionTransaction::TYPE_MOVE_TO: $dict = $xaction->getNewValue(); $this->getNewContent()->setContent($dict['content']); $this->getNewContent()->setTitle($dict['title']); $this->getNewContent()->setChangeType( PhrictionChangeType::CHANGE_MOVE_HERE); $this->getNewContent()->setChangeRef($dict['id']); break; case PhrictionTransaction::TYPE_MOVE_AWAY: $dict = $xaction->getNewValue(); $this->getNewContent()->setContent(''); $this->getNewContent()->setChangeType( PhrictionChangeType::CHANGE_MOVE_AWAY); $this->getNewContent()->setChangeRef($dict['id']); break; default: break; } } protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { $save_content = false; foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: case PhrictionTransaction::TYPE_CONTENT: case PhrictionTransaction::TYPE_DELETE: case PhrictionTransaction::TYPE_MOVE_AWAY: case PhrictionTransaction::TYPE_MOVE_TO: $save_content = true; break; default: break; } } if ($save_content) { $content = $this->getNewContent(); $content->setDocumentID($object->getID()); $content->save(); $object->setContentID($content->getID()); $object->save(); $object->attachContent($content); } if ($this->getIsNewObject() && !$this->getSkipAncestorCheck()) { // Stub out empty parent documents if they don't exist $ancestral_slugs = PhabricatorSlug::getAncestry($object->getSlug()); if ($ancestral_slugs) { $ancestors = id(new PhrictionDocumentQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withSlugs($ancestral_slugs) ->needContent(true) ->execute(); $ancestors = mpull($ancestors, null, 'getSlug'); $stub_type = PhrictionChangeType::CHANGE_STUB; foreach ($ancestral_slugs as $slug) { $ancestor_doc = idx($ancestors, $slug); // We check for change type to prevent near-infinite recursion if (!$ancestor_doc && $content->getChangeType() != $stub_type) { $ancestor_doc = PhrictionDocument::initializeNewDocument( $this->getActor(), $slug); $stub_xactions = array(); $stub_xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhrictionTransaction::TYPE_TITLE) ->setNewValue(PhabricatorSlug::getDefaultTitle($slug)) ->setMetadataValue('stub:create:phid', $object->getPHID()); $stub_xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhrictionTransaction::TYPE_CONTENT) ->setNewValue('') ->setMetadataValue('stub:create:phid', $object->getPHID()); $stub_xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setNewValue($object->getViewPolicy()); $stub_xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) ->setNewValue($object->getEditPolicy()); $sub_editor = id(new PhrictionTransactionEditor()) ->setActor($this->getActor()) ->setContentSource($this->getContentSource()) ->setContinueOnNoEffect($this->getContinueOnNoEffect()) ->setSkipAncestorCheck(true) ->setDescription(pht('Empty Parent Document')) ->applyTransactions($ancestor_doc, $stub_xactions); } } } } if ($this->moveAwayDocument !== null) { $move_away_xactions = array(); $move_away_xactions[] = id(new PhrictionTransaction()) ->setTransactionType(PhrictionTransaction::TYPE_MOVE_AWAY) ->setNewValue($object); $sub_editor = id(new PhrictionTransactionEditor()) ->setActor($this->getActor()) ->setContentSource($this->getContentSource()) ->setContinueOnNoEffect($this->getContinueOnNoEffect()) ->setDescription($this->getDescription()) ->applyTransactions($this->moveAwayDocument, $move_away_xactions); } // Compute the content diff URI for the publishing phase. foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_CONTENT: $uri = id(new PhutilURI('/phriction/diff/'.$object->getID().'/')) ->alter('l', $this->getOldContent()->getVersion()) ->alter('r', $this->getNewContent()->getVersion()); $this->contentDiffURI = (string)$uri; break 2; default: break; } } return $xactions; } protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function getMailSubjectPrefix() { return '[Phriction]'; } protected function getMailTo(PhabricatorLiskDAO $object) { return array( $object->getContent()->getAuthorPHID(), $this->getActingAsPHID(), ); } public function getMailTagsMap() { return array( PhrictionTransaction::MAILTAG_TITLE => pht("A document's title changes."), PhrictionTransaction::MAILTAG_CONTENT => pht("A document's content changes."), PhrictionTransaction::MAILTAG_DELETE => pht('A document is deleted.'), PhrictionTransaction::MAILTAG_SUBSCRIBERS => pht('A document\'s subscribers change.'), PhrictionTransaction::MAILTAG_OTHER => pht('Other document activity not listed above occurs.'), ); } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new PhrictionReplyHandler()) ->setMailReceiver($object); } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $id = $object->getID(); $title = $object->getContent()->getTitle(); return id(new PhabricatorMetaMTAMail()) ->setSubject($title) ->addHeader('Thread-Topic', $object->getPHID()); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $body = parent::buildMailBody($object, $xactions); if ($this->getIsNewObject()) { $body->addRemarkupSection( pht('DOCUMENT CONTENT'), $object->getContent()->getContent()); } else if ($this->contentDiffURI) { $body->addLinkSection( pht('DOCUMENT DIFF'), PhabricatorEnv::getProductionURI($this->contentDiffURI)); } $description = $object->getContent()->getDescription(); if (strlen($description)) { $body->addTextSection( pht('EDIT NOTES'), $description); } $body->addLinkSection( pht('DOCUMENT DETAIL'), PhabricatorEnv::getProductionURI( PhrictionDocument::getSlugURI($object->getSlug()))); return $body; } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { return $this->shouldSendMail($object, $xactions); } protected function getFeedRelatedPHIDs( PhabricatorLiskDAO $object, array $xactions) { $phids = parent::getFeedRelatedPHIDs($object, $xactions); foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_MOVE_TO: $dict = $xaction->getNewValue(); $phids[] = $dict['phid']; break; } } return $phids; } protected function validateTransaction( PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); foreach ($xactions as $xaction) { switch ($type) { case PhrictionTransaction::TYPE_TITLE: $title = $object->getContent()->getTitle(); $missing = $this->validateIsEmptyTextField( $title, $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), pht('Document title is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } else if ($this->getProcessContentVersionError()) { $error = $this->validateContentVersion($object, $type, $xaction); if ($error) { $this->setProcessContentVersionError(false); $errors[] = $error; } } break; case PhrictionTransaction::TYPE_CONTENT: if ($xaction->getMetadataValue('stub:create:phid')) { continue; } $missing = false; if ($this->getIsNewObject()) { $content = $object->getContent()->getContent(); $missing = $this->validateIsEmptyTextField( $content, $xactions); } if ($missing) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), pht('Document content is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } else if ($this->getProcessContentVersionError()) { $error = $this->validateContentVersion($object, $type, $xaction); if ($error) { $this->setProcessContentVersionError(false); $errors[] = $error; } } if ($this->getIsNewObject()) { $ancestry_errors = $this->validateAncestry( $object, $type, $xaction, self::VALIDATE_CREATE_ANCESTRY); if ($ancestry_errors) { $errors = array_merge($errors, $ancestry_errors); } } break; case PhrictionTransaction::TYPE_MOVE_TO: $source_document = $xaction->getNewValue(); switch ($source_document->getStatus()) { case PhrictionDocumentStatus::STATUS_DELETED: $e_text = pht('A deleted document can not be moved.'); break; case PhrictionDocumentStatus::STATUS_MOVED: $e_text = pht('A moved document can not be moved again.'); break; case PhrictionDocumentStatus::STATUS_STUB: $e_text = pht('A stub document can not be moved.'); break; default: $e_text = null; break; } if ($e_text) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Can not move document.'), $e_text, $xaction); $errors[] = $error; } $ancestry_errors = $this->validateAncestry( $object, $type, $xaction, self::VALIDATE_MOVE_ANCESTRY); if ($ancestry_errors) { $errors = array_merge($errors, $ancestry_errors); } $target_document = id(new PhrictionDocumentQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withSlugs(array($object->getSlug())) ->needContent(true) ->executeOne(); // Prevent overwrites and no-op moves. $exists = PhrictionDocumentStatus::STATUS_EXISTS; if ($target_document) { + $message = null; if ($target_document->getSlug() == $source_document->getSlug()) { $message = pht( 'You can not move a document to its existing location. '. 'Choose a different location to move the document to.'); } else if ($target_document->getStatus() == $exists) { $message = pht( 'You can not move this document there, because it would '. 'overwrite an existing document which is already at that '. 'location. Move or delete the existing document first.'); } - - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - $message, - $xaction); - $errors[] = $error; + if ($message !== null) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Invalid'), + $message, + $xaction); + $errors[] = $error; + } } break; case PhrictionTransaction::TYPE_DELETE: switch ($object->getStatus()) { case PhrictionDocumentStatus::STATUS_DELETED: if ($xaction->getMetadataValue('contentDelete')) { $e_text = pht( 'This document is already deleted. You must specify '. 'content to re-create the document and make further edits.'); } else { $e_text = pht( 'An already deleted document can not be deleted.'); } break; case PhrictionDocumentStatus::STATUS_MOVED: $e_text = pht('A moved document can not be deleted.'); break; case PhrictionDocumentStatus::STATUS_STUB: $e_text = pht('A stub document can not be deleted.'); break; default: break 2; } $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Can not delete document.'), $e_text, $xaction); $errors[] = $error; break; } } return $errors; } private function validateAncestry( PhabricatorLiskDAO $object, $type, PhabricatorApplicationTransaction $xaction, $verb) { $errors = array(); // NOTE: We use the ominpotent user for these checks because policy // doesn't matter; existence does. $other_doc_viewer = PhabricatorUser::getOmnipotentUser(); $ancestral_slugs = PhabricatorSlug::getAncestry($object->getSlug()); if ($ancestral_slugs) { $ancestors = id(new PhrictionDocumentQuery()) ->setViewer($other_doc_viewer) ->withSlugs($ancestral_slugs) ->execute(); $ancestors = mpull($ancestors, null, 'getSlug'); foreach ($ancestral_slugs as $slug) { $ancestor_doc = idx($ancestors, $slug); if (!$ancestor_doc) { $create_uri = '/phriction/edit/?slug='.$slug; $create_link = phutil_tag( 'a', array( 'href' => $create_uri, ), $slug); switch ($verb) { case self::VALIDATE_MOVE_ANCESTRY: $message = pht( 'Can not move document because the parent document with '. 'slug %s does not exist!', $create_link); break; case self::VALIDATE_CREATE_ANCESTRY: $message = pht( 'Can not create document because the parent document with '. 'slug %s does not exist!', $create_link); break; } $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Missing Ancestor'), $message, $xaction); $errors[] = $error; } } } return $errors; } private function validateContentVersion( PhabricatorLiskDAO $object, $type, PhabricatorApplicationTransaction $xaction) { $error = null; if ($this->getContentVersion() && ($object->getContent()->getVersion() != $this->getContentVersion())) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Edit Conflict'), pht( 'Another user made changes to this document after you began '. 'editing it. Do you want to overwrite their changes? '. '(If you choose to overwrite their changes, you should review '. 'the document edit history to see what you overwrote, and '. 'then make another edit to merge the changes if necessary.)'), $xaction); } return $error; } protected function requireCapabilities( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { /* * New objects have a special case. If a user can't see * x/y * then definitely don't let them make some * x/y/z * We need to load the direct parent to handle this case. */ if ($this->getIsNewObject()) { $actor = $this->requireActor(); $parent_doc = null; $ancestral_slugs = PhabricatorSlug::getAncestry($object->getSlug()); // No ancestral slugs is "/"; the first person gets to play with "/". if ($ancestral_slugs) { $parent = end($ancestral_slugs); $parent_doc = id(new PhrictionDocumentQuery()) ->setViewer($actor) ->withSlugs(array($parent)) ->executeOne(); // If the $actor can't see the $parent_doc then they can't create // the child $object; throw a policy exception. if (!$parent_doc) { id(new PhabricatorPolicyFilter()) ->setViewer($actor) ->raisePolicyExceptions(true) ->rejectObject( $object, $object->getEditPolicy(), PhabricatorPolicyCapability::CAN_EDIT); } // If the $actor can't edit the $parent_doc then they can't create // the child $object; throw a policy exception. if (!PhabricatorPolicyFilter::hasCapability( $actor, $parent_doc, PhabricatorPolicyCapability::CAN_EDIT)) { id(new PhabricatorPolicyFilter()) ->setViewer($actor) ->raisePolicyExceptions(true) ->rejectObject( $object, $object->getEditPolicy(), PhabricatorPolicyCapability::CAN_EDIT); } } } return parent::requireCapabilities($object, $xaction); } protected function supportsSearch() { return true; } protected function shouldApplyHeraldRules( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function buildHeraldAdapter( PhabricatorLiskDAO $object, array $xactions) { return id(new PhrictionDocumentHeraldAdapter()) ->setDocument($object); } private function buildNewContentTemplate( PhrictionDocument $document) { $new_content = id(new PhrictionContent()) ->setSlug($document->getSlug()) ->setAuthorPHID($this->getActor()->getPHID()) ->setChangeType(PhrictionChangeType::CHANGE_EDIT) ->setTitle($this->getOldContent()->getTitle()) ->setContent($this->getOldContent()->getContent()); if (strlen($this->getDescription())) { $new_content->setDescription($this->getDescription()); } $new_content->setVersion($this->getOldContent()->getVersion() + 1); return $new_content; } protected function getCustomWorkerState() { return array( 'contentDiffURI' => $this->contentDiffURI, ); } protected function loadCustomWorkerState(array $state) { $this->contentDiffURI = idx($state, 'contentDiffURI'); return $this; } } diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php index 6350df5e02..b7bef9a623 100644 --- a/src/applications/search/controller/PhabricatorApplicationSearchController.php +++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php @@ -1,528 +1,599 @@ preface = $preface; return $this; } public function getPreface() { return $this->preface; } public function setQueryKey($query_key) { $this->queryKey = $query_key; return $this; } protected function getQueryKey() { return $this->queryKey; } public function setNavigation(AphrontSideNavFilterView $navigation) { $this->navigation = $navigation; return $this; } protected function getNavigation() { return $this->navigation; } public function setSearchEngine( PhabricatorApplicationSearchEngine $search_engine) { $this->searchEngine = $search_engine; return $this; } protected function getSearchEngine() { return $this->searchEngine; } protected function validateDelegatingController() { $parent = $this->getDelegatingController(); if (!$parent) { throw new Exception( pht('You must delegate to this controller, not invoke it directly.')); } $engine = $this->getSearchEngine(); if (!$engine) { throw new PhutilInvalidStateException('setEngine'); } $engine->setViewer($this->getRequest()->getUser()); $parent = $this->getDelegatingController(); } public function processRequest() { $this->validateDelegatingController(); $key = $this->getQueryKey(); if ($key == 'edit') { return $this->processEditRequest(); } else { return $this->processSearchRequest(); } } private function processSearchRequest() { $parent = $this->getDelegatingController(); $request = $this->getRequest(); $user = $request->getUser(); $engine = $this->getSearchEngine(); $nav = $this->getNavigation(); if (!$nav) { $nav = $this->buildNavigation(); } if ($request->isFormPost()) { $saved_query = $engine->buildSavedQueryFromRequest($request); $engine->saveQuery($saved_query); return id(new AphrontRedirectResponse())->setURI( $engine->getQueryResultsPageURI($saved_query->getQueryKey()).'#R'); } $named_query = null; $run_query = true; $query_key = $this->queryKey; if ($this->queryKey == 'advanced') { $run_query = false; $query_key = $request->getStr('query'); } else if (!strlen($this->queryKey)) { $found_query_data = false; if ($request->isHTTPGet() || $request->isQuicksand()) { // If this is a GET request and it has some query data, don't // do anything unless it's only before= or after=. We'll build and // execute a query from it below. This allows external tools to build // URIs like "/query/?users=a,b". $pt_data = $request->getPassthroughRequestData(); $exempt = array( 'before' => true, 'after' => true, 'nux' => true, + 'overheated' => true, ); foreach ($pt_data as $pt_key => $pt_value) { if (isset($exempt[$pt_key])) { continue; } $found_query_data = true; break; } } if (!$found_query_data) { // Otherwise, there's no query data so just run the user's default // query for this application. $query_key = head_key($engine->loadEnabledNamedQueries()); } } if ($engine->isBuiltinQuery($query_key)) { $saved_query = $engine->buildSavedQueryFromBuiltin($query_key); $named_query = idx($engine->loadEnabledNamedQueries(), $query_key); } else if ($query_key) { $saved_query = id(new PhabricatorSavedQueryQuery()) ->setViewer($user) ->withQueryKeys(array($query_key)) ->executeOne(); if (!$saved_query) { return new Aphront404Response(); } $named_query = idx($engine->loadEnabledNamedQueries(), $query_key); } else { $saved_query = $engine->buildSavedQueryFromRequest($request); // Save the query to generate a query key, so "Save Custom Query..." and // other features like Maniphest's "Export..." work correctly. $engine->saveQuery($saved_query); } $nav->selectFilter( 'query/'.$saved_query->getQueryKey(), 'query/advanced'); $form = id(new AphrontFormView()) ->setUser($user) ->setAction($request->getPath()); $engine->buildSearchForm($form, $saved_query); $errors = $engine->getErrors(); if ($errors) { $run_query = false; } $submit = id(new AphrontFormSubmitControl()) ->setValue(pht('Execute Query')); if ($run_query && !$named_query && $user->isLoggedIn()) { $submit->addCancelButton( '/search/edit/'.$saved_query->getQueryKey().'/', pht('Save Custom Query...')); } // TODO: A "Create Dashboard Panel" action goes here somewhere once // we sort out T5307. $form->appendChild($submit); $body = array(); if ($this->getPreface()) { $body[] = $this->getPreface(); } if ($named_query) { $title = $named_query->getQueryName(); } else { $title = pht('Advanced Search'); } $header = id(new PHUIHeaderView()) ->setHeader($title) ->setProfileHeader(true); $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addClass('application-search-results'); if ($run_query || $named_query) { $box->setShowHide( pht('Edit Query'), pht('Hide Query'), $form, $this->getApplicationURI('query/advanced/?query='.$query_key), (!$named_query ? true : false)); } else { $box->setForm($form); } $body[] = $box; $more_crumbs = null; if ($run_query) { $exec_errors = array(); $box->setAnchor( id(new PhabricatorAnchorView()) ->setAnchorName('R')); try { $engine->setRequest($request); $query = $engine->buildQueryFromSavedQuery($saved_query); $pager = $engine->newPagerForSavedQuery($saved_query); $pager->readFromRequest($request); $objects = $engine->executeQuery($query, $pager); $force_nux = $request->getBool('nux'); if (!$objects || $force_nux) { $nux_view = $this->renderNewUserView($engine, $force_nux); } else { $nux_view = null; } + $force_overheated = $request->getBool('overheated'); + $is_overheated = $query->getIsOverheated() || $force_overheated; + if ($nux_view) { $box->appendChild($nux_view); } else { $list = $engine->renderResults($objects, $saved_query); if (!($list instanceof PhabricatorApplicationSearchResultView)) { throw new Exception( pht( 'SearchEngines must render a "%s" object, but this engine '. '(of class "%s") rendered something else.', 'PhabricatorApplicationSearchResultView', get_class($engine))); } if ($list->getObjectList()) { $box->setObjectList($list->getObjectList()); } if ($list->getTable()) { $box->setTable($list->getTable()); } if ($list->getInfoView()) { $box->setInfoView($list->getInfoView()); } if ($list->getContent()) { $box->appendChild($list->getContent()); } + if ($is_overheated) { + $box->appendChild($this->newOverheatedView($objects)); + } + $result_header = $list->getHeader(); if ($result_header) { $box->setHeader($result_header); $header = $result_header; } - if ($list->getActions()) { - foreach ($list->getActions() as $action) { + $actions = $list->getActions(); + if ($actions) { + foreach ($actions as $action) { $header->addActionLink($action); } } $use_actions = $engine->newUseResultsActions($saved_query); + + // TODO: Eventually, modularize all this stuff. + $builtin_use_actions = $this->newBuiltinUseActions(); + if ($builtin_use_actions) { + foreach ($builtin_use_actions as $builtin_use_action) { + $use_actions[] = $builtin_use_action; + } + } + if ($use_actions) { $use_dropdown = $this->newUseResultsDropdown( $saved_query, $use_actions); $header->addActionLink($use_dropdown); } $more_crumbs = $list->getCrumbs(); if ($pager->willShowPagingControls()) { $pager_box = id(new PHUIBoxView()) ->setColor(PHUIBoxView::GREY) ->addClass('application-search-pager') ->appendChild($pager); $body[] = $pager_box; } } } catch (PhabricatorTypeaheadInvalidTokenException $ex) { $exec_errors[] = pht( 'This query specifies an invalid parameter. Review the '. 'query parameters and correct errors.'); } // The engine may have encountered additional errors during rendering; // merge them in and show everything. foreach ($engine->getErrors() as $error) { $exec_errors[] = $error; } $errors = $exec_errors; } if ($errors) { $box->setFormErrors($errors, pht('Query Errors')); } $crumbs = $parent ->buildApplicationCrumbs() ->setBorder(true); if ($more_crumbs) { $query_uri = $engine->getQueryResultsPageURI($saved_query->getQueryKey()); $crumbs->addTextCrumb($title, $query_uri); foreach ($more_crumbs as $crumb) { $crumbs->addCrumb($crumb); } } else { $crumbs->addTextCrumb($title); } - $nav->addClass('application-search-view'); require_celerity_resource('application-search-view-css'); return $this->newPage() ->setApplicationMenu($this->buildApplicationMenu()) ->setTitle(pht('Query: %s', $title)) ->setCrumbs($crumbs) ->setNavigation($nav) + ->addClass('application-search-view') ->appendChild($body); } private function processEditRequest() { $parent = $this->getDelegatingController(); $request = $this->getRequest(); $user = $request->getUser(); $engine = $this->getSearchEngine(); $nav = $this->getNavigation(); if (!$nav) { $nav = $this->buildNavigation(); } $named_queries = $engine->loadAllNamedQueries(); $list_id = celerity_generate_unique_node_id(); $list = new PHUIObjectItemListView(); $list->setUser($user); $list->setID($list_id); Javelin::initBehavior( 'search-reorder-queries', array( 'listID' => $list_id, 'orderURI' => '/search/order/'.get_class($engine).'/', )); foreach ($named_queries as $named_query) { $class = get_class($engine); $key = $named_query->getQueryKey(); $item = id(new PHUIObjectItemView()) ->setHeader($named_query->getQueryName()) ->setHref($engine->getQueryResultsPageURI($key)); if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) { $icon = 'fa-plus'; } else { $icon = 'fa-times'; } $item->addAction( id(new PHUIListItemView()) ->setIcon($icon) ->setHref('/search/delete/'.$key.'/'.$class.'/') ->setWorkflow(true)); if ($named_query->getIsBuiltin()) { if ($named_query->getIsDisabled()) { $item->addIcon('fa-times lightgreytext', pht('Disabled')); $item->setDisabled(true); } else { $item->addIcon('fa-lock lightgreytext', pht('Builtin')); } } else { $item->addAction( id(new PHUIListItemView()) ->setIcon('fa-pencil') ->setHref('/search/edit/'.$key.'/')); } $item->setGrippable(true); $item->addSigil('named-query'); $item->setMetadata( array( 'queryKey' => $named_query->getQueryKey(), )); $list->addItem($item); } $list->setNoDataString(pht('No saved queries.')); $crumbs = $parent ->buildApplicationCrumbs() ->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI()) ->setBorder(true); $nav->selectFilter('query/edit'); $header = id(new PHUIHeaderView()) ->setHeader(pht('Saved Queries')) ->setProfileHeader(true); $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->setObjectList($list) ->addClass('application-search-results'); $nav->addClass('application-search-view'); require_celerity_resource('application-search-view-css'); return $this->newPage() ->setApplicationMenu($this->buildApplicationMenu()) ->setTitle(pht('Saved Queries')) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($box); } public function buildApplicationMenu() { $menu = $this->getDelegatingController() ->buildApplicationMenu(); if ($menu instanceof PHUIApplicationMenuView) { $menu->setSearchEngine($this->getSearchEngine()); } return $menu; } private function buildNavigation() { $viewer = $this->getViewer(); $engine = $this->getSearchEngine(); $nav = id(new AphrontSideNavFilterView()) ->setUser($viewer) ->setBaseURI(new PhutilURI($this->getApplicationURI())); $engine->addNavigationItems($nav->getMenu()); return $nav; } private function renderNewUserView( PhabricatorApplicationSearchEngine $engine, $force_nux) { // Don't render NUX if the user has clicked away from the default page. if (strlen($this->getQueryKey())) { return null; } // Don't put NUX in panels because it would be weird. if ($engine->isPanelContext()) { return null; } // Try to render the view itself first, since this should be very cheap // (just returning some text). $nux_view = $engine->renderNewUserView(); if (!$nux_view) { return null; } $query = $engine->newQuery(); if (!$query) { return null; } // Try to load any object at all. If we can, the application has seen some // use so we just render the normal view. if (!$force_nux) { $object = $query ->setViewer(PhabricatorUser::getOmnipotentUser()) ->setLimit(1) ->execute(); if ($object) { return null; } } return $nux_view; } private function newUseResultsDropdown( PhabricatorSavedQuery $query, array $dropdown_items) { $viewer = $this->getViewer(); $action_list = id(new PhabricatorActionListView()) ->setViewer($viewer); foreach ($dropdown_items as $dropdown_item) { $action_list->addAction($dropdown_item); } return id(new PHUIButtonView()) ->setTag('a') ->setHref('#') ->setText(pht('Use Results...')) ->setIcon('fa-road') ->setDropdownMenu($action_list); } + private function newOverheatedView(array $results) { + if ($results) { + $message = pht( + 'Most objects matching your query are not visible to you, so '. + 'filtering results is taking a long time. Only some results are '. + 'shown. Refine your query to find results more quickly.'); + } else { + $message = pht( + 'Most objects matching your query are not visible to you, so '. + 'filtering results is taking a long time. Refine your query to '. + 'find results more quickly.'); + } + + return id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_WARNING) + ->setFlush(true) + ->setTitle(pht('Query Overheated')) + ->setErrors( + array( + $message, + )); + } + + private function newBuiltinUseActions() { + $actions = array(); + + $is_dev = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); + + if ($is_dev) { + $engine = $this->getSearchEngine(); + $nux_uri = $engine->getQueryBaseURI(); + $nux_uri = id(new PhutilURI($nux_uri)) + ->setQueryParam('nux', true); + + $actions[] = id(new PhabricatorActionView()) + ->setIcon('fa-bug') + ->setName(pht('Developer: Show New User State')) + ->setHref($nux_uri); + } + + if ($is_dev) { + $overheated_uri = $this->getRequest()->getRequestURI() + ->setQueryParam('overheated', true); + + $actions[] = id(new PhabricatorActionView()) + ->setIcon('fa-bug') + ->setName(pht('Developer: Show Overheated State')) + ->setHref($overheated_uri); + } + + return $actions; + } + } diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php index a1279ad8ae..26a9e0f8e4 100644 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -1,1397 +1,1403 @@ controller = $controller; return $this; } public function getController() { return $this->controller; } public function buildResponse() { $controller = $this->getController(); $request = $controller->getRequest(); $search = id(new PhabricatorApplicationSearchController()) ->setQueryKey($request->getURIData('queryKey')) ->setSearchEngine($this); return $controller->delegateToController($search); } public function newResultObject() { // We may be able to get this automatically if newQuery() is implemented. $query = $this->newQuery(); if ($query) { $object = $query->newResultObject(); if ($object) { return $object; } } return null; } public function newQuery() { return null; } public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; return $this; } protected function requireViewer() { if (!$this->viewer) { throw new PhutilInvalidStateException('setViewer'); } return $this->viewer; } public function setContext($context) { $this->context = $context; return $this; } public function isPanelContext() { return ($this->context == self::CONTEXT_PANEL); } public function setNavigationItems(array $navigation_items) { assert_instances_of($navigation_items, 'PHUIListItemView'); $this->navigationItems = $navigation_items; return $this; } public function getNavigationItems() { return $this->navigationItems; } public function canUseInPanelContext() { return true; } public function saveQuery(PhabricatorSavedQuery $query) { $query->setEngineClassName(get_class($this)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); try { $query->save(); } catch (AphrontDuplicateKeyQueryException $ex) { // Ignore, this is just a repeated search. } unset($unguarded); } /** * Create a saved query object from the request. * * @param AphrontRequest The search request. * @return PhabricatorSavedQuery */ public function buildSavedQueryFromRequest(AphrontRequest $request) { $fields = $this->buildSearchFields(); $viewer = $this->requireViewer(); $saved = new PhabricatorSavedQuery(); foreach ($fields as $field) { $field->setViewer($viewer); $value = $field->readValueFromRequest($request); $saved->setParameter($field->getKey(), $value); } return $saved; } /** * Executes the saved query. * * @param PhabricatorSavedQuery The saved query to operate on. * @return The result of the query. */ public function buildQueryFromSavedQuery(PhabricatorSavedQuery $original) { $saved = clone $original; $this->willUseSavedQuery($saved); $fields = $this->buildSearchFields(); $viewer = $this->requireViewer(); $map = array(); foreach ($fields as $field) { $field->setViewer($viewer); $field->readValueFromSavedQuery($saved); $value = $field->getValueForQuery($field->getValue()); $map[$field->getKey()] = $value; } $original->attachParameterMap($map); $query = $this->buildQueryFromParameters($map); $object = $this->newResultObject(); if (!$object) { return $query; } $extensions = $this->getEngineExtensions(); foreach ($extensions as $extension) { $extension->applyConstraintsToQuery($object, $query, $saved, $map); } $order = $saved->getParameter('order'); $builtin = $query->getBuiltinOrderAliasMap(); if (strlen($order) && isset($builtin[$order])) { $query->setOrder($order); } else { // If the order is invalid or not available, we choose the first // builtin order. This isn't always the default order for the query, // but is the first value in the "Order" dropdown, and makes the query // behavior more consistent with the UI. In queries where the two // orders differ, this order is the preferred order for humans. $query->setOrder(head_key($builtin)); } return $query; } /** * Hook for subclasses to adjust saved queries prior to use. * * If an application changes how queries are saved, it can implement this * hook to keep old queries working the way users expect, by reading, * adjusting, and overwriting parameters. * * @param PhabricatorSavedQuery Saved query which will be executed. * @return void */ protected function willUseSavedQuery(PhabricatorSavedQuery $saved) { return; } protected function buildQueryFromParameters(array $parameters) { throw new PhutilMethodNotImplementedException(); } /** * Builds the search form using the request. * * @param AphrontFormView Form to populate. * @param PhabricatorSavedQuery The query from which to build the form. * @return void */ public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved) { $saved = clone $saved; $this->willUseSavedQuery($saved); $fields = $this->buildSearchFields(); $fields = $this->adjustFieldsForDisplay($fields); $viewer = $this->requireViewer(); foreach ($fields as $field) { $field->setViewer($viewer); $field->readValueFromSavedQuery($saved); } foreach ($fields as $field) { foreach ($field->getErrors() as $error) { $this->addError(last($error)); } } foreach ($fields as $field) { $field->appendToForm($form); } } protected function buildSearchFields() { $fields = array(); foreach ($this->buildCustomSearchFields() as $field) { $fields[] = $field; } $object = $this->newResultObject(); if ($object) { $extensions = $this->getEngineExtensions(); foreach ($extensions as $extension) { $extension_fields = $extension->getSearchFields($object); foreach ($extension_fields as $extension_field) { $fields[] = $extension_field; } } } $query = $this->newQuery(); if ($query && $this->shouldShowOrderField()) { $orders = $query->getBuiltinOrders(); $orders = ipull($orders, 'name'); $fields[] = id(new PhabricatorSearchOrderField()) ->setLabel(pht('Order By')) ->setKey('order') ->setOrderAliases($query->getBuiltinOrderAliasMap()) ->setOptions($orders); } $buckets = $this->newResultBuckets(); if ($query && $buckets) { $bucket_options = array( self::BUCKET_NONE => pht('No Bucketing'), ) + mpull($buckets, 'getResultBucketName'); $fields[] = id(new PhabricatorSearchSelectField()) ->setLabel(pht('Bucket')) ->setKey('bucket') ->setOptions($bucket_options); } $field_map = array(); foreach ($fields as $field) { $key = $field->getKey(); if (isset($field_map[$key])) { throw new Exception( pht( 'Two fields in this SearchEngine use the same key ("%s"), but '. 'each field must use a unique key.', $key)); } $field_map[$key] = $field; } return $field_map; } protected function shouldShowOrderField() { return true; } private function adjustFieldsForDisplay(array $field_map) { $order = $this->getDefaultFieldOrder(); $head_keys = array(); $tail_keys = array(); $seen_tail = false; foreach ($order as $order_key) { if ($order_key === '...') { $seen_tail = true; continue; } if (!$seen_tail) { $head_keys[] = $order_key; } else { $tail_keys[] = $order_key; } } $head = array_select_keys($field_map, $head_keys); $body = array_diff_key($field_map, array_fuse($tail_keys)); $tail = array_select_keys($field_map, $tail_keys); $result = $head + $body + $tail; foreach ($this->getHiddenFields() as $hidden_key) { unset($result[$hidden_key]); } return $result; } protected function buildCustomSearchFields() { throw new PhutilMethodNotImplementedException(); } /** * Define the default display order for fields by returning a list of * field keys. * * You can use the special key `...` to mean "all unspecified fields go * here". This lets you easily put important fields at the top of the form, * standard fields in the middle of the form, and less important fields at * the bottom. * * For example, you might return a list like this: * * return array( * 'authorPHIDs', * 'reviewerPHIDs', * '...', * 'createdAfter', * 'createdBefore', * ); * * Any unspecified fields (including custom fields and fields added * automatically by infrastruture) will be put in the middle. * * @return list Default ordering for field keys. */ protected function getDefaultFieldOrder() { return array(); } /** * Return a list of field keys which should be hidden from the viewer. * * @return list Fields to hide. */ protected function getHiddenFields() { return array(); } public function getErrors() { return $this->errors; } public function addError($error) { $this->errors[] = $error; return $this; } /** * Return an application URI corresponding to the results page of a query. * Normally, this is something like `/application/query/QUERYKEY/`. * * @param string The query key to build a URI for. * @return string URI where the query can be executed. * @task uri */ public function getQueryResultsPageURI($query_key) { return $this->getURI('query/'.$query_key.'/'); } /** * Return an application URI for query management. This is used when, e.g., * a query deletion operation is cancelled. * * @return string URI where queries can be managed. * @task uri */ public function getQueryManagementURI() { return $this->getURI('query/edit/'); } + public function getQueryBaseURI() { + return $this->getURI(''); + } + /** * Return the URI to a path within the application. Used to construct default * URIs for management and results. * * @return string URI to path. * @task uri */ abstract protected function getURI($path); /** * Return a human readable description of the type of objects this query * searches for. * * For example, "Tasks" or "Commits". * * @return string Human-readable description of what this engine is used to * find. */ abstract public function getResultTypeDescription(); public function newSavedQuery() { return id(new PhabricatorSavedQuery()) ->setEngineClassName(get_class($this)); } public function addNavigationItems(PHUIListView $menu) { $viewer = $this->requireViewer(); $menu->newLabel(pht('Queries')); $named_queries = $this->loadEnabledNamedQueries(); foreach ($named_queries as $query) { $key = $query->getQueryKey(); $uri = $this->getQueryResultsPageURI($key); $menu->newLink($query->getQueryName(), $uri, 'query/'.$key); } if ($viewer->isLoggedIn()) { $manage_uri = $this->getQueryManagementURI(); $menu->newLink(pht('Edit Queries...'), $manage_uri, 'query/edit'); } $menu->newLabel(pht('Search')); $advanced_uri = $this->getQueryResultsPageURI('advanced'); $menu->newLink(pht('Advanced Search'), $advanced_uri, 'query/advanced'); foreach ($this->navigationItems as $extra_item) { $menu->addMenuItem($extra_item); } return $this; } public function loadAllNamedQueries() { $viewer = $this->requireViewer(); $builtin = $this->getBuiltinQueries($viewer); if ($this->namedQueries === null) { $named_queries = id(new PhabricatorNamedQueryQuery()) ->setViewer($viewer) ->withUserPHIDs(array($viewer->getPHID())) ->withEngineClassNames(array(get_class($this))) ->execute(); $named_queries = mpull($named_queries, null, 'getQueryKey'); $builtin = mpull($builtin, null, 'getQueryKey'); foreach ($named_queries as $key => $named_query) { if ($named_query->getIsBuiltin()) { if (isset($builtin[$key])) { $named_queries[$key]->setQueryName($builtin[$key]->getQueryName()); unset($builtin[$key]); } else { unset($named_queries[$key]); } } unset($builtin[$key]); } $named_queries = msort($named_queries, 'getSortKey'); $this->namedQueries = $named_queries; } return $this->namedQueries + $builtin; } public function loadEnabledNamedQueries() { $named_queries = $this->loadAllNamedQueries(); foreach ($named_queries as $key => $named_query) { if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) { unset($named_queries[$key]); } } return $named_queries; } protected function setQueryProjects( PhabricatorCursorPagedPolicyAwareQuery $query, PhabricatorSavedQuery $saved) { $datasource = id(new PhabricatorProjectLogicalDatasource()) ->setViewer($this->requireViewer()); $projects = $saved->getParameter('projects', array()); $constraints = $datasource->evaluateTokens($projects); if ($constraints) { $query->withEdgeLogicConstraints( PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, $constraints); } return $this; } /* -( Applications )------------------------------------------------------- */ protected function getApplicationURI($path = '') { return $this->getApplication()->getApplicationURI($path); } protected function getApplication() { if (!$this->application) { $class = $this->getApplicationClassName(); $this->application = id(new PhabricatorApplicationQuery()) ->setViewer($this->requireViewer()) ->withClasses(array($class)) ->withInstalled(true) ->executeOne(); if (!$this->application) { throw new Exception( pht( 'Application "%s" is not installed!', $class)); } } return $this->application; } abstract public function getApplicationClassName(); /* -( Constructing Engines )----------------------------------------------- */ /** * Load all available application search engines. * * @return list All available engines. * @task construct */ public static function getAllEngines() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) ->execute(); } /** * Get an engine by class name, if it exists. * * @return PhabricatorApplicationSearchEngine|null Engine, or null if it does * not exist. * @task construct */ public static function getEngineByClassName($class_name) { return idx(self::getAllEngines(), $class_name); } /* -( Builtin Queries )---------------------------------------------------- */ /** * @task builtin */ public function getBuiltinQueries() { $names = $this->getBuiltinQueryNames(); $queries = array(); $sequence = 0; foreach ($names as $key => $name) { $queries[$key] = id(new PhabricatorNamedQuery()) ->setUserPHID($this->requireViewer()->getPHID()) ->setEngineClassName(get_class($this)) ->setQueryName($name) ->setQueryKey($key) ->setSequence((1 << 24) + $sequence++) ->setIsBuiltin(true); } return $queries; } /** * @task builtin */ public function getBuiltinQuery($query_key) { if (!$this->isBuiltinQuery($query_key)) { throw new Exception(pht("'%s' is not a builtin!", $query_key)); } return idx($this->getBuiltinQueries(), $query_key); } /** * @task builtin */ protected function getBuiltinQueryNames() { return array(); } /** * @task builtin */ public function isBuiltinQuery($query_key) { $builtins = $this->getBuiltinQueries(); return isset($builtins[$query_key]); } /** * @task builtin */ public function buildSavedQueryFromBuiltin($query_key) { throw new Exception(pht("Builtin '%s' is not supported!", $query_key)); } /* -( Reading Utilities )--------------------------------------------------- */ /** * Read a list of user PHIDs from a request in a flexible way. This method * supports either of these forms: * * users[]=alincoln&users[]=htaft * users=alincoln,htaft * * Additionally, users can be specified either by PHID or by name. * * The main goal of this flexibility is to allow external programs to generate * links to pages (like "alincoln's open revisions") without needing to make * API calls. * * @param AphrontRequest Request to read user PHIDs from. * @param string Key to read in the request. * @param list Other permitted PHID types. * @return list List of user PHIDs and selector functions. * @task read */ protected function readUsersFromRequest( AphrontRequest $request, $key, array $allow_types = array()) { $list = $this->readListFromRequest($request, $key); $phids = array(); $names = array(); $allow_types = array_fuse($allow_types); $user_type = PhabricatorPeopleUserPHIDType::TYPECONST; foreach ($list as $item) { $type = phid_get_type($item); if ($type == $user_type) { $phids[] = $item; } else if (isset($allow_types[$type])) { $phids[] = $item; } else { if (PhabricatorTypeaheadDatasource::isFunctionToken($item)) { // If this is a function, pass it through unchanged; we'll evaluate // it later. $phids[] = $item; } else { $names[] = $item; } } } if ($names) { $users = id(new PhabricatorPeopleQuery()) ->setViewer($this->requireViewer()) ->withUsernames($names) ->execute(); foreach ($users as $user) { $phids[] = $user->getPHID(); } $phids = array_unique($phids); } return $phids; } /** * Read a list of subscribers from a request in a flexible way. * * @param AphrontRequest Request to read PHIDs from. * @param string Key to read in the request. * @return list List of object PHIDs. * @task read */ protected function readSubscribersFromRequest( AphrontRequest $request, $key) { return $this->readUsersFromRequest( $request, $key, array( PhabricatorProjectProjectPHIDType::TYPECONST, )); } /** * Read a list of generic PHIDs from a request in a flexible way. Like * @{method:readUsersFromRequest}, this method supports either array or * comma-delimited forms. Objects can be specified either by PHID or by * object name. * * @param AphrontRequest Request to read PHIDs from. * @param string Key to read in the request. * @param list Optional, list of permitted PHID types. * @return list List of object PHIDs. * * @task read */ protected function readPHIDsFromRequest( AphrontRequest $request, $key, array $allow_types = array()) { $list = $this->readListFromRequest($request, $key); $objects = id(new PhabricatorObjectQuery()) ->setViewer($this->requireViewer()) ->withNames($list) ->execute(); $list = mpull($objects, 'getPHID'); if (!$list) { return array(); } // If only certain PHID types are allowed, filter out all the others. if ($allow_types) { $allow_types = array_fuse($allow_types); foreach ($list as $key => $phid) { if (empty($allow_types[phid_get_type($phid)])) { unset($list[$key]); } } } return $list; } /** * Read a list of items from the request, in either array format or string * format: * * list[]=item1&list[]=item2 * list=item1,item2 * * This provides flexibility when constructing URIs, especially from external * sources. * * @param AphrontRequest Request to read strings from. * @param string Key to read in the request. * @return list List of values. */ protected function readListFromRequest( AphrontRequest $request, $key) { $list = $request->getArr($key, null); if ($list === null) { $list = $request->getStrList($key); } if (!$list) { return array(); } return $list; } protected function readBoolFromRequest( AphrontRequest $request, $key) { if (!strlen($request->getStr($key))) { return null; } return $request->getBool($key); } protected function getBoolFromQuery(PhabricatorSavedQuery $query, $key) { $value = $query->getParameter($key); if ($value === null) { return $value; } return $value ? 'true' : 'false'; } /* -( Dates )-------------------------------------------------------------- */ /** * @task dates */ protected function parseDateTime($date_time) { if (!strlen($date_time)) { return null; } return PhabricatorTime::parseLocalTime($date_time, $this->requireViewer()); } /** * @task dates */ protected function buildDateRange( AphrontFormView $form, PhabricatorSavedQuery $saved_query, $start_key, $start_name, $end_key, $end_name) { $start_str = $saved_query->getParameter($start_key); $start = null; if (strlen($start_str)) { $start = $this->parseDateTime($start_str); if (!$start) { $this->addError( pht( '"%s" date can not be parsed.', $start_name)); } } $end_str = $saved_query->getParameter($end_key); $end = null; if (strlen($end_str)) { $end = $this->parseDateTime($end_str); if (!$end) { $this->addError( pht( '"%s" date can not be parsed.', $end_name)); } } if ($start && $end && ($start >= $end)) { $this->addError( pht( '"%s" must be a date before "%s".', $start_name, $end_name)); } $form ->appendChild( id(new PHUIFormFreeformDateControl()) ->setName($start_key) ->setLabel($start_name) ->setValue($start_str)) ->appendChild( id(new AphrontFormTextControl()) ->setName($end_key) ->setLabel($end_name) ->setValue($end_str)); } /* -( Paging and Executing Queries )--------------------------------------- */ protected function newResultBuckets() { return array(); } protected function getResultBucket(PhabricatorSavedQuery $saved) { $key = $saved->getParameter('bucket'); if ($key == self::BUCKET_NONE) { return null; } $buckets = $this->newResultBuckets(); return idx($buckets, $key); } public function getPageSize(PhabricatorSavedQuery $saved) { $bucket = $this->getResultBucket($saved); $limit = (int)$saved->getParameter('limit'); if ($limit > 0) { if ($bucket) { $bucket->setPageSize($limit); } return $limit; } if ($bucket) { return $bucket->getPageSize(); } return 100; } public function shouldUseOffsetPaging() { return false; } public function newPagerForSavedQuery(PhabricatorSavedQuery $saved) { if ($this->shouldUseOffsetPaging()) { $pager = new PHUIPagerView(); } else { $pager = new AphrontCursorPagerView(); } $page_size = $this->getPageSize($saved); if (is_finite($page_size)) { $pager->setPageSize($page_size); } else { // Consider an INF pagesize to mean a large finite pagesize. // TODO: It would be nice to handle this more gracefully, but math // with INF seems to vary across PHP versions, systems, and runtimes. $pager->setPageSize(0xFFFF); } return $pager; } public function executeQuery( PhabricatorPolicyAwareQuery $query, AphrontView $pager) { $query->setViewer($this->requireViewer()); if ($this->shouldUseOffsetPaging()) { $objects = $query->executeWithOffsetPager($pager); } else { $objects = $query->executeWithCursorPager($pager); } return $objects; } /* -( Rendering )---------------------------------------------------------- */ public function setRequest(AphrontRequest $request) { $this->request = $request; return $this; } public function getRequest() { return $this->request; } public function renderResults( array $objects, PhabricatorSavedQuery $query) { $phids = $this->getRequiredHandlePHIDsForResultList($objects, $query); if ($phids) { $handles = id(new PhabricatorHandleQuery()) ->setViewer($this->requireViewer()) ->witHPHIDs($phids) ->execute(); } else { $handles = array(); } return $this->renderResultList($objects, $query, $handles); } protected function getRequiredHandlePHIDsForResultList( array $objects, PhabricatorSavedQuery $query) { return array(); } abstract protected function renderResultList( array $objects, PhabricatorSavedQuery $query, array $handles); /* -( Application Search )------------------------------------------------- */ public function getSearchFieldsForConduit() { $standard_fields = $this->buildSearchFields(); $fields = array(); foreach ($standard_fields as $field_key => $field) { $conduit_key = $field->getConduitKey(); if (isset($fields[$conduit_key])) { $other = $fields[$conduit_key]; $other_key = $other->getKey(); throw new Exception( pht( 'SearchFields "%s" (of class "%s") and "%s" (of class "%s") both '. 'define the same Conduit key ("%s"). Keys must be unique.', $field_key, get_class($field), $other_key, get_class($other), $conduit_key)); } $fields[$conduit_key] = $field; } // These are handled separately for Conduit, so don't show them as // supported. unset($fields['order']); unset($fields['limit']); $viewer = $this->requireViewer(); foreach ($fields as $key => $field) { $field->setViewer($viewer); } return $fields; } public function buildConduitResponse( ConduitAPIRequest $request, ConduitAPIMethod $method) { $viewer = $this->requireViewer(); $query_key = $request->getValue('queryKey'); if (!strlen($query_key)) { $saved_query = new PhabricatorSavedQuery(); } else if ($this->isBuiltinQuery($query_key)) { $saved_query = $this->buildSavedQueryFromBuiltin($query_key); } else { $saved_query = id(new PhabricatorSavedQueryQuery()) ->setViewer($viewer) ->withQueryKeys(array($query_key)) ->executeOne(); if (!$saved_query) { throw new Exception( pht( 'Query key "%s" does not correspond to a valid query.', $query_key)); } } $constraints = $request->getValue('constraints', array()); $fields = $this->getSearchFieldsForConduit(); foreach ($fields as $key => $field) { if (!$field->getConduitParameterType()) { unset($fields[$key]); } } $valid_constraints = array(); foreach ($fields as $field) { foreach ($field->getValidConstraintKeys() as $key) { $valid_constraints[$key] = true; } } foreach ($constraints as $key => $constraint) { if (empty($valid_constraints[$key])) { throw new Exception( pht( 'Constraint "%s" is not a valid constraint for this query.', $key)); } } foreach ($fields as $field) { if (!$field->getValueExistsInConduitRequest($constraints)) { continue; } - $value = $field->readValueFromConduitRequest($constraints); + $value = $field->readValueFromConduitRequest( + $constraints, + $request->getIsStrictlyTyped()); $saved_query->setParameter($field->getKey(), $value); } // NOTE: Currently, when running an ad-hoc query we never persist it into // a saved query. We might want to add an option to do this in the future // (for example, to enable a CLI-to-Web workflow where user can view more // details about results by following a link), but have no use cases for // it today. If we do identify a use case, we could save the query here. $query = $this->buildQueryFromSavedQuery($saved_query); $pager = $this->newPagerForSavedQuery($saved_query); $attachments = $this->getConduitSearchAttachments(); // TODO: Validate this better. $attachment_specs = $request->getValue('attachments', array()); $attachments = array_select_keys( $attachments, array_keys($attachment_specs)); foreach ($attachments as $key => $attachment) { $attachment->setViewer($viewer); } foreach ($attachments as $key => $attachment) { $attachment->willLoadAttachmentData($query, $attachment_specs[$key]); } $this->setQueryOrderForConduit($query, $request); $this->setPagerLimitForConduit($pager, $request); $this->setPagerOffsetsForConduit($pager, $request); $objects = $this->executeQuery($query, $pager); $data = array(); if ($objects) { $field_extensions = $this->getConduitFieldExtensions(); $extension_data = array(); foreach ($field_extensions as $key => $extension) { $extension_data[$key] = $extension->loadExtensionConduitData($objects); } $attachment_data = array(); foreach ($attachments as $key => $attachment) { $attachment_data[$key] = $attachment->loadAttachmentData( $objects, $attachment_specs[$key]); } foreach ($objects as $object) { $field_map = $this->getObjectWireFieldsForConduit( $object, $field_extensions, $extension_data); $attachment_map = array(); foreach ($attachments as $key => $attachment) { $attachment_map[$key] = $attachment->getAttachmentForObject( $object, $attachment_data[$key], $attachment_specs[$key]); } // If this is empty, we still want to emit a JSON object, not a // JSON list. if (!$attachment_map) { $attachment_map = (object)$attachment_map; } $id = (int)$object->getID(); $phid = $object->getPHID(); $data[] = array( 'id' => $id, 'type' => phid_get_type($phid), 'phid' => $phid, 'fields' => $field_map, 'attachments' => $attachment_map, ); } } return array( 'data' => $data, 'maps' => $method->getQueryMaps($query), 'query' => array( // This may be `null` if we have not saved the query. 'queryKey' => $saved_query->getQueryKey(), ), 'cursor' => array( 'limit' => $pager->getPageSize(), 'after' => $pager->getNextPageID(), 'before' => $pager->getPrevPageID(), 'order' => $request->getValue('order'), ), ); } public function getAllConduitFieldSpecifications() { $extensions = $this->getConduitFieldExtensions(); $object = $this->newQuery()->newResultObject(); $map = array(); foreach ($extensions as $extension) { $specifications = $extension->getFieldSpecificationsForConduit($object); foreach ($specifications as $specification) { $key = $specification->getKey(); if (isset($map[$key])) { throw new Exception( pht( 'Two field specifications share the same key ("%s"). Each '. 'specification must have a unique key.', $key)); } $map[$key] = $specification; } } return $map; } private function getEngineExtensions() { $extensions = PhabricatorSearchEngineExtension::getAllEnabledExtensions(); foreach ($extensions as $key => $extension) { $extension ->setViewer($this->requireViewer()) ->setSearchEngine($this); } $object = $this->newResultObject(); foreach ($extensions as $key => $extension) { if (!$extension->supportsObject($object)) { unset($extensions[$key]); } } return $extensions; } private function getConduitFieldExtensions() { $extensions = $this->getEngineExtensions(); $object = $this->newResultObject(); foreach ($extensions as $key => $extension) { if (!$extension->getFieldSpecificationsForConduit($object)) { unset($extensions[$key]); } } return $extensions; } private function setQueryOrderForConduit($query, ConduitAPIRequest $request) { $order = $request->getValue('order'); if ($order === null) { return; } if (is_scalar($order)) { $query->setOrder($order); } else { $query->setOrderVector($order); } } private function setPagerLimitForConduit($pager, ConduitAPIRequest $request) { $limit = $request->getValue('limit'); // If there's no limit specified and the query uses a weird huge page // size, just leave it at the default gigantic page size. Otherwise, // make sure it's between 1 and 100, inclusive. if ($limit === null) { if ($pager->getPageSize() >= 0xFFFF) { return; } else { $limit = 100; } } if ($limit > 100) { throw new Exception( pht( 'Maximum page size for Conduit API method calls is 100, but '. 'this call specified %s.', $limit)); } if ($limit < 1) { throw new Exception( pht( 'Minimum page size for API searches is 1, but this call '. 'specified %s.', $limit)); } $pager->setPageSize($limit); } private function setPagerOffsetsForConduit( $pager, ConduitAPIRequest $request) { $before_id = $request->getValue('before'); if ($before_id !== null) { $pager->setBeforeID($before_id); } $after_id = $request->getValue('after'); if ($after_id !== null) { $pager->setAfterID($after_id); } } protected function getObjectWireFieldsForConduit( $object, array $field_extensions, array $extension_data) { $fields = array(); foreach ($field_extensions as $key => $extension) { $data = idx($extension_data, $key, array()); $fields += $extension->getFieldValuesForConduit($object, $data); } return $fields; } public function getConduitSearchAttachments() { $extensions = $this->getEngineExtensions(); $object = $this->newResultObject(); $attachments = array(); foreach ($extensions as $extension) { $extension_attachments = $extension->getSearchAttachments($object); foreach ($extension_attachments as $attachment) { $attachment_key = $attachment->getAttachmentKey(); if (isset($attachments[$attachment_key])) { $other = $attachments[$attachment_key]; throw new Exception( pht( 'Two search engine attachments (of classes "%s" and "%s") '. 'specify the same attachment key ("%s"); keys must be unique.', get_class($attachment), get_class($other), $attachment_key)); } $attachments[$attachment_key] = $attachment; } } return $attachments; } final public function renderNewUserView() { $body = $this->getNewUserBody(); if (!$body) { return null; } return $body; } protected function getNewUserHeader() { return null; } protected function getNewUserBody() { return null; } public function newUseResultsActions(PhabricatorSavedQuery $saved) { return array(); } } diff --git a/src/applications/search/field/PhabricatorSearchField.php b/src/applications/search/field/PhabricatorSearchField.php index d31aeb1950..f45befead6 100644 --- a/src/applications/search/field/PhabricatorSearchField.php +++ b/src/applications/search/field/PhabricatorSearchField.php @@ -1,374 +1,378 @@ key = $key; return $this; } /** * Get the field's key. * * @return string Unique key for this field. * @task config */ public function getKey() { return $this->key; } /** * Set a human-readable label for the field. * * This should be a short text string, like "Reviewers" or "Colors". * * @param string Short, human-readable field label. * @return this * task config */ public function setLabel($label) { $this->label = $label; return $this; } /** * Get the field's human-readable label. * * @return string Short, human-readable field label. * @task config */ public function getLabel() { return $this->label; } /** * Set the acting viewer. * * Engines do not need to do this explicitly; it will be done on their * behalf by the caller. * * @param PhabricatorUser Viewer. * @return this * @task config */ public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; return $this; } /** * Get the acting viewer. * * @return PhabricatorUser Viewer. * @task config */ public function getViewer() { return $this->viewer; } /** * Provide alternate field aliases, usually more human-readable versions * of the key. * * These aliases can be used when building GET requests, so you can provide * an alias like `authors` to let users write `&authors=alincoln` instead of * `&authorPHIDs=alincoln`. This is a little easier to use. * * @param list List of aliases for this field. * @return this * @task config */ public function setAliases(array $aliases) { $this->aliases = $aliases; return $this; } /** * Get aliases for this field. * * @return list List of aliases for this field. * @task config */ public function getAliases() { return $this->aliases; } /** * Provide an alternate field key for Conduit. * * This can allow you to choose a more usable key for API endpoints. * If no key is provided, the main key is used. * * @param string Alternate key for Conduit. * @return this * @task config */ public function setConduitKey($conduit_key) { $this->conduitKey = $conduit_key; return $this; } /** * Get the field key for use in Conduit. * * @return string Conduit key for this field. * @task config */ public function getConduitKey() { if ($this->conduitKey !== null) { return $this->conduitKey; } return $this->getKey(); } /** * Set a human-readable description for this field. * * @param string Human-readable description. * @return this * @task config */ public function setDescription($description) { $this->description = $description; return $this; } /** * Get this field's human-readable description. * * @return string|null Human-readable description. * @task config */ public function getDescription() { return $this->description; } /* -( Handling Errors )---------------------------------------------------- */ protected function addError($short, $long) { $this->errors[] = array($short, $long); return $this; } public function getErrors() { return $this->errors; } protected function validateControlValue($value) { return; } protected function getShortError() { $error = head($this->getErrors()); if ($error) { return head($error); } return null; } /* -( Reading and Writing Field Values )----------------------------------- */ public function readValueFromRequest(AphrontRequest $request) { $check = array_merge(array($this->getKey()), $this->getAliases()); foreach ($check as $key) { if ($this->getValueExistsInRequest($request, $key)) { return $this->getValueFromRequest($request, $key); } } return $this->getDefaultValue(); } protected function getValueExistsInRequest(AphrontRequest $request, $key) { return $request->getExists($key); } abstract protected function getValueFromRequest( AphrontRequest $request, $key); public function readValueFromSavedQuery(PhabricatorSavedQuery $saved) { $value = $saved->getParameter( $this->getKey(), $this->getDefaultValue()); $this->value = $this->didReadValueFromSavedQuery($value); $this->validateControlValue($value); return $this; } protected function didReadValueFromSavedQuery($value) { return $value; } public function getValue() { return $this->value; } protected function getValueForControl() { return $this->value; } protected function getDefaultValue() { return null; } public function getValueForQuery($value) { return $value; } /* -( Rendering Controls )------------------------------------------------- */ protected function newControl() { throw new PhutilMethodNotImplementedException(); } protected function renderControl() { $control = $this->newControl(); if (!$control) { return null; } // TODO: We should `setError($this->getShortError())` here, but it looks // terrible in the form layout. return $control ->setValue($this->getValueForControl()) ->setName($this->getKey()) ->setLabel($this->getLabel()); } public function appendToForm(AphrontFormView $form) { $control = $this->renderControl(); if ($control !== null) { $form->appendControl($this->renderControl()); } return $this; } /* -( Integration with Conduit )------------------------------------------- */ /** * @task conduit */ final public function getConduitParameterType() { $type = $this->newConduitParameterType(); if ($type) { $type->setViewer($this->getViewer()); } return $type; } protected function newConduitParameterType() { return null; } public function getValueExistsInConduitRequest(array $constraints) { return $this->getConduitParameterType()->getExists( $constraints, $this->getConduitKey()); } - public function readValueFromConduitRequest(array $constraints) { + public function readValueFromConduitRequest( + array $constraints, + $strict = true) { + return $this->getConduitParameterType()->getValue( $constraints, - $this->getConduitKey()); + $this->getConduitKey(), + $strict); } public function getValidConstraintKeys() { return $this->getConduitParameterType()->getKeys( $this->getConduitKey()); } /* -( Utility Methods )----------------------------------------------------- */ /** * Read a list of items from the request, in either array format or string * format: * * list[]=item1&list[]=item2 * list=item1,item2 * * This provides flexibility when constructing URIs, especially from external * sources. * * @param AphrontRequest Request to read strings from. * @param string Key to read in the request. * @return list List of values. * @task utility */ protected function getListFromRequest( AphrontRequest $request, $key) { $list = $request->getArr($key, null); if ($list === null) { $list = $request->getStrList($key); } if (!$list) { return array(); } return $list; } } diff --git a/src/applications/search/view/PhabricatorApplicationSearchResultView.php b/src/applications/search/view/PhabricatorApplicationSearchResultView.php index 1c3f4aad65..3576d5238e 100644 --- a/src/applications/search/view/PhabricatorApplicationSearchResultView.php +++ b/src/applications/search/view/PhabricatorApplicationSearchResultView.php @@ -1,99 +1,97 @@ objectList = $list; return $this; } public function getObjectList() { $list = $this->objectList; if ($list) { if ($this->noDataString) { $list->setNoDataString($this->noDataString); } else { $list->setNoDataString(pht('No results found for this query.')); } } return $list; } public function setTable($table) { $this->table = $table; return $this; } public function getTable() { return $this->table; } public function setInfoView(PHUIInfoView $infoview) { $this->infoView = $infoview; return $this; } public function getInfoView() { return $this->infoView; } public function setContent($content) { $this->content = $content; return $this; } public function getContent() { return $this->content; } public function addAction(PHUIButtonView $button) { $this->actions[] = $button; return $this; } public function getActions() { return $this->actions; } public function setNoDataString($nodata) { $this->noDataString = $nodata; return $this; } public function setCrumbs(array $crumbs) { assert_instances_of($crumbs, 'PHUICrumbView'); $this->crumbs = $crumbs; return $this; } public function getCrumbs() { return $this->crumbs; } public function setHeader(PHUIHeaderView $header) { $this->header = $header; return $this; } public function getHeader() { return $this->header; } - - } diff --git a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php index 6896f7ba2f..78c21f5d65 100644 --- a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php +++ b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php @@ -1,218 +1,218 @@ setViewer($actor) ->withClasses(array('PhabricatorSlowvoteApplication')) ->executeOne(); $view_policy = $app->getPolicy( PhabricatorSlowvoteDefaultViewCapability::CAPABILITY); return id(new PhabricatorSlowvotePoll()) ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy) ->setSpacePHID($actor->getDefaultSpacePHID()); } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_COLUMN_SCHEMA => array( 'question' => 'text255', 'responseVisibility' => 'uint32', 'shuffle' => 'uint32', 'method' => 'uint32', 'description' => 'text', 'isClosed' => 'bool', 'mailKey' => 'bytes20', ), self::CONFIG_KEY_SCHEMA => array( 'key_phid' => null, 'phid' => array( 'columns' => array('phid'), 'unique' => true, ), ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorSlowvotePollPHIDType::TYPECONST); } public function getOptions() { return $this->assertAttached($this->options); } public function attachOptions(array $options) { assert_instances_of($options, 'PhabricatorSlowvoteOption'); $this->options = $options; return $this; } public function getChoices() { return $this->assertAttached($this->choices); } public function attachChoices(array $choices) { assert_instances_of($choices, 'PhabricatorSlowvoteChoice'); $this->choices = $choices; return $this; } public function getViewerChoices(PhabricatorUser $viewer) { return $this->assertAttachedKey($this->viewerChoices, $viewer->getPHID()); } public function attachViewerChoices(PhabricatorUser $viewer, array $choices) { if ($this->viewerChoices === self::ATTACHABLE) { $this->viewerChoices = array(); } assert_instances_of($choices, 'PhabricatorSlowvoteChoice'); $this->viewerChoices[$viewer->getPHID()] = $choices; return $this; } public function getMonogram() { return 'V'.$this->getID(); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new PhabricatorSlowvoteEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new PhabricatorSlowvoteTransaction(); } public function willRenderTimeline( PhabricatorApplicationTransactionView $timeline, AphrontRequest $request) { return $timeline; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->viewPolicy; case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return ($viewer->getPHID() == $this->getAuthorPHID()); } public function describeAutomaticCapability($capability) { return pht('The author of a poll can always view and edit it.'); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return ($phid == $this->getAuthorPHID()); } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array($this->getAuthorPHID()); } -/* -( PhabricatorDestructableInterface )----------------------------------- */ +/* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $choices = id(new PhabricatorSlowvoteChoice())->loadAllWhere( 'pollID = %d', $this->getID()); foreach ($choices as $choice) { $choice->delete(); } $options = id(new PhabricatorSlowvoteOption())->loadAllWhere( 'pollID = %d', $this->getID()); foreach ($options as $option) { $option->delete(); } $this->delete(); $this->saveTransaction(); } /* -( PhabricatorSpacesInterface )--------------------------------------- */ public function getSpacePHID() { return $this->spacePHID; } } diff --git a/src/applications/system/application/PhabricatorSystemApplication.php b/src/applications/system/application/PhabricatorSystemApplication.php index 0ec8f6a7a4..7ce2b4dbe0 100644 --- a/src/applications/system/application/PhabricatorSystemApplication.php +++ b/src/applications/system/application/PhabricatorSystemApplication.php @@ -1,32 +1,33 @@ 'PhabricatorStatusController', '/debug/' => 'PhabricatorDebugController', '/robots.txt' => 'PhabricatorRobotsController', '/services/' => array( 'encoding/' => 'PhabricatorSystemSelectEncodingController', 'highlight/' => 'PhabricatorSystemSelectHighlightController', ), '/readonly/' => array( '(?P[^/]+)/' => 'PhabricatorSystemReadOnlyController', ), + '/favicon.ico' => 'PhabricatorSystemFaviconController', ); } } diff --git a/src/applications/system/controller/PhabricatorSystemFaviconController.php b/src/applications/system/controller/PhabricatorSystemFaviconController.php new file mode 100644 index 0000000000..d9a31cbcb6 --- /dev/null +++ b/src/applications/system/controller/PhabricatorSystemFaviconController.php @@ -0,0 +1,19 @@ +setContent($content) + ->setMimeType('image/x-icon') + ->setCacheDurationInSeconds(phutil_units('24 hours in seconds')) + ->setCanCDN(true); + } +} diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 2805162336..8a71509c99 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -1,2195 +1,2198 @@ viewer = $viewer; return $this; } final public function getViewer() { return $this->viewer; } final public function setController(PhabricatorController $controller) { $this->controller = $controller; $this->setViewer($controller->getViewer()); return $this; } final public function getController() { return $this->controller; } final public function getEngineKey() { return $this->getPhobjectClassConstant('ENGINECONST', 64); } final public function getApplication() { $app_class = $this->getEngineApplicationClass(); return PhabricatorApplication::getByClass($app_class); } final public function addContextParameter($key) { $this->contextParameters[] = $key; return $this; } public function isEngineConfigurable() { return true; } public function isEngineExtensible() { return true; } /** * Force the engine to edit a particular object. */ public function setTargetObject($target_object) { $this->targetObject = $target_object; return $this; } public function getTargetObject() { return $this->targetObject; } public function setNavigation(AphrontSideNavFilterView $navigation) { $this->navigation = $navigation; return $this; } public function getNavigation() { return $this->navigation; } public function setHideHeader($hide_header) { $this->hideHeader = $hide_header; return $this; } public function getHideHeader() { return $this->hideHeader; } /* -( Managing Fields )---------------------------------------------------- */ abstract public function getEngineApplicationClass(); abstract protected function buildCustomEditFields($object); public function getFieldsForConfig( PhabricatorEditEngineConfiguration $config) { $object = $this->newEditableObject(); $this->editEngineConfiguration = $config; // This is mostly making sure that we fill in default values. $this->setIsCreate(true); return $this->buildEditFields($object); } final protected function buildEditFields($object) { $viewer = $this->getViewer(); $fields = $this->buildCustomEditFields($object); foreach ($fields as $field) { $field ->setViewer($viewer) ->setObject($object); } $fields = mpull($fields, null, 'getKey'); if ($this->isEngineExtensible()) { $extensions = PhabricatorEditEngineExtension::getAllEnabledExtensions(); } else { $extensions = array(); } foreach ($extensions as $extension) { $extension->setViewer($viewer); if (!$extension->supportsObject($this, $object)) { continue; } $extension_fields = $extension->buildCustomEditFields($this, $object); // TODO: Validate this in more detail with a more tailored error. assert_instances_of($extension_fields, 'PhabricatorEditField'); foreach ($extension_fields as $field) { $field ->setViewer($viewer) ->setObject($object); } $extension_fields = mpull($extension_fields, null, 'getKey'); foreach ($extension_fields as $key => $field) { $fields[$key] = $field; } } $config = $this->getEditEngineConfiguration(); $fields = $this->willConfigureFields($object, $fields); $fields = $config->applyConfigurationToFields($this, $object, $fields); $fields = $this->applyPageToFields($object, $fields); return $fields; } protected function willConfigureFields($object, array $fields) { return $fields; } /* -( Display Text )------------------------------------------------------- */ /** * @task text */ abstract public function getEngineName(); /** * @task text */ abstract protected function getObjectCreateTitleText($object); /** * @task text */ protected function getFormHeaderText($object) { $config = $this->getEditEngineConfiguration(); return $config->getName(); } /** * @task text */ abstract protected function getObjectEditTitleText($object); /** * @task text */ abstract protected function getObjectCreateShortText(); /** * @task text */ abstract protected function getObjectName(); /** * @task text */ abstract protected function getObjectEditShortText($object); /** * @task text */ protected function getObjectCreateButtonText($object) { return $this->getObjectCreateTitleText($object); } /** * @task text */ protected function getObjectEditButtonText($object) { return pht('Save Changes'); } /** * @task text */ protected function getCommentViewSeriousHeaderText($object) { return pht('Take Action'); } /** * @task text */ protected function getCommentViewSeriousButtonText($object) { return pht('Submit'); } /** * @task text */ protected function getCommentViewHeaderText($object) { return $this->getCommentViewSeriousHeaderText($object); } /** * @task text */ protected function getCommentViewButtonText($object) { return $this->getCommentViewSeriousButtonText($object); } /** * @task text */ protected function getQuickCreateMenuHeaderText() { return $this->getObjectCreateShortText(); } /** * Return a human-readable header describing what this engine is used to do, * like "Configure Maniphest Task Forms". * * @return string Human-readable description of the engine. * @task text */ abstract public function getSummaryHeader(); /** * Return a human-readable summary of what this engine is used to do. * * @return string Human-readable description of the engine. * @task text */ abstract public function getSummaryText(); /* -( Edit Engine Configuration )------------------------------------------ */ protected function supportsEditEngineConfiguration() { return true; } final protected function getEditEngineConfiguration() { return $this->editEngineConfiguration; } private function newConfigurationQuery() { return id(new PhabricatorEditEngineConfigurationQuery()) ->setViewer($this->getViewer()) ->withEngineKeys(array($this->getEngineKey())); } private function loadEditEngineConfigurationWithQuery( PhabricatorEditEngineConfigurationQuery $query, $sort_method) { if ($sort_method) { $results = $query->execute(); $results = msort($results, $sort_method); $result = head($results); } else { $result = $query->executeOne(); } if (!$result) { return null; } $this->editEngineConfiguration = $result; return $result; } private function loadEditEngineConfigurationWithIdentifier($identifier) { $query = $this->newConfigurationQuery() ->withIdentifiers(array($identifier)); return $this->loadEditEngineConfigurationWithQuery($query, null); } private function loadDefaultConfiguration() { $query = $this->newConfigurationQuery() ->withIdentifiers( array( self::EDITENGINECONFIG_DEFAULT, )) ->withIgnoreDatabaseConfigurations(true); return $this->loadEditEngineConfigurationWithQuery($query, null); } private function loadDefaultCreateConfiguration() { $query = $this->newConfigurationQuery() ->withIsDefault(true) ->withIsDisabled(false); return $this->loadEditEngineConfigurationWithQuery( $query, 'getCreateSortKey'); } public function loadDefaultEditConfiguration() { $query = $this->newConfigurationQuery() ->withIsEdit(true) ->withIsDisabled(false); return $this->loadEditEngineConfigurationWithQuery( $query, 'getEditSortKey'); } final public function getBuiltinEngineConfigurations() { $configurations = $this->newBuiltinEngineConfigurations(); if (!$configurations) { throw new Exception( pht( 'EditEngine ("%s") returned no builtin engine configurations, but '. 'an edit engine must have at least one configuration.', get_class($this))); } assert_instances_of($configurations, 'PhabricatorEditEngineConfiguration'); $has_default = false; foreach ($configurations as $config) { if ($config->getBuiltinKey() == self::EDITENGINECONFIG_DEFAULT) { $has_default = true; } } if (!$has_default) { $first = head($configurations); if (!$first->getBuiltinKey()) { $first ->setBuiltinKey(self::EDITENGINECONFIG_DEFAULT) ->setIsDefault(true) ->setIsEdit(true); if (!strlen($first->getName())) { $first->setName($this->getObjectCreateShortText()); } } else { throw new Exception( pht( 'EditEngine ("%s") returned builtin engine configurations, '. 'but none are marked as default and the first configuration has '. 'a different builtin key already. Mark a builtin as default or '. 'omit the key from the first configuration', get_class($this))); } } $builtins = array(); foreach ($configurations as $key => $config) { $builtin_key = $config->getBuiltinKey(); if ($builtin_key === null) { throw new Exception( pht( 'EditEngine ("%s") returned builtin engine configurations, '. 'but one (with key "%s") is missing a builtin key. Provide a '. 'builtin key for each configuration (you can omit it from the '. 'first configuration in the list to automatically assign the '. 'default key).', get_class($this), $key)); } if (isset($builtins[$builtin_key])) { throw new Exception( pht( 'EditEngine ("%s") returned builtin engine configurations, '. 'but at least two specify the same builtin key ("%s"). Engines '. 'must have unique builtin keys.', get_class($this), $builtin_key)); } $builtins[$builtin_key] = $config; } return $builtins; } protected function newBuiltinEngineConfigurations() { return array( $this->newConfiguration(), ); } final protected function newConfiguration() { return PhabricatorEditEngineConfiguration::initializeNewConfiguration( $this->getViewer(), $this); } /* -( Managing URIs )------------------------------------------------------ */ /** * @task uri */ abstract protected function getObjectViewURI($object); /** * @task uri */ protected function getObjectCreateCancelURI($object) { return $this->getApplication()->getApplicationURI(); } /** * @task uri */ protected function getEditorURI() { return $this->getApplication()->getApplicationURI('edit/'); } /** * @task uri */ protected function getObjectEditCancelURI($object) { return $this->getObjectViewURI($object); } /** * @task uri */ public function getEditURI($object = null, $path = null) { $parts = array(); $parts[] = $this->getEditorURI(); if ($object && $object->getID()) { $parts[] = $object->getID().'/'; } if ($path !== null) { $parts[] = $path; } return implode('', $parts); } public function getEffectiveObjectViewURI($object) { if ($this->getIsCreate()) { return $this->getObjectViewURI($object); } $page = $this->getSelectedPage(); if ($page) { $view_uri = $page->getViewURI(); if ($view_uri !== null) { return $view_uri; } } return $this->getObjectViewURI($object); } public function getEffectiveObjectEditDoneURI($object) { return $this->getEffectiveObjectViewURI($object); } public function getEffectiveObjectEditCancelURI($object) { $page = $this->getSelectedPage(); if ($page) { $view_uri = $page->getViewURI(); if ($view_uri !== null) { return $view_uri; } } return $this->getObjectEditCancelURI($object); } /* -( Creating and Loading Objects )--------------------------------------- */ /** * Initialize a new object for creation. * * @return object Newly initialized object. * @task load */ abstract protected function newEditableObject(); /** * Build an empty query for objects. * * @return PhabricatorPolicyAwareQuery Query. * @task load */ abstract protected function newObjectQuery(); /** * Test if this workflow is creating a new object or editing an existing one. * * @return bool True if a new object is being created. * @task load */ final public function getIsCreate() { return $this->isCreate; } /** * Flag this workflow as a create or edit. * * @param bool True if this is a create workflow. * @return this * @task load */ private function setIsCreate($is_create) { $this->isCreate = $is_create; return $this; } /** * Try to load an object by ID, PHID, or monogram. This is done primarily * to make Conduit a little easier to use. * * @param wild ID, PHID, or monogram. * @param list List of required capability constants, or omit for * defaults. * @return object Corresponding editable object. * @task load */ private function newObjectFromIdentifier( $identifier, array $capabilities = array()) { if (is_int($identifier) || ctype_digit($identifier)) { $object = $this->newObjectFromID($identifier, $capabilities); if (!$object) { throw new Exception( pht( 'No object exists with ID "%s".', $identifier)); } return $object; } $type_unknown = PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN; if (phid_get_type($identifier) != $type_unknown) { $object = $this->newObjectFromPHID($identifier, $capabilities); if (!$object) { throw new Exception( pht( 'No object exists with PHID "%s".', $identifier)); } return $object; } $target = id(new PhabricatorObjectQuery()) ->setViewer($this->getViewer()) ->withNames(array($identifier)) ->executeOne(); if (!$target) { throw new Exception( pht( 'Monogram "%s" does not identify a valid object.', $identifier)); } $expect = $this->newEditableObject(); $expect_class = get_class($expect); $target_class = get_class($target); if ($expect_class !== $target_class) { throw new Exception( pht( 'Monogram "%s" identifies an object of the wrong type. Loaded '. 'object has class "%s", but this editor operates on objects of '. 'type "%s".', $identifier, $target_class, $expect_class)); } // Load the object by PHID using this engine's standard query. This makes // sure it's really valid, goes through standard policy check logic, and // picks up any `need...()` clauses we want it to load with. $object = $this->newObjectFromPHID($target->getPHID(), $capabilities); if (!$object) { throw new Exception( pht( 'Failed to reload object identified by monogram "%s" when '. 'querying by PHID.', $identifier)); } return $object; } /** * Load an object by ID. * * @param int Object ID. * @param list List of required capability constants, or omit for * defaults. * @return object|null Object, or null if no such object exists. * @task load */ private function newObjectFromID($id, array $capabilities = array()) { $query = $this->newObjectQuery() ->withIDs(array($id)); return $this->newObjectFromQuery($query, $capabilities); } /** * Load an object by PHID. * * @param phid Object PHID. * @param list List of required capability constants, or omit for * defaults. * @return object|null Object, or null if no such object exists. * @task load */ private function newObjectFromPHID($phid, array $capabilities = array()) { $query = $this->newObjectQuery() ->withPHIDs(array($phid)); return $this->newObjectFromQuery($query, $capabilities); } /** * Load an object given a configured query. * * @param PhabricatorPolicyAwareQuery Configured query. * @param list List of required capabilitiy constants, or omit for * defaults. * @return object|null Object, or null if no such object exists. * @task load */ private function newObjectFromQuery( PhabricatorPolicyAwareQuery $query, array $capabilities = array()) { $viewer = $this->getViewer(); if (!$capabilities) { $capabilities = array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } $object = $query ->setViewer($viewer) ->requireCapabilities($capabilities) ->executeOne(); if (!$object) { return null; } return $object; } /** * Verify that an object is appropriate for editing. * * @param wild Loaded value. * @return void * @task load */ private function validateObject($object) { if (!$object || !is_object($object)) { throw new Exception( pht( 'EditEngine "%s" created or loaded an invalid object: object must '. 'actually be an object, but is of some other type ("%s").', get_class($this), gettype($object))); } if (!($object instanceof PhabricatorApplicationTransactionInterface)) { throw new Exception( pht( 'EditEngine "%s" created or loaded an invalid object: object (of '. 'class "%s") must implement "%s", but does not.', get_class($this), get_class($object), 'PhabricatorApplicationTransactionInterface')); } } /* -( Responding to Web Requests )----------------------------------------- */ final public function buildResponse() { $viewer = $this->getViewer(); $controller = $this->getController(); $request = $controller->getRequest(); $action = $request->getURIData('editAction'); $capabilities = array(); $use_default = false; $require_create = true; switch ($action) { case 'comment': $capabilities = array( PhabricatorPolicyCapability::CAN_VIEW, ); $use_default = true; break; case 'parameters': $use_default = true; break; case 'nodefault': case 'nocreate': case 'nomanage': $require_create = false; break; default: break; } $object = $this->getTargetObject(); if (!$object) { $id = $request->getURIData('id'); if ($id) { $this->setIsCreate(false); $object = $this->newObjectFromID($id, $capabilities); if (!$object) { return new Aphront404Response(); } } else { // Make sure the viewer has permission to create new objects of // this type if we're going to create a new object. if ($require_create) { $this->requireCreateCapability(); } $this->setIsCreate(true); $object = $this->newEditableObject(); } } else { $id = $object->getID(); } $this->validateObject($object); if ($use_default) { $config = $this->loadDefaultConfiguration(); if (!$config) { return new Aphront404Response(); } } else { $form_key = $request->getURIData('formKey'); if (strlen($form_key)) { $config = $this->loadEditEngineConfigurationWithIdentifier($form_key); if (!$config) { return new Aphront404Response(); } if ($id && !$config->getIsEdit()) { return $this->buildNotEditFormRespose($object, $config); } } else { if ($id) { $config = $this->loadDefaultEditConfiguration(); if (!$config) { return $this->buildNoEditResponse($object); } } else { $config = $this->loadDefaultCreateConfiguration(); if (!$config) { return $this->buildNoCreateResponse($object); } } } } if ($config->getIsDisabled()) { return $this->buildDisabledFormResponse($object, $config); } $page_key = $request->getURIData('pageKey'); if (!strlen($page_key)) { $pages = $this->getPages($object); if ($pages) { $page_key = head_key($pages); } } if (strlen($page_key)) { $page = $this->selectPage($object, $page_key); if (!$page) { return new Aphront404Response(); } } switch ($action) { case 'parameters': return $this->buildParametersResponse($object); case 'nodefault': return $this->buildNoDefaultResponse($object); case 'nocreate': return $this->buildNoCreateResponse($object); case 'nomanage': return $this->buildNoManageResponse($object); case 'comment': return $this->buildCommentResponse($object); default: return $this->buildEditResponse($object); } } private function buildCrumbs($object, $final = false) { $controller = $this->getController(); $crumbs = $controller->buildApplicationCrumbsForEditEngine(); if ($this->getIsCreate()) { $create_text = $this->getObjectCreateShortText(); if ($final) { $crumbs->addTextCrumb($create_text); } else { $edit_uri = $this->getEditURI($object); $crumbs->addTextCrumb($create_text, $edit_uri); } } else { $crumbs->addTextCrumb( $this->getObjectEditShortText($object), $this->getEffectiveObjectViewURI($object)); $edit_text = pht('Edit'); if ($final) { $crumbs->addTextCrumb($edit_text); } else { $edit_uri = $this->getEditURI($object); $crumbs->addTextCrumb($edit_text, $edit_uri); } } return $crumbs; } private function buildEditResponse($object) { $viewer = $this->getViewer(); $controller = $this->getController(); $request = $controller->getRequest(); $fields = $this->buildEditFields($object); $template = $object->getApplicationTransactionTemplate(); $validation_exception = null; if ($request->isFormPost() && $request->getBool('editEngine')) { $submit_fields = $fields; foreach ($submit_fields as $key => $field) { if (!$field->shouldGenerateTransactionsFromSubmit()) { unset($submit_fields[$key]); continue; } } // Before we read the submitted values, store a copy of what we would // use if the form was empty so we can figure out which transactions are // just setting things to their default values for the current form. $defaults = array(); foreach ($submit_fields as $key => $field) { $defaults[$key] = $field->getValueForTransaction(); } foreach ($submit_fields as $key => $field) { $field->setIsSubmittedForm(true); if (!$field->shouldReadValueFromSubmit()) { continue; } $field->readValueFromSubmit($request); } $xactions = array(); if ($this->getIsCreate()) { $xactions[] = id(clone $template) ->setTransactionType(PhabricatorTransactions::TYPE_CREATE); } foreach ($submit_fields as $key => $field) { $field_value = $field->getValueForTransaction(); $type_xactions = $field->generateTransactions( clone $template, array( 'value' => $field_value, )); foreach ($type_xactions as $type_xaction) { $default = $defaults[$key]; if ($default === $field->getValueForTransaction()) { $type_xaction->setIsDefaultTransaction(true); } $xactions[] = $type_xaction; } } $editor = $object->getApplicationTransactionEditor() ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($object, $xactions); return $this->newEditResponse($request, $object, $xactions); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; foreach ($fields as $field) { $message = $this->getValidationExceptionShortMessage($ex, $field); if ($message === null) { continue; } $field->setControlError($message); } } } else { if ($this->getIsCreate()) { $template = $request->getStr('template'); if (strlen($template)) { $template_object = $this->newObjectFromIdentifier( $template, array( PhabricatorPolicyCapability::CAN_VIEW, )); if (!$template_object) { return new Aphront404Response(); } } else { $template_object = null; } if ($template_object) { $copy_fields = $this->buildEditFields($template_object); $copy_fields = mpull($copy_fields, null, 'getKey'); foreach ($copy_fields as $copy_key => $copy_field) { if (!$copy_field->getIsCopyable()) { unset($copy_fields[$copy_key]); } } } else { $copy_fields = array(); } foreach ($fields as $field) { if (!$field->shouldReadValueFromRequest()) { continue; } $field_key = $field->getKey(); if (isset($copy_fields[$field_key])) { $field->readValueFromField($copy_fields[$field_key]); } $field->readValueFromRequest($request); } } } $action_button = $this->buildEditFormActionButton($object); if ($this->getIsCreate()) { $header_text = $this->getFormHeaderText($object); $header_icon = 'fa-plus-square'; } else { $header_text = $this->getObjectEditTitleText($object); $header_icon = 'fa-pencil'; } $show_preview = !$request->isAjax(); if ($show_preview) { $previews = array(); foreach ($fields as $field) { $preview = $field->getPreviewPanel(); if (!$preview) { continue; } $control_id = $field->getControlID(); $preview ->setControlID($control_id) ->setPreviewURI('/transactions/remarkuppreview/'); $previews[] = $preview; } } else { $previews = array(); } $form = $this->buildEditForm($object, $fields); if ($request->isAjax()) { if ($this->getIsCreate()) { $cancel_uri = $this->getObjectCreateCancelURI($object); $submit_button = $this->getObjectCreateButtonText($object); } else { $cancel_uri = $this->getEffectiveObjectEditCancelURI($object); $submit_button = $this->getObjectEditButtonText($object); } return $this->getController() ->newDialog() ->setWidth(AphrontDialogView::WIDTH_FULL) ->setTitle($header_text) ->setValidationException($validation_exception) ->appendForm($form) ->addCancelButton($cancel_uri) ->addSubmitButton($submit_button); } $crumbs = $this->buildCrumbs($object, $final = true); if ($this->getHideHeader()) { $header = null; $crumbs->setBorder(false); } else { $header = id(new PHUIHeaderView()) ->setHeader($header_text) ->setHeaderIcon($header_icon); $crumbs->setBorder(true); } if ($action_button) { $header->addActionLink($action_button); } $box = id(new PHUIObjectBoxView()) ->setUser($viewer) ->setHeaderText($this->getObjectName()) ->setValidationException($validation_exception) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($form); // This is fairly questionable, but in use by Settings. if ($request->getURIData('formSaved')) { $box->setFormSaved(true); } $content = array( $box, $previews, ); $view = new PHUITwoColumnView(); if ($header) { $view->setHeader($header); } $navigation = $this->getNavigation(); if ($navigation) { $view ->setNavigation($navigation) ->setMainColumn($content); } else { $view->setFooter($content); } return $controller->newPage() ->setTitle($header_text) ->setCrumbs($crumbs) ->appendChild($view); } protected function newEditResponse( AphrontRequest $request, $object, array $xactions) { return id(new AphrontRedirectResponse()) ->setURI($this->getEffectiveObjectEditDoneURI($object)); } private function buildEditForm($object, array $fields) { $viewer = $this->getViewer(); $controller = $this->getController(); $request = $controller->getRequest(); $fields = $this->willBuildEditForm($object, $fields); $form = id(new AphrontFormView()) ->setUser($viewer) ->addHiddenInput('editEngine', 'true'); foreach ($this->contextParameters as $param) { $form->addHiddenInput($param, $request->getStr($param)); } foreach ($fields as $field) { $field->appendToForm($form); } if ($this->getIsCreate()) { $cancel_uri = $this->getObjectCreateCancelURI($object); $submit_button = $this->getObjectCreateButtonText($object); } else { $cancel_uri = $this->getEffectiveObjectEditCancelURI($object); $submit_button = $this->getObjectEditButtonText($object); } if (!$request->isAjax()) { $buttons = id(new AphrontFormSubmitControl()) ->setValue($submit_button); if ($cancel_uri) { $buttons->addCancelButton($cancel_uri); } $form->appendControl($buttons); } return $form; } protected function willBuildEditForm($object, array $fields) { return $fields; } private function buildEditFormActionButton($object) { if (!$this->isEngineConfigurable()) { return null; } $viewer = $this->getViewer(); $action_view = id(new PhabricatorActionListView()) ->setUser($viewer); foreach ($this->buildEditFormActions($object) as $action) { $action_view->addAction($action); } $action_button = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('Configure Form')) ->setHref('#') ->setIcon('fa-gear') ->setDropdownMenu($action_view); return $action_button; } private function buildEditFormActions($object) { $actions = array(); if ($this->supportsEditEngineConfiguration()) { $engine_key = $this->getEngineKey(); $config = $this->getEditEngineConfiguration(); $can_manage = PhabricatorPolicyFilter::hasCapability( $this->getViewer(), $config, PhabricatorPolicyCapability::CAN_EDIT); if ($can_manage) { $manage_uri = $config->getURI(); } else { $manage_uri = $this->getEditURI(null, 'nomanage/'); } $view_uri = "/transactions/editengine/{$engine_key}/"; $actions[] = id(new PhabricatorActionView()) ->setLabel(true) ->setName(pht('Configuration')); $actions[] = id(new PhabricatorActionView()) ->setName(pht('View Form Configurations')) ->setIcon('fa-list-ul') ->setHref($view_uri); $actions[] = id(new PhabricatorActionView()) ->setName(pht('Edit Form Configuration')) ->setIcon('fa-pencil') ->setHref($manage_uri) ->setDisabled(!$can_manage) ->setWorkflow(!$can_manage); } $actions[] = id(new PhabricatorActionView()) ->setLabel(true) ->setName(pht('Documentation')); $actions[] = id(new PhabricatorActionView()) ->setName(pht('Using HTTP Parameters')) ->setIcon('fa-book') ->setHref($this->getEditURI($object, 'parameters/')); $doc_href = PhabricatorEnv::getDoclink('User Guide: Customizing Forms'); $actions[] = id(new PhabricatorActionView()) ->setName(pht('User Guide: Customizing Forms')) ->setIcon('fa-book') ->setHref($doc_href); return $actions; } /** * Test if the viewer could apply a certain type of change by using the * normal "Edit" form. * * This method returns `true` if the user has access to an edit form and * that edit form has a field which applied the specified transaction type, * and that field is visible and editable for the user. * * For example, you can use it to test if a user is able to reassign tasks * or not, prior to rendering dedicated UI for task reassingment. * * Note that this method does NOT test if the user can actually edit the * current object, just if they have access to the related field. * * @param const Transaction type to test for. * @return bool True if the user could "Edit" to apply the transaction type. */ final public function hasEditAccessToTransaction($xaction_type) { $viewer = $this->getViewer(); $config = $this->loadDefaultEditConfiguration(); if (!$config) { return false; } $object = $this->getTargetObject(); if (!$object) { $object = $this->newEditableObject(); } $fields = $this->buildEditFields($object); $field = null; foreach ($fields as $form_field) { $field_xaction_type = $form_field->getTransactionType(); if ($field_xaction_type === $xaction_type) { $field = $form_field; break; } } if (!$field) { return false; } if (!$field->shouldReadValueFromSubmit()) { return false; } return true; } final public function addActionToCrumbs(PHUICrumbsView $crumbs) { $viewer = $this->getViewer(); $can_create = $this->hasCreateCapability(); if ($can_create) { $configs = $this->loadUsableConfigurationsForCreate(); } else { $configs = array(); } $dropdown = null; $disabled = false; $workflow = false; $menu_icon = 'fa-plus-square'; if (!$configs) { if ($viewer->isLoggedIn()) { $disabled = true; } else { // If the viewer isn't logged in, assume they'll get hit with a login // dialog and are likely able to create objects after they log in. $disabled = false; } $workflow = true; if ($can_create) { $create_uri = $this->getEditURI(null, 'nodefault/'); } else { $create_uri = $this->getEditURI(null, 'nocreate/'); } } else { $config = head($configs); $form_key = $config->getIdentifier(); $create_uri = $this->getEditURI(null, "form/{$form_key}/"); if (count($configs) > 1) { $menu_icon = 'fa-caret-square-o-down'; $dropdown = id(new PhabricatorActionListView()) ->setUser($viewer); foreach ($configs as $config) { $form_key = $config->getIdentifier(); $config_uri = $this->getEditURI(null, "form/{$form_key}/"); $item_icon = 'fa-plus'; $dropdown->addAction( id(new PhabricatorActionView()) ->setName($config->getDisplayName()) ->setIcon($item_icon) ->setHref($config_uri)); } } } $action = id(new PHUIListItemView()) ->setName($this->getObjectCreateShortText()) ->setHref($create_uri) ->setIcon($menu_icon) ->setWorkflow($workflow) ->setDisabled($disabled); if ($dropdown) { $action->setDropdownMenu($dropdown); } $crumbs->addAction($action); } final public function buildEditEngineCommentView($object) { $config = $this->loadDefaultEditConfiguration(); if (!$config) { // TODO: This just nukes the entire comment form if you don't have access // to any edit forms. We might want to tailor this UX a bit. return id(new PhabricatorApplicationTransactionCommentView()) ->setNoPermission(true); } $viewer = $this->getViewer(); $object_phid = $object->getPHID(); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($is_serious) { $header_text = $this->getCommentViewSeriousHeaderText($object); $button_text = $this->getCommentViewSeriousButtonText($object); } else { $header_text = $this->getCommentViewHeaderText($object); $button_text = $this->getCommentViewButtonText($object); } $comment_uri = $this->getEditURI($object, 'comment/'); $view = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($viewer) ->setObjectPHID($object_phid) ->setHeaderText($header_text) ->setAction($comment_uri) ->setSubmitButtonName($button_text); $draft = PhabricatorVersionedDraft::loadDraft( $object_phid, $viewer->getPHID()); if ($draft) { $view->setVersionedDraft($draft); } $view->setCurrentVersion($this->loadDraftVersion($object)); $fields = $this->buildEditFields($object); $comment_actions = array(); foreach ($fields as $field) { if (!$field->shouldGenerateTransactionsFromComment()) { continue; } $comment_action = $field->getCommentAction(); if (!$comment_action) { continue; } $key = $comment_action->getKey(); // TODO: Validate these better. $comment_actions[$key] = $comment_action; } $comment_actions = msortv($comment_actions, 'getSortVector'); $view->setCommentActions($comment_actions); return $view; } protected function loadDraftVersion($object) { $viewer = $this->getViewer(); if (!$viewer->isLoggedIn()) { return null; } $template = $object->getApplicationTransactionTemplate(); $conn_r = $template->establishConnection('r'); // Find the most recent transaction the user has written. We'll use this // as a version number to make sure that out-of-date drafts get discarded. $result = queryfx_one( $conn_r, 'SELECT id AS version FROM %T WHERE objectPHID = %s AND authorPHID = %s ORDER BY id DESC LIMIT 1', $template->getTableName(), $object->getPHID(), $viewer->getPHID()); if ($result) { return (int)$result['version']; } else { return null; } } /* -( Responding to HTTP Parameter Requests )------------------------------ */ /** * Respond to a request for documentation on HTTP parameters. * * @param object Editable object. * @return AphrontResponse Response object. * @task http */ private function buildParametersResponse($object) { $controller = $this->getController(); $viewer = $this->getViewer(); $request = $controller->getRequest(); $fields = $this->buildEditFields($object); $crumbs = $this->buildCrumbs($object); $crumbs->addTextCrumb(pht('HTTP Parameters')); $crumbs->setBorder(true); $header_text = pht( 'HTTP Parameters: %s', $this->getObjectCreateShortText()); $header = id(new PHUIHeaderView()) ->setHeader($header_text); $help_view = id(new PhabricatorApplicationEditHTTPParameterHelpView()) ->setUser($viewer) ->setFields($fields); $document = id(new PHUIDocumentViewPro()) ->setUser($viewer) ->setHeader($header) ->appendChild($help_view); return $controller->newPage() ->setTitle(pht('HTTP Parameters')) ->setCrumbs($crumbs) ->appendChild($document); } private function buildError($object, $title, $body) { $cancel_uri = $this->getObjectCreateCancelURI($object); return $this->getController() ->newDialog() ->setTitle($title) ->appendParagraph($body) ->addCancelButton($cancel_uri); } private function buildNoDefaultResponse($object) { return $this->buildError( $object, pht('No Default Create Forms'), pht( 'This application is not configured with any forms for creating '. 'objects that are visible to you and enabled.')); } private function buildNoCreateResponse($object) { return $this->buildError( $object, pht('No Create Permission'), pht('You do not have permission to create these objects.')); } private function buildNoManageResponse($object) { return $this->buildError( $object, pht('No Manage Permission'), pht( 'You do not have permission to configure forms for this '. 'application.')); } private function buildNoEditResponse($object) { return $this->buildError( $object, pht('No Edit Forms'), pht( 'You do not have access to any forms which are enabled and marked '. 'as edit forms.')); } private function buildNotEditFormRespose($object, $config) { return $this->buildError( $object, pht('Not an Edit Form'), pht( 'This form ("%s") is not marked as an edit form, so '. 'it can not be used to edit objects.', $config->getName())); } private function buildDisabledFormResponse($object, $config) { return $this->buildError( $object, pht('Form Disabled'), pht( 'This form ("%s") has been disabled, so it can not be used.', $config->getName())); } private function buildCommentResponse($object) { $viewer = $this->getViewer(); if ($this->getIsCreate()) { return new Aphront404Response(); } $controller = $this->getController(); $request = $controller->getRequest(); if (!$request->isFormPost()) { return new Aphront400Response(); } $config = $this->loadDefaultEditConfiguration(); if (!$config) { return new Aphront404Response(); } $fields = $this->buildEditFields($object); $is_preview = $request->isPreviewRequest(); $view_uri = $this->getEffectiveObjectViewURI($object); $template = $object->getApplicationTransactionTemplate(); $comment_template = $template->getApplicationTransactionCommentObject(); $comment_text = $request->getStr('comment'); $actions = $request->getStr('editengine.actions'); if ($actions) { $actions = phutil_json_decode($actions); } if ($is_preview) { $version_key = PhabricatorVersionedDraft::KEY_VERSION; $request_version = $request->getInt($version_key); $current_version = $this->loadDraftVersion($object); if ($request_version >= $current_version) { $draft = PhabricatorVersionedDraft::loadOrCreateDraft( $object->getPHID(), $viewer->getPHID(), $current_version); $draft ->setProperty('comment', $comment_text) ->setProperty('actions', $actions) ->save(); } } $xactions = array(); if ($actions) { $action_map = array(); foreach ($actions as $action) { $type = idx($action, 'type'); if (!$type) { continue; } if (empty($fields[$type])) { continue; } $action_map[$type] = $action; } foreach ($action_map as $type => $action) { $field = $fields[$type]; if (!$field->shouldGenerateTransactionsFromComment()) { continue; } if (array_key_exists('initialValue', $action)) { $field->setInitialValue($action['initialValue']); } $field->readValueFromComment(idx($action, 'value')); $type_xactions = $field->generateTransactions( clone $template, array( 'value' => $field->getValueForTransaction(), )); foreach ($type_xactions as $type_xaction) { $xactions[] = $type_xaction; } } } if (strlen($comment_text) || !$xactions) { $xactions[] = id(clone $template) ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) ->attachComment( id(clone $comment_template) ->setContent($comment_text)); } $editor = $object->getApplicationTransactionEditor() ->setActor($viewer) ->setContinueOnNoEffect($request->isContinueRequest()) ->setContinueOnMissingFields(true) ->setContentSourceFromRequest($request) ->setIsPreview($is_preview); try { $xactions = $editor->applyTransactions($object, $xactions); } catch (PhabricatorApplicationTransactionNoEffectException $ex) { return id(new PhabricatorApplicationTransactionNoEffectResponse()) ->setCancelURI($view_uri) ->setException($ex); } if (!$is_preview) { PhabricatorVersionedDraft::purgeDrafts( $object->getPHID(), $viewer->getPHID(), $this->loadDraftVersion($object)); } if ($request->isAjax() && $is_preview) { return id(new PhabricatorApplicationTransactionResponse()) ->setViewer($viewer) ->setTransactions($xactions) ->setIsPreview($is_preview); } else { return id(new AphrontRedirectResponse()) ->setURI($view_uri); } } /* -( Conduit )------------------------------------------------------------ */ /** * Respond to a Conduit edit request. * * This method accepts a list of transactions to apply to an object, and * either edits an existing object or creates a new one. * * @task conduit */ final public function buildConduitResponse(ConduitAPIRequest $request) { $viewer = $this->getViewer(); $config = $this->loadDefaultConfiguration(); if (!$config) { throw new Exception( pht( 'Unable to load configuration for this EditEngine ("%s").', get_class($this))); } $identifier = $request->getValue('objectIdentifier'); if ($identifier) { $this->setIsCreate(false); $object = $this->newObjectFromIdentifier($identifier); } else { $this->requireCreateCapability(); $this->setIsCreate(true); $object = $this->newEditableObject(); } $this->validateObject($object); $fields = $this->buildEditFields($object); $types = $this->getConduitEditTypesFromFields($fields); $template = $object->getApplicationTransactionTemplate(); $xactions = $this->getConduitTransactions($request, $types, $template); $editor = $object->getApplicationTransactionEditor() ->setActor($viewer) ->setContentSource($request->newContentSource()) ->setContinueOnNoEffect(true); if (!$this->getIsCreate()) { $editor->setContinueOnMissingFields(true); } $xactions = $editor->applyTransactions($object, $xactions); $xactions_struct = array(); foreach ($xactions as $xaction) { $xactions_struct[] = array( 'phid' => $xaction->getPHID(), ); } return array( 'object' => array( 'id' => $object->getID(), 'phid' => $object->getPHID(), ), 'transactions' => $xactions_struct, ); } /** * Generate transactions which can be applied from edit actions in a Conduit * request. * * @param ConduitAPIRequest The request. * @param list Supported edit types. * @param PhabricatorApplicationTransaction Template transaction. * @return list Generated transactions. * @task conduit */ private function getConduitTransactions( ConduitAPIRequest $request, array $types, PhabricatorApplicationTransaction $template) { $viewer = $request->getUser(); $transactions_key = 'transactions'; $xactions = $request->getValue($transactions_key); if (!is_array($xactions)) { throw new Exception( pht( 'Parameter "%s" is not a list of transactions.', $transactions_key)); } foreach ($xactions as $key => $xaction) { if (!is_array($xaction)) { throw new Exception( pht( 'Parameter "%s" must contain a list of transaction descriptions, '. 'but item with key "%s" is not a dictionary.', $transactions_key, $key)); } if (!array_key_exists('type', $xaction)) { throw new Exception( pht( 'Parameter "%s" must contain a list of transaction descriptions, '. 'but item with key "%s" is missing a "type" field. Each '. 'transaction must have a type field.', $transactions_key, $key)); } $type = $xaction['type']; if (empty($types[$type])) { throw new Exception( pht( 'Transaction with key "%s" has invalid type "%s". This type is '. 'not recognized. Valid types are: %s.', $key, $type, implode(', ', array_keys($types)))); } } $results = array(); if ($this->getIsCreate()) { $results[] = id(clone $template) ->setTransactionType(PhabricatorTransactions::TYPE_CREATE); } foreach ($xactions as $xaction) { $type = $types[$xaction['type']]; // Let the parameter type interpret the value. This allows you to // use usernames in list fields, for example. $parameter_type = $type->getConduitParameterType(); $parameter_type->setViewer($viewer); try { - $xaction['value'] = $parameter_type->getValue($xaction, 'value'); + $xaction['value'] = $parameter_type->getValue( + $xaction, + 'value', + $request->getIsStrictlyTyped()); } catch (Exception $ex) { throw new PhutilProxyException( pht( 'Exception when processing transaction of type "%s": %s', $xaction['type'], $ex->getMessage()), $ex); } $type_xactions = $type->generateTransactions( clone $template, $xaction); foreach ($type_xactions as $type_xaction) { $results[] = $type_xaction; } } return $results; } /** * @return map * @task conduit */ private function getConduitEditTypesFromFields(array $fields) { $types = array(); foreach ($fields as $field) { $field_types = $field->getConduitEditTypes(); if ($field_types === null) { continue; } foreach ($field_types as $field_type) { $field_type->setField($field); $types[$field_type->getEditType()] = $field_type; } } return $types; } public function getConduitEditTypes() { $config = $this->loadDefaultConfiguration(); if (!$config) { return array(); } $object = $this->newEditableObject(); $fields = $this->buildEditFields($object); return $this->getConduitEditTypesFromFields($fields); } final public static function getAllEditEngines() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) ->setUniqueMethod('getEngineKey') ->execute(); } final public static function getByKey(PhabricatorUser $viewer, $key) { return id(new PhabricatorEditEngineQuery()) ->setViewer($viewer) ->withEngineKeys(array($key)) ->executeOne(); } public function getIcon() { $application = $this->getApplication(); return $application->getIcon(); } public function hasQuickCreateActions() { if (!$this->isEngineConfigurable()) { return false; } return true; } public function newQuickCreateActions(array $configs) { $items = array(); if (!$configs) { return array(); } // If the viewer is logged in and can't create objects, don't show the // menu item. If they're logged out, we assume they could create objects // if they logged in, so we show the item as a hint about how to // accomplish the action. if ($this->getViewer()->isLoggedIn()) { if (!$this->hasCreateCapability()) { return array(); } } if (count($configs) == 1) { $config = head($configs); $items[] = $this->newQuickCreateAction($config); } else { $group_name = $this->getQuickCreateMenuHeaderText(); $items[] = id(new PHUIListItemView()) ->setType(PHUIListItemView::TYPE_LABEL) ->setName($group_name); foreach ($configs as $config) { $items[] = $this->newQuickCreateAction($config) ->setIndented(true); } } return $items; } private function loadUsableConfigurationsForCreate() { $viewer = $this->getViewer(); $configs = id(new PhabricatorEditEngineConfigurationQuery()) ->setViewer($viewer) ->withEngineKeys(array($this->getEngineKey())) ->withIsDefault(true) ->withIsDisabled(false) ->execute(); $configs = msort($configs, 'getCreateSortKey'); return $configs; } private function newQuickCreateAction( PhabricatorEditEngineConfiguration $config) { $item_name = $config->getName(); $item_icon = $config->getIcon(); $form_key = $config->getIdentifier(); $item_uri = $this->getEditURI(null, "form/{$form_key}/"); return id(new PHUIListItemView()) ->setName($item_name) ->setIcon($item_icon) ->setHref($item_uri); } protected function getValidationExceptionShortMessage( PhabricatorApplicationTransactionValidationException $ex, PhabricatorEditField $field) { $xaction_type = $field->getTransactionType(); if ($xaction_type === null) { return null; } return $ex->getShortMessage($xaction_type); } protected function getCreateNewObjectPolicy() { return PhabricatorPolicies::POLICY_USER; } private function requireCreateCapability() { PhabricatorPolicyFilter::requireCapability( $this->getViewer(), $this, PhabricatorPolicyCapability::CAN_EDIT); } private function hasCreateCapability() { return PhabricatorPolicyFilter::hasCapability( $this->getViewer(), $this, PhabricatorPolicyCapability::CAN_EDIT); } /* -( Form Pages )--------------------------------------------------------- */ public function getSelectedPage() { return $this->page; } private function selectPage($object, $page_key) { $pages = $this->getPages($object); if (empty($pages[$page_key])) { return null; } $this->page = $pages[$page_key]; return $this->page; } protected function newPages($object) { return array(); } protected function getPages($object) { if ($this->pages === null) { $pages = $this->newPages($object); assert_instances_of($pages, 'PhabricatorEditPage'); $pages = mpull($pages, null, 'getKey'); $this->pages = $pages; } return $this->pages; } private function applyPageToFields($object, array $fields) { $pages = $this->getPages($object); if (!$pages) { return $fields; } if (!$this->getSelectedPage()) { return $fields; } $page_picks = array(); $default_key = head($pages)->getKey(); foreach ($pages as $page_key => $page) { foreach ($page->getFieldKeys() as $field_key) { $page_picks[$field_key] = $page_key; } if ($page->getIsDefault()) { $default_key = $page_key; } } $page_map = array_fill_keys(array_keys($pages), array()); foreach ($fields as $field_key => $field) { if (isset($page_picks[$field_key])) { $page_map[$page_picks[$field_key]][$field_key] = $field; continue; } // TODO: Maybe let the field pick a page to associate itself with so // extensions can force themselves onto a particular page? $page_map[$default_key][$field_key] = $field; } $page = $this->getSelectedPage(); if (!$page) { $page = head($pages); } $selected_key = $page->getKey(); return $page_map[$selected_key]; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getPHID() { return get_class($this); } public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::getMostOpenPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getCreateNewObjectPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/transactions/editfield/PhabricatorFileEditField.php b/src/applications/transactions/editfield/PhabricatorFileEditField.php new file mode 100644 index 0000000000..48f5e6b215 --- /dev/null +++ b/src/applications/transactions/editfield/PhabricatorFileEditField.php @@ -0,0 +1,23 @@ +setEncType('multipart/form-data'); + return parent::appendToForm($form); + } + +} diff --git a/src/docs/user/configuration/configuration_guide.diviner b/src/docs/user/configuration/configuration_guide.diviner index b420996848..b4c494449b 100644 --- a/src/docs/user/configuration/configuration_guide.diviner +++ b/src/docs/user/configuration/configuration_guide.diviner @@ -1,212 +1,204 @@ @title Configuration Guide @group config This document contains basic configuration instructions for Phabricator. = Prerequisites = This document assumes you've already installed all the components you need. If you haven't, see @{article:Installation Guide}. The next steps are: - Configure your webserver (Apache, nginx, or lighttpd). - Access Phabricator with your browser. - Follow the instructions to complete setup. = Webserver: Configuring Apache = NOTE: Follow these instructions to use Apache. To use nginx or lighttpd, scroll down to their sections. Get Apache running and verify it's serving a test page. Consult the Apache documentation for help. Make sure `mod_php` and `mod_rewrite` are enabled, and `mod_ssl` if you intend to set up SSL. If you haven't already, set up a domain name to point to the host you're installing on. You can either install Phabricator on a subdomain (like phabricator.example.com) or an entire domain, but you can not install it in some subdirectory of an existing website. Navigate to whatever domain you're going to use and make sure Apache serves you something to verify that DNS is correctly configured. NOTE: The domain must contain a dot ('.'), i.e. not be just a bare name like 'http://example/'. Some web browsers will not set cookies otherwise. Now create a VirtualHost entry for Phabricator. It should look something like this: name=httpd.conf # Change this to the domain which points to your host. ServerName phabricator.example.com # Change this to the path where you put 'phabricator' when you checked it # out from GitHub when following the Installation Guide. # # Make sure you include "/webroot" at the end! DocumentRoot /path/to/phabricator/webroot RewriteEngine on - RewriteRule ^/rsrc/(.*) - [L,QSA] - RewriteRule ^/favicon.ico - [L,QSA] RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA] If Apache isn't currently configured to serve documents out of the directory where you put Phabricator, you may also need to add `` section. The syntax for this section depends on which version of Apache you're running. (If you don't know, you can usually figure this out by running `httpd -v`.) For Apache versions older than 2.4, use this: name="Apache Older Than 2.4" Order allow,deny Allow from all For Apache versions 2.4 and newer, use this: name="Apache 2.4 and Newer" Require all granted After making your edits, restart Apache, then continue to "Setup" below. = Webserver: Configuring nginx = NOTE: Follow these instructions to use nginx. To use Apache or lighttpd, scroll to their sections. For nginx, use a configuration like this: name=nginx.conf server { server_name phabricator.example.com; root /path/to/phabricator/webroot; location / { index index.php; rewrite ^/(.*)$ /index.php?__path__=/$1 last; } - location = /favicon.ico { - try_files $uri =204; - } - location /index.php { fastcgi_pass localhost:9000; fastcgi_index index.php; #required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; #variables to make the $_SERVER populate in PHP fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; } } Restart nginx after making your edits, then continue to "Setup" below. = Webserver: Configuring lighttpd = NOTE: Follow these instructions to use lighttpd. To use Apache or niginx, scroll up to their sections. For lighttpd, add a section like this to your lighttpd.conf: $HTTP["host"] =~ "phabricator(\.example\.com)?" { server.document-root = "/path/to/phabricator/webroot" url.rewrite-once = ( - "^(/rsrc/.*)$" => "$1", - "^(/favicon.ico)$" => "$1", # This simulates QSA ("query string append") mode in apache "^(/[^?]*)\?(.*)" => "/index.php?__path__=$1&$2", "^(/.*)$" => "/index.php?__path__=$1", ) } You should also ensure the following modules are listed in your server.modules list: mod_fastcgi mod_rewrite Finally, you should run the following commands to enable php support: $ sudo apt-get install php5-cgi # for ubuntu; other distros should be similar $ sudo lighty-enable-mod fastcgi-php Restart lighttpd after making your edits, then continue below. = Setup = Now, navigate to whichever subdomain you set up. You should see instructions to continue setup. The rest of this document contains additional instructions for specific setup steps. When you resolve any issues and see the welcome screen, enter credentials to create your initial administrator account. After you log in, you'll want to configure how other users will be able to log in or register -- until you do, no one else will be able to sign up or log in. For more information, see @{article:Configuring Accounts and Registration}. = Storage: Configuring MySQL = During setup, you'll need to configure MySQL. To do this, get MySQL running and verify you can connect to it. Consult the MySQL documentation for help. When MySQL works, you need to load the Phabricator schemata into it. To do this, run: phabricator/ $ ./bin/storage upgrade If your configuration uses an unprivileged user to connect to the database, you may have to override the default user so the schema changes can be applied with root or some other admin user: phabricator/ $ ./bin/storage upgrade --user --password You can avoid the prompt the script issues by passing the `--force` flag (for example, if you are scripting the upgrade process). phabricator/ $ ./bin/storage upgrade --force NOTE: When you update Phabricator, run `storage upgrade` again to apply any new updates. = Next Steps = Continue by: - setting up your admin account and login/registration with @{article:Configuring Accounts and Registration}; or - understanding advanced configuration topics with @{article:Configuration User Guide: Advanced Configuration}; or - configuring an alternate file domain with @{article:Configuring a File Domain}; or - configuring a preamble script to set up the environment properly behind a load balancer, or adjust rate limiting with @{article:Configuring a Preamble Script}; or - configuring where uploaded files and attachments will be stored with @{article:Configuring File Storage}; or - configuring Phabricator so it can send mail with @{article:Configuring Outbound Email}; or - configuring inbound mail with @{article:Configuring Inbound Email}; or - importing repositories with @{article:Diffusion User Guide}; or - learning about daemons with @{article:Managing Daemons with phd}; or - learning about notification with @{article:Notifications User Guide: Setup and Configuration}; or - configuring backups with @{article:Configuring Backups and Performing Migrations}; or - contributing to Phabricator with @{article:Contributor Introduction}. diff --git a/src/infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php b/src/infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php index 3e5b70cc05..f5960e9504 100644 --- a/src/infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php +++ b/src/infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php @@ -1,155 +1,175 @@ hasAutomaticPolicy()) { throw new Exception( pht( 'Can not get retention policy of collector with automatic '. 'policy.')); } $config = PhabricatorEnv::getEnvConfig('phd.garbage-collection'); $const = $this->getCollectorConstant(); return idx($config, $const, $this->getDefaultRetentionPolicy()); } /** * Get a unique string constant identifying this collector. * * @return string Collector constant. * @task info */ final public function getCollectorConstant() { return $this->getPhobjectClassConstant('COLLECTORCONST', 64); } /* -( Collecting Garbage )------------------------------------------------- */ /** * Run the collector. * * @return bool True if there is more garbage to collect. * @task collect */ final public function runCollector() { // Don't do anything if this collector is configured with an indefinite // retention policy. if (!$this->hasAutomaticPolicy()) { $policy = $this->getRetentionPolicy(); if (!$policy) { return false; } } - return $this->collectGarbage(); + // Hold a lock while performing collection to avoid racing other daemons + // running the same collectors. + $lock_name = 'gc:'.$this->getCollectorConstant(); + $lock = PhabricatorGlobalLock::newLock($lock_name); + + try { + $lock->lock(5); + } catch (PhutilLockException $ex) { + return false; + } + + try { + $result = $this->collectGarbage(); + } catch (Exception $ex) { + $lock->unlock(); + throw $ex; + } + + $lock->unlock(); + + return $result; } /** * Collect garbage from whatever source this GC handles. * * @return bool True if there is more garbage to collect. * @task collect */ abstract protected function collectGarbage(); /** * Get the most recent epoch timestamp that is considered garbage. * * Records older than this should be collected. * * @return int Most recent garbage timestamp. * @task collect */ final protected function getGarbageEpoch() { if ($this->hasAutomaticPolicy()) { throw new Exception( pht( 'Can not get garbage epoch for a collector with an automatic '. 'collection policy.')); } $ttl = $this->getRetentionPolicy(); if (!$ttl) { throw new Exception( pht( 'Can not get garbage epoch for a collector with an indefinite '. 'retention policy.')); } return (PhabricatorTime::getNow() - $ttl); } /** * Load all of the available garbage collectors. * * @return list Garbage collectors. * @task collect */ final public static function getAllCollectors() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) ->setUniqueMethod('getCollectorConstant') ->execute(); } } diff --git a/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php index 42d8001ee2..7aa0f28dfe 100644 --- a/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php @@ -1,726 +1,751 @@ setViewer($user) * ->withConstraint($example) * ->execute(); * * Normally, you should extend @{class:PhabricatorCursorPagedPolicyAwareQuery}, * not this class. @{class:PhabricatorCursorPagedPolicyAwareQuery} provides a * more practical interface for building usable queries against most object * types. * * NOTE: Although this class extends @{class:PhabricatorOffsetPagedQuery}, * offset paging with policy filtering is not efficient. All results must be * loaded into the application and filtered here: skipping `N` rows via offset * is an `O(N)` operation with a large constant. Prefer cursor-based paging * with @{class:PhabricatorCursorPagedPolicyAwareQuery}, which can filter far * more efficiently in MySQL. * * @task config Query Configuration * @task exec Executing Queries * @task policyimpl Policy Query Implementation */ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery { private $viewer; private $parentQuery; private $rawResultLimit; private $capabilities; private $workspace = array(); private $inFlightPHIDs = array(); private $policyFilteredPHIDs = array(); /** * Should we continue or throw an exception when a query result is filtered * by policy rules? * * Values are `true` (raise exceptions), `false` (do not raise exceptions) * and `null` (inherit from parent query, with no exceptions by default). */ private $raisePolicyExceptions; + private $isOverheated; /* -( Query Configuration )------------------------------------------------ */ /** * Set the viewer who is executing the query. Results will be filtered * according to the viewer's capabilities. You must set a viewer to execute * a policy query. * * @param PhabricatorUser The viewing user. * @return this * @task config */ final public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; return $this; } /** * Get the query's viewer. * * @return PhabricatorUser The viewing user. * @task config */ final public function getViewer() { return $this->viewer; } /** * Set the parent query of this query. This is useful for nested queries so * that configuration like whether or not to raise policy exceptions is * seamlessly passed along to child queries. * * @return this * @task config */ final public function setParentQuery(PhabricatorPolicyAwareQuery $query) { $this->parentQuery = $query; return $this; } /** * Get the parent query. See @{method:setParentQuery} for discussion. * * @return PhabricatorPolicyAwareQuery The parent query. * @task config */ final public function getParentQuery() { return $this->parentQuery; } /** * Hook to configure whether this query should raise policy exceptions. * * @return this * @task config */ final public function setRaisePolicyExceptions($bool) { $this->raisePolicyExceptions = $bool; return $this; } /** * @return bool * @task config */ final public function shouldRaisePolicyExceptions() { return (bool)$this->raisePolicyExceptions; } /** * @task config */ final public function requireCapabilities(array $capabilities) { $this->capabilities = $capabilities; return $this; } /* -( Query Execution )---------------------------------------------------- */ /** * Execute the query, expecting a single result. This method simplifies * loading objects for detail pages or edit views. * * // Load one result by ID. * $obj = id(new ExampleQuery()) * ->setViewer($user) * ->withIDs(array($id)) * ->executeOne(); * if (!$obj) { * return new Aphront404Response(); * } * * If zero results match the query, this method returns `null`. * If one result matches the query, this method returns that result. * * If two or more results match the query, this method throws an exception. * You should use this method only when the query constraints guarantee at * most one match (e.g., selecting a specific ID or PHID). * * If one result matches the query but it is caught by the policy filter (for * example, the user is trying to view or edit an object which exists but * which they do not have permission to see) a policy exception is thrown. * * @return mixed Single result, or null. * @task exec */ final public function executeOne() { $this->setRaisePolicyExceptions(true); try { $results = $this->execute(); } catch (Exception $ex) { $this->setRaisePolicyExceptions(false); throw $ex; } if (count($results) > 1) { throw new Exception(pht('Expected a single result!')); } if (!$results) { return null; } return head($results); } /** * Execute the query, loading all visible results. * * @return list Result objects. * @task exec */ final public function execute() { if (!$this->viewer) { throw new PhutilInvalidStateException('setViewer'); } $parent_query = $this->getParentQuery(); if ($parent_query && ($this->raisePolicyExceptions === null)) { $this->setRaisePolicyExceptions( $parent_query->shouldRaisePolicyExceptions()); } $results = array(); $filter = $this->getPolicyFilter(); $offset = (int)$this->getOffset(); $limit = (int)$this->getLimit(); $count = 0; if ($limit) { $need = $offset + $limit; } else { $need = 0; } $this->willExecute(); + // If we examine and filter significantly more objects than the query + // limit, we stop early. This prevents us from looping through a huge + // number of records when the viewer can see few or none of them. See + // T11773 for some discussion. + $this->isOverheated = false; + $overheat_limit = $limit * 10; + $total_seen = 0; + do { if ($need) { $this->rawResultLimit = min($need - $count, 1024); } else { $this->rawResultLimit = 0; } if ($this->canViewerUseQueryApplication()) { try { $page = $this->loadPage(); } catch (PhabricatorEmptyQueryException $ex) { $page = array(); } } else { $page = array(); } + $total_seen += count($page); + if ($page) { $maybe_visible = $this->willFilterPage($page); if ($maybe_visible) { $maybe_visible = $this->applyWillFilterPageExtensions($maybe_visible); } } else { $maybe_visible = array(); } if ($this->shouldDisablePolicyFiltering()) { $visible = $maybe_visible; } else { $visible = $filter->apply($maybe_visible); $policy_filtered = array(); foreach ($maybe_visible as $key => $object) { if (empty($visible[$key])) { $phid = $object->getPHID(); if ($phid) { $policy_filtered[$phid] = $phid; } } } $this->addPolicyFilteredPHIDs($policy_filtered); } if ($visible) { $visible = $this->didFilterPage($visible); } $removed = array(); foreach ($maybe_visible as $key => $object) { if (empty($visible[$key])) { $removed[$key] = $object; } } $this->didFilterResults($removed); foreach ($visible as $key => $result) { ++$count; // If we have an offset, we just ignore that many results and start // storing them only once we've hit the offset. This reduces memory // requirements for large offsets, compared to storing them all and // slicing them away later. if ($count > $offset) { $results[$key] = $result; } if ($need && ($count >= $need)) { // If we have all the rows we need, break out of the paging query. break 2; } } if (!$this->rawResultLimit) { // If we don't have a load count, we loaded all the results. We do // not need to load another page. break; } if (count($page) < $this->rawResultLimit) { // If we have a load count but the unfiltered results contained fewer // objects, we know this was the last page of objects; we do not need // to load another page because we can deduce it would be empty. break; } $this->nextPage($page); + + if ($overheat_limit && ($total_seen >= $overheat_limit)) { + $this->isOverheated = true; + break; + } } while (true); $results = $this->didLoadResults($results); return $results; } private function getPolicyFilter() { $filter = new PhabricatorPolicyFilter(); $filter->setViewer($this->viewer); $capabilities = $this->getRequiredCapabilities(); $filter->requireCapabilities($capabilities); $filter->raisePolicyExceptions($this->shouldRaisePolicyExceptions()); return $filter; } protected function getRequiredCapabilities() { if ($this->capabilities) { return $this->capabilities; } return array( PhabricatorPolicyCapability::CAN_VIEW, ); } protected function applyPolicyFilter(array $objects, array $capabilities) { if ($this->shouldDisablePolicyFiltering()) { return $objects; } $filter = $this->getPolicyFilter(); $filter->requireCapabilities($capabilities); return $filter->apply($objects); } protected function didRejectResult(PhabricatorPolicyInterface $object) { // Some objects (like commits) may be rejected because related objects // (like repositories) can not be loaded. In some cases, we may need these // related objects to determine the object policy, so it's expected that // we may occasionally be unable to determine the policy. try { $policy = $object->getPolicy(PhabricatorPolicyCapability::CAN_VIEW); } catch (Exception $ex) { $policy = null; } // Mark this object as filtered so handles can render "Restricted" instead // of "Unknown". $phid = $object->getPHID(); $this->addPolicyFilteredPHIDs(array($phid => $phid)); $this->getPolicyFilter()->rejectObject( $object, $policy, PhabricatorPolicyCapability::CAN_VIEW); } public function addPolicyFilteredPHIDs(array $phids) { $this->policyFilteredPHIDs += $phids; if ($this->getParentQuery()) { $this->getParentQuery()->addPolicyFilteredPHIDs($phids); } return $this; } + + public function getIsOverheated() { + if ($this->isOverheated === null) { + throw new PhutilInvalidStateException('execute'); + } + return $this->isOverheated; + } + + /** * Return a map of all object PHIDs which were loaded in the query but * filtered out by policy constraints. This allows a caller to distinguish * between objects which do not exist (or, at least, were filtered at the * content level) and objects which exist but aren't visible. * * @return map Map of object PHIDs which were filtered * by policies. * @task exec */ public function getPolicyFilteredPHIDs() { return $this->policyFilteredPHIDs; } /* -( Query Workspace )---------------------------------------------------- */ /** * Put a map of objects into the query workspace. Many queries perform * subqueries, which can eventually end up loading the same objects more than * once (often to perform policy checks). * * For example, loading a user may load the user's profile image, which might * load the user object again in order to verify that the viewer has * permission to see the file. * * The "query workspace" allows queries to load objects from elsewhere in a * query block instead of refetching them. * * When using the query workspace, it's important to obey two rules: * * **Never put objects into the workspace which the viewer may not be able * to see**. You need to apply all policy filtering //before// putting * objects in the workspace. Otherwise, subqueries may read the objects and * use them to permit access to content the user shouldn't be able to view. * * **Fully enrich objects pulled from the workspace.** After pulling objects * from the workspace, you still need to load and attach any additional * content the query requests. Otherwise, a query might return objects * without requested content. * * Generally, you do not need to update the workspace yourself: it is * automatically populated as a side effect of objects surviving policy * filtering. * * @param map Objects to add to the query * workspace. * @return this * @task workspace */ public function putObjectsInWorkspace(array $objects) { $parent = $this->getParentQuery(); if ($parent) { $parent->putObjectsInWorkspace($objects); return $this; } assert_instances_of($objects, 'PhabricatorPolicyInterface'); $viewer_fragment = $this->getViewer()->getCacheFragment(); // The workspace is scoped per viewer to prevent accidental contamination. if (empty($this->workspace[$viewer_fragment])) { $this->workspace[$viewer_fragment] = array(); } $this->workspace[$viewer_fragment] += $objects; return $this; } /** * Retrieve objects from the query workspace. For more discussion about the * workspace mechanism, see @{method:putObjectsInWorkspace}. This method * searches both the current query's workspace and the workspaces of parent * queries. * * @param list List of PHIDs to retrieve. * @return this * @task workspace */ public function getObjectsFromWorkspace(array $phids) { $parent = $this->getParentQuery(); if ($parent) { return $parent->getObjectsFromWorkspace($phids); } $viewer_fragment = $this->getViewer()->getCacheFragment(); $results = array(); foreach ($phids as $key => $phid) { if (isset($this->workspace[$viewer_fragment][$phid])) { $results[$phid] = $this->workspace[$viewer_fragment][$phid]; unset($phids[$key]); } } return $results; } /** * Mark PHIDs as in flight. * * PHIDs which are "in flight" are actively being queried for. Using this * list can prevent infinite query loops by aborting queries which cycle. * * @param list List of PHIDs which are now in flight. * @return this */ public function putPHIDsInFlight(array $phids) { foreach ($phids as $phid) { $this->inFlightPHIDs[$phid] = $phid; } return $this; } /** * Get PHIDs which are currently in flight. * * PHIDs which are "in flight" are actively being queried for. * * @return map PHIDs currently in flight. */ public function getPHIDsInFlight() { $results = $this->inFlightPHIDs; if ($this->getParentQuery()) { $results += $this->getParentQuery()->getPHIDsInFlight(); } return $results; } /* -( Policy Query Implementation )---------------------------------------- */ /** * Get the number of results @{method:loadPage} should load. If the value is * 0, @{method:loadPage} should load all available results. * * @return int The number of results to load, or 0 for all results. * @task policyimpl */ final protected function getRawResultLimit() { return $this->rawResultLimit; } /** * Hook invoked before query execution. Generally, implementations should * reset any internal cursors. * * @return void * @task policyimpl */ protected function willExecute() { return; } /** * Load a raw page of results. Generally, implementations should load objects * from the database. They should attempt to return the number of results * hinted by @{method:getRawResultLimit}. * * @return list List of filterable policy objects. * @task policyimpl */ abstract protected function loadPage(); /** * Update internal state so that the next call to @{method:loadPage} will * return new results. Generally, you should adjust a cursor position based * on the provided result page. * * @param list The current page of results. * @return void * @task policyimpl */ abstract protected function nextPage(array $page); /** * Hook for applying a page filter prior to the privacy filter. This allows * you to drop some items from the result set without creating problems with * pagination or cursor updates. You can also load and attach data which is * required to perform policy filtering. * * Generally, you should load non-policy data and perform non-policy filtering * later, in @{method:didFilterPage}. Strictly fewer objects will make it that * far (so the program will load less data) and subqueries from that context * can use the query workspace to further reduce query load. * * This method will only be called if data is available. Implementations * do not need to handle the case of no results specially. * * @param list Results from `loadPage()`. * @return list Objects for policy filtering. * @task policyimpl */ protected function willFilterPage(array $page) { return $page; } /** * Hook for performing additional non-policy loading or filtering after an * object has satisfied all policy checks. Generally, this means loading and * attaching related data. * * Subqueries executed during this phase can use the query workspace, which * may improve performance or make circular policies resolvable. Data which * is not necessary for policy filtering should generally be loaded here. * * This callback can still filter objects (for example, if attachable data * is discovered to not exist), but should not do so for policy reasons. * * This method will only be called if data is available. Implementations do * not need to handle the case of no results specially. * * @param list Results from @{method:willFilterPage()}. * @return list Objects after additional * non-policy processing. */ protected function didFilterPage(array $page) { return $page; } /** * Hook for removing filtered results from alternate result sets. This * hook will be called with any objects which were returned by the query but * filtered for policy reasons. The query should remove them from any cached * or partial result sets. * * @param list List of objects that should not be returned by alternate * result mechanisms. * @return void * @task policyimpl */ protected function didFilterResults(array $results) { return; } /** * Hook for applying final adjustments before results are returned. This is * used by @{class:PhabricatorCursorPagedPolicyAwareQuery} to reverse results * that are queried during reverse paging. * * @param list Query results. * @return list Final results. * @task policyimpl */ protected function didLoadResults(array $results) { return $results; } /** * Allows a subclass to disable policy filtering. This method is dangerous. * It should be used only if the query loads data which has already been * filtered (for example, because it wraps some other query which uses * normal policy filtering). * * @return bool True to disable all policy filtering. * @task policyimpl */ protected function shouldDisablePolicyFiltering() { return false; } /** * If this query belongs to an application, return the application class name * here. This will prevent the query from returning results if the viewer can * not access the application. * * If this query does not belong to an application, return `null`. * * @return string|null Application class name. */ abstract public function getQueryApplicationClass(); /** * Determine if the viewer has permission to use this query's application. * For queries which aren't part of an application, this method always returns * true. * * @return bool True if the viewer has application-level permission to * execute the query. */ public function canViewerUseQueryApplication() { $class = $this->getQueryApplicationClass(); if (!$class) { return true; } $viewer = $this->getViewer(); return PhabricatorApplication::isClassInstalledForViewer($class, $viewer); } private function applyWillFilterPageExtensions(array $page) { $bridges = array(); foreach ($page as $key => $object) { if ($object instanceof DoorkeeperBridgedObjectInterface) { $bridges[$key] = $object; } } if ($bridges) { $external_phids = array(); foreach ($bridges as $bridge) { $external_phid = $bridge->getBridgedObjectPHID(); if ($external_phid) { $external_phids[$key] = $external_phid; } } if ($external_phids) { $external_objects = id(new DoorkeeperExternalObjectQuery()) ->setViewer($this->getViewer()) ->withPHIDs($external_phids) ->execute(); $external_objects = mpull($external_objects, null, 'getPHID'); } else { $external_objects = array(); } foreach ($bridges as $key => $bridge) { $external_phid = idx($external_phids, $key); if (!$external_phid) { $bridge->attachBridgedObject(null); continue; } $external_object = idx($external_objects, $external_phid); if (!$external_object) { $this->didRejectResult($bridge); unset($page[$key]); continue; } $bridge->attachBridgedObject($external_object); } } return $page; } } diff --git a/src/infrastructure/ssh/PhabricatorSSHWorkflow.php b/src/infrastructure/ssh/PhabricatorSSHWorkflow.php index b5ac17b7bf..beee356951 100644 --- a/src/infrastructure/ssh/PhabricatorSSHWorkflow.php +++ b/src/infrastructure/ssh/PhabricatorSSHWorkflow.php @@ -1,86 +1,101 @@ errorChannel = $error_channel; return $this; } public function getErrorChannel() { return $this->errorChannel; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } public function getUser() { return $this->user; } public function setIOChannel(PhutilChannel $channel) { $this->iochannel = $channel; return $this; } public function getIOChannel() { return $this->iochannel; } public function readAllInput() { $channel = $this->getIOChannel(); while ($channel->update()) { PhutilChannel::waitForAny(array($channel)); if (!$channel->isOpenForReading()) { break; } } return $channel->read(); } public function writeIO($data) { $this->getIOChannel()->write($data); return $this; } public function writeErrorIO($data) { $this->getErrorChannel()->write($data); return $this; } protected function newPassthruCommand() { return id(new PhabricatorSSHPassthruCommand()) ->setErrorChannel($this->getErrorChannel()); } public function setIsClusterRequest($is_cluster_request) { $this->isClusterRequest = $is_cluster_request; return $this; } public function getIsClusterRequest() { return $this->isClusterRequest; } public function setOriginalArguments(array $original_arguments) { $this->originalArguments = $original_arguments; return $this; } public function getOriginalArguments() { return $this->originalArguments; } + public function getSSHRemoteAddress() { + $ssh_client = getenv('SSH_CLIENT'); + if (!strlen($ssh_client)) { + return null; + } + + // TODO: When commands are proxied, the original remote address should + // also be proxied. + + // This has the format " ". Grab the IP. + $remote_address = head(explode(' ', $ssh_client)); + + return $remote_address; + } + } diff --git a/src/view/page/PhabricatorBarePageView.php b/src/view/page/PhabricatorBarePageView.php index 82b4d43faf..ca9d432286 100644 --- a/src/view/page/PhabricatorBarePageView.php +++ b/src/view/page/PhabricatorBarePageView.php @@ -1,165 +1,167 @@ controller = $controller; return $this; } public function getController() { return $this->controller; } public function setRequest(AphrontRequest $request) { $this->request = $request; return $this; } public function getRequest() { return $this->request; } public function setFrameable($frameable) { $this->frameable = $frameable; return $this; } public function getFrameable() { return $this->frameable; } public function setDeviceReady($device_ready) { $this->deviceReady = $device_ready; return $this; } public function getDeviceReady() { return $this->deviceReady; } protected function willRenderPage() { // We render this now to resolve static resources so they can appear in the // document head. $this->bodyContent = phutil_implode_html('', $this->renderChildren()); } protected function getHead() { $framebust = null; if (!$this->getFrameable()) { $framebust = '(top == self) || top.location.replace(self.location.href);'; } $viewport_tag = null; if ($this->getDeviceReady()) { $viewport_tag = phutil_tag( 'meta', array( 'name' => 'viewport', 'content' => 'width=device-width, '. 'initial-scale=1, '. 'maximum-scale=1', )); } $mask_icon = phutil_tag( 'link', array( 'rel' => 'mask-icon', 'color' => '#3D4B67', 'href' => celerity_get_resource_uri( '/rsrc/favicons/mask-icon.svg'), )); $icon_tag_76 = phutil_tag( 'link', array( 'rel' => 'apple-touch-icon', 'href' => celerity_get_resource_uri( '/rsrc/favicons/apple-touch-icon-76x76.png'), )); $icon_tag_120 = phutil_tag( 'link', array( 'rel' => 'apple-touch-icon', 'sizes' => '120x120', 'href' => celerity_get_resource_uri( '/rsrc/favicons/apple-touch-icon-120x120.png'), )); $icon_tag_152 = phutil_tag( 'link', array( 'rel' => 'apple-touch-icon', 'sizes' => '152x152', 'href' => celerity_get_resource_uri( '/rsrc/favicons/apple-touch-icon-152x152.png'), )); - $apple_tag = phutil_tag( - 'meta', + $favicon_tag = phutil_tag( + 'link', array( - 'name' => 'apple-mobile-web-app-status-bar-style', - 'content' => 'black-translucent', + 'id' => 'favicon', + 'rel' => 'shortcut icon', + 'href' => celerity_get_resource_uri( + '/rsrc/favicons/favicon.ico'), )); $referrer_tag = phutil_tag( 'meta', array( 'name' => 'referrer', 'content' => 'never', )); $response = CelerityAPI::getStaticResourceResponse(); if ($this->getRequest()) { $viewer = $this->getRequest()->getViewer(); if ($viewer) { $postprocessor_key = $viewer->getUserSetting( PhabricatorAccessibilitySetting::SETTINGKEY); if (strlen($postprocessor_key)) { $response->setPostProcessorKey($postprocessor_key); } } } $developer = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); return hsprintf( '%s%s%s%s%s%s%s%s%s', $viewport_tag, $mask_icon, $icon_tag_76, $icon_tag_120, $icon_tag_152, - $apple_tag, + $favicon_tag, $referrer_tag, CelerityStaticResourceResponse::renderInlineScript( $framebust.jsprintf('window.__DEV__=%d;', ($developer ? 1 : 0))), $response->renderResourcesOfType('css')); } protected function getBody() { return $this->bodyContent; } protected function getTail() { $response = CelerityAPI::getStaticResourceResponse(); return $response->renderResourcesOfType('js'); } } diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index 7d9fccde5b..4bd09992e4 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -1,634 +1,654 @@ applicationMenu = $application_menu; return $this; } public function getApplicationMenu() { return $this->applicationMenu; } public function setController(PhabricatorController $controller) { $this->controller = $controller; return $this; } public function getController() { return $this->controller; } + private function getFaviconURI($type = null) { + switch ($type) { + case 'message': + return celerity_get_resource_uri('/rsrc/favicons/favicon-message.ico'); + case 'mention': + return celerity_get_resource_uri('/rsrc/favicons/favicon-mention.ico'); + default: + return celerity_get_resource_uri('/rsrc/favicons/favicon.ico'); + } + } + public function render() { $viewer = $this->getViewer(); require_celerity_resource('phabricator-main-menu-view'); $header_id = celerity_generate_unique_node_id(); $menu_bar = array(); $alerts = array(); $search_button = ''; $app_button = ''; $aural = null; if ($viewer->isLoggedIn() && $viewer->isUserActivated()) { list($menu, $dropdowns, $aural) = $this->renderNotificationMenu(); if (array_filter($menu)) { $alerts[] = $menu; } $menu_bar = array_merge($menu_bar, $dropdowns); $app_button = $this->renderApplicationMenuButton($header_id); $search_button = $this->renderSearchMenuButton($header_id); } else { $app_button = $this->renderApplicationMenuButton($header_id); if (PhabricatorEnv::getEnvConfig('policy.allow-public')) { $search_button = $this->renderSearchMenuButton($header_id); } } $search_menu = $this->renderPhabricatorSearchMenu(); if ($alerts) { $alerts = javelin_tag( 'div', array( 'class' => 'phabricator-main-menu-alerts', 'aural' => false, ), $alerts); } if ($aural) { $aural = javelin_tag( 'span', array( 'aural' => true, ), phutil_implode_html(' ', $aural)); } $applications = PhabricatorApplication::getAllInstalledApplications(); $menus = array(); $controller = $this->getController(); foreach ($applications as $application) { $app_actions = $application->buildMainMenuItems( $viewer, $controller); $app_extra = $application->buildMainMenuExtraNodes( $viewer, $controller); foreach ($app_actions as $action) { $menus[] = id(new PHUIMainMenuView()) ->setMenuBarItem($action) ->setOrder($action->getOrder()); } if ($app_extra !== null) { $menus[] = id(new PHUIMainMenuView()) ->appendChild($app_extra); } } $extensions = PhabricatorMainMenuBarExtension::getAllEnabledExtensions(); foreach ($extensions as $extension) { $extension->setViewer($viewer); $controller = $this->getController(); if ($controller) { $extension->setController($controller); $application = $controller->getCurrentApplication(); if ($application) { $extension->setApplication($application); } } } foreach ($extensions as $key => $extension) { if (!$extension->isExtensionEnabledForViewer($extension->getViewer())) { unset($extensions[$key]); } } foreach ($extensions as $extension) { foreach ($extension->buildMainMenus() as $menu) { $menus[] = $menu; } } $menus = msort($menus, 'getOrder'); $bar_items = array(); foreach ($menus as $menu) { $menu_bar[] = $menu; $item = $menu->getMenuBarItem(); if ($item === null) { continue; } $bar_items[] = $item; } $application_menu = $this->renderApplicationMenu($bar_items); $classes = array(); $classes[] = 'phabricator-main-menu'; $classes[] = 'phabricator-main-menu-background'; return phutil_tag( 'div', array( 'class' => implode(' ', $classes), 'id' => $header_id, ), array( $app_button, $search_button, $this->renderPhabricatorLogo(), $alerts, $aural, $application_menu, $search_menu, $menu_bar, )); } private function renderSearch() { $viewer = $this->getViewer(); $result = null; $keyboard_config = array( 'helpURI' => '/help/keyboardshortcut/', ); if ($viewer->isLoggedIn()) { $show_search = $viewer->isUserActivated(); } else { $show_search = PhabricatorEnv::getEnvConfig('policy.allow-public'); } if ($show_search) { $search = new PhabricatorMainMenuSearchView(); $search->setViewer($viewer); $application = null; $controller = $this->getController(); if ($controller) { $application = $controller->getCurrentApplication(); } if ($application) { $search->setApplication($application); } $result = $search; $keyboard_config['searchID'] = $search->getID(); } $keyboard_config['pht'] = array( '/' => pht('Give keyboard focus to the search box.'), '?' => pht('Show keyboard shortcut help for the current page.'), ); Javelin::initBehavior( 'phabricator-keyboard-shortcuts', $keyboard_config); if ($result) { $result = id(new PHUIListItemView()) ->addClass('phabricator-main-menu-search') ->appendChild($result); } return $result; } public function renderApplicationMenuButton($header_id) { $button_id = celerity_generate_unique_node_id(); return javelin_tag( 'a', array( 'class' => 'phabricator-main-menu-expand-button '. 'phabricator-expand-search-menu', 'sigil' => 'jx-toggle-class', 'meta' => array( 'map' => array( $header_id => 'phabricator-application-menu-expanded', $button_id => 'menu-icon-selected', ), ), ), phutil_tag( 'span', array( 'class' => 'phabricator-menu-button-icon phui-icon-view '. 'phui-font-fa fa-bars', 'id' => $button_id, ), '')); } private function renderApplicationMenu(array $bar_items) { $viewer = $this->getViewer(); $view = $this->getApplicationMenu(); if (!$view) { $view = new PHUIListView(); } $view->addClass('phabricator-dark-menu'); $view->addClass('phabricator-application-menu'); if ($bar_items) { $view->addMenuItem( id(new PHUIListItemView()) ->setType(PHUIListItemView::TYPE_LABEL) ->setName(pht('Actions'))); foreach ($bar_items as $bar_item) { $view->addMenuItem($bar_item); } } return $view; } public function renderSearchMenuButton($header_id) { $button_id = celerity_generate_unique_node_id(); return javelin_tag( 'a', array( 'class' => 'phabricator-main-menu-search-button '. 'phabricator-expand-application-menu', 'sigil' => 'jx-toggle-class', 'meta' => array( 'map' => array( $header_id => 'phabricator-search-menu-expanded', $button_id => 'menu-icon-selected', ), ), ), phutil_tag( 'span', array( 'class' => 'phabricator-menu-button-icon phui-icon-view '. 'phui-font-fa fa-search', 'id' => $button_id, ), '')); } private function renderPhabricatorSearchMenu() { $view = new PHUIListView(); $view->addClass('phabricator-dark-menu'); $view->addClass('phabricator-search-menu'); $search = $this->renderSearch(); if ($search) { $view->addMenuItem($search); } return $view; } private function renderPhabricatorLogo() { $custom_header = PhabricatorCustomLogoConfigType::getLogoImagePHID(); $logo_style = array(); if ($custom_header) { $cache = PhabricatorCaches::getImmutableCache(); $cache_key_logo = 'ui.custom-header.logo-phid.v3.'.$custom_header; $logo_uri = $cache->getKey($cache_key_logo); if (!$logo_uri) { $file = id(new PhabricatorFileQuery()) ->setViewer($this->getViewer()) ->withPHIDs(array($custom_header)) ->executeOne(); if ($file) { $logo_uri = $file->getViewURI(); $cache->setKey($cache_key_logo, $logo_uri); } } $logo_style[] = 'background-size: 40px 40px;'; $logo_style[] = 'background-position: 0 0;'; $logo_style[] = 'background-image: url('.$logo_uri.')'; } $logo_node = phutil_tag( 'span', array( 'class' => 'phabricator-main-menu-eye', 'style' => implode(' ', $logo_style), )); $wordmark_text = PhabricatorCustomLogoConfigType::getLogoWordmark(); if (!strlen($wordmark_text)) { $wordmark_text = pht('Phabricator'); } $wordmark_node = phutil_tag( 'span', array( 'class' => 'phabricator-wordmark', ), $wordmark_text); return phutil_tag( 'a', array( 'class' => 'phabricator-main-menu-brand', 'href' => '/', ), array( javelin_tag( 'span', array( 'aural' => true, ), pht('Home')), $logo_node, $wordmark_node, )); } private function renderNotificationMenu() { $viewer = $this->getViewer(); require_celerity_resource('phabricator-notification-css'); require_celerity_resource('phabricator-notification-menu-css'); $container_classes = array('alert-notifications'); $aural = array(); $dropdown_query = id(new AphlictDropdownDataQuery()) ->setViewer($viewer); $dropdown_data = $dropdown_query->execute(); $message_tag = ''; $message_notification_dropdown = ''; $conpherence_app = 'PhabricatorConpherenceApplication'; $conpherence_data = $dropdown_data[$conpherence_app]; if ($conpherence_data['isInstalled']) { $message_id = celerity_generate_unique_node_id(); $message_count_id = celerity_generate_unique_node_id(); $message_dropdown_id = celerity_generate_unique_node_id(); $message_count_number = $conpherence_data['rawCount']; if ($message_count_number) { $aural[] = phutil_tag( 'a', array( 'href' => '/conpherence/', ), pht( '%s unread messages.', new PhutilNumber($message_count_number))); } else { $aural[] = pht('No messages.'); } $message_count_tag = phutil_tag( 'span', array( 'id' => $message_count_id, 'class' => 'phabricator-main-menu-message-count', ), $conpherence_data['count']); $message_icon_tag = javelin_tag( 'span', array( 'class' => 'phabricator-main-menu-message-icon phui-icon-view '. 'phui-font-fa fa-comments', 'sigil' => 'menu-icon', ), ''); if ($message_count_number) { $container_classes[] = 'message-unread'; } $message_tag = phutil_tag( 'a', array( 'href' => '/conpherence/', 'class' => implode(' ', $container_classes), 'id' => $message_id, ), array( $message_icon_tag, $message_count_tag, )); Javelin::initBehavior( 'aphlict-dropdown', array( 'bubbleID' => $message_id, 'countID' => $message_count_id, 'dropdownID' => $message_dropdown_id, 'loadingText' => pht('Loading...'), 'uri' => '/conpherence/panel/', 'countType' => $conpherence_data['countType'], 'countNumber' => $message_count_number, 'unreadClass' => 'message-unread', + 'favicon' => $this->getFaviconURI('default'), + 'message_favicon' => $this->getFaviconURI('message'), + 'mention_favicon' => $this->getFaviconURI('mention'), )); $message_notification_dropdown = javelin_tag( 'div', array( 'id' => $message_dropdown_id, 'class' => 'phabricator-notification-menu', 'sigil' => 'phabricator-notification-menu', 'style' => 'display: none;', ), ''); } $bubble_tag = ''; $notification_dropdown = ''; $notification_app = 'PhabricatorNotificationsApplication'; $notification_data = $dropdown_data[$notification_app]; if ($notification_data['isInstalled']) { $count_id = celerity_generate_unique_node_id(); $dropdown_id = celerity_generate_unique_node_id(); $bubble_id = celerity_generate_unique_node_id(); $count_number = $notification_data['rawCount']; if ($count_number) { $aural[] = phutil_tag( 'a', array( 'href' => '/notification/', ), pht( '%s unread notifications.', new PhutilNumber($count_number))); } else { $aural[] = pht('No notifications.'); } $count_tag = phutil_tag( 'span', array( 'id' => $count_id, 'class' => 'phabricator-main-menu-alert-count', ), $notification_data['count']); $icon_tag = javelin_tag( 'span', array( 'class' => 'phabricator-main-menu-alert-icon phui-icon-view '. 'phui-font-fa fa-bell', 'sigil' => 'menu-icon', ), ''); if ($count_number) { $container_classes[] = 'alert-unread'; } $bubble_tag = phutil_tag( 'a', array( 'href' => '/notification/', 'class' => implode(' ', $container_classes), 'id' => $bubble_id, ), array($icon_tag, $count_tag)); Javelin::initBehavior( 'aphlict-dropdown', array( 'bubbleID' => $bubble_id, 'countID' => $count_id, 'dropdownID' => $dropdown_id, 'loadingText' => pht('Loading...'), 'uri' => '/notification/panel/', 'countType' => $notification_data['countType'], 'countNumber' => $count_number, 'unreadClass' => 'alert-unread', + 'favicon' => $this->getFaviconURI('default'), + 'message_favicon' => $this->getFaviconURI('message'), + 'mention_favicon' => $this->getFaviconURI('mention'), )); $notification_dropdown = javelin_tag( 'div', array( 'id' => $dropdown_id, 'class' => 'phabricator-notification-menu', 'sigil' => 'phabricator-notification-menu', 'style' => 'display: none;', ), ''); } // Admin Level Urgent Notification Channel $setup_tag = ''; $setup_notification_dropdown = ''; if ($viewer && $viewer->getIsAdmin()) { $open = PhabricatorSetupCheck::getOpenSetupIssueKeys(); if ($open) { $setup_id = celerity_generate_unique_node_id(); $setup_count_id = celerity_generate_unique_node_id(); $setup_dropdown_id = celerity_generate_unique_node_id(); $setup_count_number = count($open); if ($setup_count_number) { $aural[] = phutil_tag( 'a', array( 'href' => '/config/issue/', ), pht( '%s unresolved issues.', new PhutilNumber($setup_count_number))); } else { $aural[] = pht('No issues.'); } $setup_count_tag = phutil_tag( 'span', array( 'id' => $setup_count_id, 'class' => 'phabricator-main-menu-setup-count', ), $setup_count_number); $setup_icon_tag = javelin_tag( 'span', array( 'class' => 'phabricator-main-menu-setup-icon phui-icon-view '. 'phui-font-fa fa-exclamation-circle', 'sigil' => 'menu-icon', ), ''); if ($setup_count_number) { $container_classes[] = 'setup-unread'; } $setup_tag = phutil_tag( 'a', array( 'href' => '/config/issue/', 'class' => implode(' ', $container_classes), 'id' => $setup_id, ), array( $setup_icon_tag, $setup_count_tag, )); Javelin::initBehavior( 'aphlict-dropdown', array( 'bubbleID' => $setup_id, 'countID' => $setup_count_id, 'dropdownID' => $setup_dropdown_id, 'loadingText' => pht('Loading...'), 'uri' => '/config/issue/panel/', 'countType' => null, 'countNumber' => null, 'unreadClass' => 'setup-unread', + 'favicon' => $this->getFaviconURI('default'), + 'message_favicon' => $this->getFaviconURI('message'), + 'mention_favicon' => $this->getFaviconURI('mention'), )); $setup_notification_dropdown = javelin_tag( 'div', array( 'id' => $setup_dropdown_id, 'class' => 'phabricator-notification-menu', 'sigil' => 'phabricator-notification-menu', 'style' => 'display: none;', ), ''); } } $dropdowns = array( $notification_dropdown, $message_notification_dropdown, $setup_notification_dropdown, ); return array( array( $bubble_tag, $message_tag, $setup_tag, ), $dropdowns, $aural, ); } } diff --git a/webroot/rsrc/css/application/config/config-page.css b/webroot/rsrc/css/application/config/config-page.css index a46ead7a2c..5fe15aadb8 100644 --- a/webroot/rsrc/css/application/config/config-page.css +++ b/webroot/rsrc/css/application/config/config-page.css @@ -1,59 +1,77 @@ /** * @provides config-page-css */ .config-page-header { margin: 28px 24px 0; padding-bottom: 28px; border-bottom: 1px solid {$thinblueborder}; } +.device-phone .config-page-header { + margin: 4px 12px 0; + padding-bottom: 4px; +} + .config-page-header .phui-profile-header { padding: 0; } +.device-phone .config-page-header .phui-profile-header { + padding-left: 4px; + padding-right: 4px; +} + .config-page-header .phui-profile-header.phui-header-shell .phui-header-header { font-size: 20px; } +.device-phone .config-page-header .phui-profile-header.phui-header-shell + .phui-header-header { + font-size: 16px; +} .config-page-content { margin: 0 24px; } +.device-phone .config-page-content { + margin: 0 4px; +} + .device-desktop .config-page-content .phui-object-item-list-view { padding-left: 0; padding-right: 0; } .device-desktop .config-page-content .phui-document-fluid .phui-document-view { padding: 16px 0; margin: 0; } .config-page-content .aphront-table-view { border: none; } .config-page-property { padding-top: 4px; border-bottom: 1px solid {$thinblueborder}; } .config-page-content .aphront-table-notice { padding: 0; } .config-page-content .aphront-table-notice .phui-info-view { margin-left: 0; margin-right: 0; } .config-page-content .aphront-table-wrap + .aphront-table-wrap { margin-top: 20px; border-top: 1px solid {$thinblueborder}; } .config-page-content .phui-box.phui-box-blue-property { margin-top: 16px; } diff --git a/webroot/rsrc/css/application/conpherence/durable-column.css b/webroot/rsrc/css/application/conpherence/durable-column.css index f94fa1f6b8..d141115b73 100644 --- a/webroot/rsrc/css/application/conpherence/durable-column.css +++ b/webroot/rsrc/css/application/conpherence/durable-column.css @@ -1,347 +1,314 @@ /** * @provides conpherence-durable-column-view */ .global-upload-mask { pointer-events: none; } .conpherence-durable-column { position: fixed; bottom: 0; right: 16px; width: 400px; height: 360px; background: #fff; border-top-right-radius: 3px; border-top-left-radius: 3px; box-shadow: 0px 1px 8px rgba(55,55,55, .3); } .device .conpherence-durable-column { display: none; } .conpherence-durable-column .conpherence-transaction-image { float: left; border-radius: 3px; height: 24px; width: 24px; background-size: 24px; position: absolute; top: 5px; } .device-desktop .conpherence-durable-column.loading .loading-mask { display: block; } .conpherence-durable-column-header .conpherence-settings-dropdown { z-index: 1; } .conpherence-durable-column-header .phabricator-application-menu .phui-list-item-name { display: none; } .conpherence-durable-column-header .aphlict-connection-status { width: 6px; float: left; height: 18px; margin-left: 10px; margin-top: 8px; } .conpherence-durable-column-header .aphlict-connection-status .connection-status-text { display: none; } .conpherence-durable-column-header .aphlict-connection-status .phui-icon-view { font-size: 10px; } .conpherence-durable-column-header .phabricator-application-menu .phui-list-item-view { margin: 0; width: 28px; height: 34px; min-width: 28px; } .conpherence-durable-column-header .phabricator-application-menu .phui-list-item-href { background: transparent; border: none; padding: 0; } .conpherence-durable-column-header { border-top-right-radius: 3px; border-top-left-radius: 3px; background-color: #525867; } .conpherence-durable-column-header:hover { cursor: pointer; background-color: #5f6572; } .conpherence-durable-column-header .phabricator-application-menu { margin-right: 8px; } .conpherence-durable-column-header .phabricator-main-menu-dropdown.phui-list-sidenav { top: 30px; } .conpherence-durable-column-header-text { float: left; padding: 8px 0 8px 10px; color: #fff; width: 260px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; text-shadow: 1px 1px 0 rgba(0,0,0,.6); } .conpherence-durable-column-header .phabricator-application-menu .phui-list-item-icon.phui-font-fa { font-size: 15px; margin: 0; height: 15px; width: 15px; padding: 10px 8px 10px 8px; } .conpherence-durable-column-icon-bar { width: 36px; background-color: {$lightgreybackground}; border-right: 1px solid {$thinblueborder}; position: absolute; top: 0; left: 0; bottom: 0; } .conpherence-durable-column-icon-bar .conpherence-durable-column-thread-icon { height: 28px; width: 28px; padding: 4px; display: block; } .conpherence-durable-column-icon-bar .conpherence-durable-column-thread-icon.selected { background-color: rgba({$alphablue},.1); } .conpherence-durable-column-icon-bar .conpherence-durable-column-thread-icon span { display: block; width: 28px; height: 28px; border-radius: 3px; background-size: 28px 28px; } .conpherence-durable-column-body { position: absolute; top: 34px; bottom: 0; right: 0; left: 0; } .conpherence-durable-column-main { position: absolute; top: 0; bottom: 36px; left: 34px; right: 0; overflow-x: hidden; } .conpherence-durable-column .column-no-rooms { padding: 12px 8px; } .conpherence-durable-column .column-no-rooms-text { color: {$greytext}; font-style: italic; margin-bottom: 16px; } .conpherence-durable-column-transactions { padding: 8px 12px 0; } -.conpherence-durable-column-transactions - .conpherence-transaction-view.conpherence-edited { - color: {$lightgreytext}; - margin: 0; - padding: 0; - font-style: italic; -} - -.conpherence-durable-column-transactions .conpherence-edited - .conpherence-transaction-header { - display: none; -} - .conpherence-durable-column-transactions .conpherence-transaction-view { background: none; margin: 0; padding: 4px 0; min-height: 0; } .conpherence-durable-column-transactions .conpherence-transaction-view .conpherence-message { word-wrap: break-word; } -.conpherence-durable-column-transactions .conpherence-transaction-detail { - border: 0; - margin: 0 0 0 32px; +.conpherence-durable-column-transactions .conpherence-transaction-view + .conpherence-transaction-detail { + border: 0; + margin: 0 0 0 32px; } -.conpherence-durable-column-transactions .conpherence-transaction-detail - .conpherence-transaction-header { +.conpherence-durable-column-transactions .conpherence-transaction-view + .conpherence-transaction-detail .conpherence-transaction-header { background: none; padding: 0 0 2px 0; } .conpherence-durable-column-transactions -.conpherence-transaction-view.date-marker { - margin: 12px 0 0; + .conpherence-transaction-view.date-marker { + margin: 12px 0 0; } .conpherence-durable-column-transactions -.conpherence-transaction-view.date-marker .date { - left: 0; - font-size: {$normalfontsize}; - top: -14px; - padding: 0 6px 0 0; -} - -.conpherence-durable-column-transactions .conpherence-transaction-detail -.conpherence-transaction-header .conpherence-transaction-info { - color: {$lightbluetext}; - font-size: {$smallerfontsize}; -} - -.conpherence-transaction-header .epoch-link { - color: {$lightgreytext}; -} - -.conpherence-durable-column-transactions .conpherence-transaction-detail -.conpherence-transaction-header .phui-link-person { - margin: 0 8px 0 0; -} - -.conpherence-durable-column-transactions .conpherence-transaction-detail -.conpherence-transaction-content .phui-link-person { - color: #000; + .conpherence-transaction-view.date-marker .date { + left: 0; + font-size: {$normalfontsize}; + top: -10px; + padding: 0 6px 0 0; } .conpherence-durable-column-transactions .conpherence-transaction-detail .conpherence-transaction-content .phui-pinboard-item-view { width: 273px; } .conpherence-durable-column-transactions .conpherence-transaction-detail .conpherence-transaction-content .phui-pinboard-item-view .phui-pinboard-item-image-link img { width: 265px; height: 199px; } .conpherence-durable-column-transactions .conpherence-transaction-detail -.conpherence-transaction-content { - background: #fff; - padding: 0 0 8px 0; + .conpherence-transaction-content { + padding: 0 0 8px 0; } .conpherence-durable-column-textarea { position: absolute; left: 0; right: 0; bottom: 0; height: 36px; margin: 0; border-width: 1px 0 0 0; border-style: solid; border-top-color: {$thinblueborder}; padding: 8px; width: 100%; resize: none; } .conpherence-durable-column-textarea:focus { outline: 0; border-top-color: {$lightblueborder}; box-shadow: none; } /* Minimized Column */ .minimize-column .conpherence-durable-column { height: 32px; width: 240px; box-shadow: none; } .minimize-column .conpherence-durable-column .conpherence-durable-column-body { display: none; } .minimize-column .conpherence-durable-column .conpherence-durable-column-header { background-color: rgba({$alphablue},.15); } .minimize-column .conpherence-durable-column .conpherence-durable-column-header:hover { background-color: rgba({$alphablue},.2); } .minimize-column .conpherence-durable-column .conpherence-durable-column-header-text { width: 100px; color: {$darkbluetext}; text-shadow: none; } .minimize-column .conpherence-durable-column .conpherence-durable-column-header .phabricator-application-menu .phui-list-item-icon.phui-font-fa { color: {$bluetext}; } .minimize-column .conpherence-durable-column .conpherence-durable-column-header .phabricator-application-menu .phui-list-item-icon.phui-font-fa:hover { color: {$darkbluetext}; } .minimize-column .conpherence-durable-column .conpherence-durable-column-header .phabricator-application-menu .phui-list-item-icon.phui-font-fa:before { content: "\f151"; } .minimize-column .conpherence-durable-column .phabricator-application-menu .conpherence-settings-icon { display: none; } diff --git a/webroot/rsrc/css/application/conpherence/header-pane.css b/webroot/rsrc/css/application/conpherence/header-pane.css index 522771cc15..f181a1adb1 100644 --- a/webroot/rsrc/css/application/conpherence/header-pane.css +++ b/webroot/rsrc/css/application/conpherence/header-pane.css @@ -1,80 +1,98 @@ /** * @provides conpherence-header-pane-css */ .conpherence-header-pane .phui-header-shell { padding: 8px 16px 10px; min-height: 38px; } .conpherence-header-pane .phui-header-header { font-size: 16px; font-family: 'Aleo', {$fontfamily}; color: #000; } .conpherence-header-pane .phui-header-subheader { color: {$lightgreytext}; padding: 0; font-size: 12px; margin: 0; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } .conpherence-header-pane .phui-header-col1 { width: 46px; height: 35px; } .conpherence-header-pane .phui-header-image { height: 35px; width: 35px; background-size: 35px; position: absolute; top: 4px; left: 0; } .conpherence-header-pane .phui-header-image-href { position: inherit; } .conpherence-header-pane .phui-header-col2 { height: 40px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 60%; + max-width: 0; } .conpherence-header-pane .phui-header-action-list .phui-header-action-item .phui-icon-view { height: 18px; width: 24px; font-size: 14px; line-height: 23px; display: block; } .device .hide-on-device { display: none; } .device-phone .conpherence-header-pane .phui-header-col3 { vertical-align: middle; } .conpherence-participant-toggle.phui-icon-circle { text-decoration: none; border-color: {$sky}; cursor: pointer; } .conpherence-participant-toggle.phui-icon-circle .phui-icon-view { - color: {$sky}; + color: {$sky}; +} + +.show-searchbar .conpherence-search-toggle.phui-icon-circle { + text-decoration: none; + border-color: {$green}; + cursor: pointer; +} + +.show-searchbar .conpherence-search-toggle.phui-icon-circle .phui-icon-view { + color: {$green}; } .hide-widgets .conpherence-participant-toggle.phui-icon-circle { text-decoration: none; border-color: {$lightblueborder}; cursor: pointer; } .hide-widgets .conpherence-participant-toggle.phui-icon-circle .phui-icon-view { - color: {$lightblueborder}; + color: {$lightblueborder}; } diff --git a/webroot/rsrc/css/application/conpherence/message-pane.css b/webroot/rsrc/css/application/conpherence/message-pane.css index 6df4cb8828..6336ac0cc5 100644 --- a/webroot/rsrc/css/application/conpherence/message-pane.css +++ b/webroot/rsrc/css/application/conpherence/message-pane.css @@ -1,402 +1,486 @@ /** * @provides conpherence-message-pane-css */ .conpherence-message-pane, .loading .messages-loading-mask, .loading .messages-loading-icon, .conpherence-layout .conpherence-no-threads { position: fixed; left: 240px; right: 240px; top: 102px; bottom: 0px; min-width: 300px; width: auto; } .device .conpherence-message-pane, .device .loading .messages-loading-mask, .device .loading .messages-loading-icon, .device .conpherence-layout .conpherence-no-threads { left: 0; right: 0; width: 100%; } .conpherence-layout .conpherence-content-pane .conpherence-no-threads { top: 44px; right: 0; background: #fff; z-index: 26; } .conpherence-layout .phui-big-info-view { margin: 16px; } .conpherence-layout .conpherence-no-threads .phui-box-border { border: none; margin: 0; } .conpherence-show-more-messages { display: block; background: #e0e3ec; margin: 10px; text-align: center; padding: 10px; color: {$bluetext}; } .conpherence-show-more-messages-loading { font-style: italic; } .conpherence-message-pane .conpherence-messages { position: fixed; left: 240px; right: 240px; top: 103px; bottom: 122px; overflow-x: hidden; overflow-y: auto; -webkit-overflow-scrolling: touch; } .conpherence-messages.jx-scrollbar-frame { overflow-y: hidden; } .conpherence-messages .jx-scrollbar-content > .conpherence-edited:first-child, .conpherence-messages > .conpherence-edited:first-child { padding-top: 20px; } .conpherence-messages .conpherence-edited:last-child { padding-bottom: 20px; } .conpherence-message-pane .conpherence-edited + .date-marker { margin-top: 24px; } .device .conpherence-message-pane .conpherence-messages { + left: 0; + bottom: 44px; + box-shadow: none; +} + +.device-phone .conpherence-message-pane .conpherence-messages { left: 0; right: 0; bottom: 44px; width: 100%; box-shadow: none; } .conpherence-message-pane .phui-form-view { border-width: 0; height: 110px; padding: 0 20px 12px; position: fixed; bottom: 0; left: 240px; right: 241px; } .conpherence-room-status { font-size: {$smallerfontsize}; color: {$lightgreytext}; font-style: italic; position: absolute; bottom: 6px; left: 24px; } .device .conpherence-room-status { display: none; } .conpherence-no-pontificate .conpherence-message-pane .phui-form-view { border-top: 1px solid {$thinblueborder}; text-align: center; } .conpherence-no-pontificate .conpherence-message-pane .aphront-form-control-submit button, .conpherence-no-pontificate .conpherence-message-pane .aphront-form-control-submit a.button { margin: 4px 0 0 0; float: none; } .conpherence-no-pontificate .phui-form-view .aphront-form-instructions { margin: 24px 0 16px; width: 100%; padding: 0; color: {$bluetext}; font-size: {$biggestfontsize}; } .device .conpherence-message-pane .phui-form-view { padding: 8px 8px; } .conpherence-message-pane .aphront-form-control-submit button, .conpherence-message-pane .aphront-form-control-submit a.button { margin-top: 6px; } .device .conpherence-message-pane .aphront-form-control-submit button, .device .conpherence-message-pane .aphront-form-control-submit a.button { margin-top: 13px; } /** * When entering "Fullscreen Mode" in the remarkup control, we need to drop * all of the "position: fixed" on parent elements or Chrome doesn't put the * textarea on top. */ .remarkup-fullscreen-mode .conpherence-message-pane, .remarkup-fullscreen-mode .conpherence-message-pane .conpherence-messages, .remarkup-fullscreen-mode .conpherence-message-pane .phui-form-view, .remarkup-fullscreen-mode .conpherence-layout { position: static; } .conpherence-message-pane .remarkup-assist-bar { border: 2px solid {$lightgreyborder}; border-bottom: none; border-top-left-radius: 3px; border-top-right-radius: 3px; background-color: {$lightgreybackground}; } .device .conpherence-message-pane .remarkup-assist-bar { position: absolute; top: 12px; left: 12px; background: {$bluebackground}; border-radius: 3px; border: none; } .device .remarkup-assist-button, .device .remarkup-assist-separator { display: none; } .device .remarkup-assist-button.remarkup-assist-upload { display: block; } .device .conpherence-message-pane .phui-form-view { + left: 0; + height: 34px; + width: auto; +} + +.device-phone .conpherence-message-pane .phui-form-view { left: 0; right: 0; height: 34px; width: auto; } .conpherence-layout .conpherence-message-pane .phui-form-view div.aphront-form-input { margin: 0; width: 100%; } -.conpherence-message-pane .conpherence-transaction-view { +.conpherence-transaction-view { padding: 2px 0px; margin: 4px 20px; background-size: 100%; min-height: auto; } -.device-phone .conpherence-message-pane .conpherence-transaction-view { +.device-phone .conpherence-transaction-view { margin: 0 8px; } -.conpherence-message-pane .conpherence-transaction-image { +.conpherence-transaction-image { float: left; border-radius: 3px; height: 35px; width: 35px; background-size: 35px; position: absolute; top: 5px; } -.device-phone .conpherence-message-pane .conpherence-transaction-image { +.device-phone .conpherence-transaction-image { height: 25px; width: 25px; background-size: 25px; } -.conpherence-message-pane .conpherence-comment.anchor-target, -.conpherence-message-pane .conpherence-edited.anchor-target { +.conpherence-transaction-view.conpherence-comment.anchor-target, +.conpherence-transaction-view.conpherence-edited.anchor-target { background: {$lightyellow}; } -.conpherence-message-pane .conpherence-comment.anchor-target { +.cconpherence-transaction-view.conpherence-comment.anchor-target { margin: 4px 8px 4px 8px; padding: 2px 4px 2px 4px; } -.conpherence-message-pane .conpherence-edited.anchor-target { +.conpherence-transaction-view.conpherence-edited.anchor-target { margin: 0px 8px 0px 8px; padding: 0px 4px 0px 4px; } -.conpherence-message-pane .conpherence-transaction-detail { +.conpherence-transaction-view .conpherence-transaction-detail { border-width: 0; margin-left: 45px; } -.device-phone .conpherence-message-pane .conpherence-transaction-detail { +.device-phone .conpherence-transaction-view .conpherence-transaction-detail { margin-left: 32px; } -.conpherence-message-pane .conpherence-transaction-view.date-marker { +.conpherence-transaction-view.date-marker { padding: 0; margin: 20px 20px 4px; min-height: auto; } -.device-phone .conpherence-message-pane -.conpherence-transaction-view.date-marker { +.device-phone .conpherence-transaction-view.date-marker { margin: 12px 0 4px; } -.device-tablet .conpherence-message-pane - .conpherence-transaction-view.date-marker { - padding-left: 37px; +.device-tablet .conpherence-transaction-view.date-marker { + padding-left: 37px; } -.conpherence-message-pane .conpherence-transaction-view.date-marker - .date { - left: 40px; - font-size: {$normalfontsize}; - padding: 0px 4px; +.conpherence-transaction-view.date-marker .date { + left: 40px; + font-size: {$normalfontsize}; + padding: 0px 4px; } -.device .conpherence-message-pane .conpherence-transaction-view.date-marker - .date { - left: 4px; +.device .conpherence-transaction-view.date-marker .date { + left: 4px; } -.device-phone .conpherence-message-pane .conpherence-edited { +.device-phone .conpherence-transaction-view.conpherence-edited { min-height: none; color: {$lightgreytext}; margin: 0 8px; } -.conpherence-message-pane .conpherence-edited .conpherence-transaction-content { - color: {$lightgreytext}; - font-size: {$biggerfontsize}; - font-style: italic; - margin: 0; - padding: 0; - float: left; - line-height: 20px; +.conpherence-transaction-view.conpherence-edited + .conpherence-transaction-content { + color: {$lightgreytext}; + font-size: {$biggerfontsize}; + font-style: italic; + margin: 0; + padding: 0; + float: left; + line-height: 20px; } -.conpherence-message-pane .conpherence-edited { +.conpherence-transaction-view.conpherence-edited { padding: 0; margin-top: 0; margin-bottom: 0; min-height: inherit; } -.conpherence-message-pane .conpherence-edited + .conpherence-comment { +.conpherence-transaction-view.conpherence-edited + .conpherence-comment { margin-top: 16px; } .conpherence-transaction-view.conpherence-edited + .conpherence-transaction-view.date-marker { margin-top: 24px; } -.conpherence-message-pane .conpherence-edited .conpherence-transaction-header { - float: right; +.conpherence-transaction-view.conpherence-edited + .conpherence-transaction-header { + float: right; } -.conpherence-message-pane .conpherence-edited +.conpherence-transaction-view.conpherence-edited .conpherence-transaction-content a { color: {$darkbluetext}; } -.conpherence-message-pane .conpherence-transaction-info { +.conpherence-transaction-view .conpherence-transaction-info { margin: 0 8px; } -.conpherence-message-pane .conpherence-transaction-info, -.conpherence-message-pane .anchor-link, -.conpherence-message-pane .phabricator-content-source-view { +.conpherence-transaction-view .conpherence-transaction-info, +.conpherence-transaction-view .transaction-date, +.conpherence-transaction-view .phabricator-content-source-view { color: {$lightgreytext}; line-height: 16px; font-size: {$smallerfontsize}; } -.conpherence-message-pane .conpherence-transaction-content { +.conpherence-transaction-view .conpherence-transaction-content { padding: 2px 0 8px 0; } .conpherence-message-pane .aphront-form-control { padding: 0; } .conpherence-message-pane .remarkup-assist-textarea { height: 68px; padding: 8px; border: 2px solid {$lightgreyborder}; border-top: 1px solid {$thinblueborder}; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; resize: none; outline: none; box-shadow: none; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; } .conpherence-message-pane .remarkup-assist-textarea:focus { border: 2px solid {$lightgreyborder}; border-top: 1px solid {$thinblueborder}; } .device .conpherence-message-pane .remarkup-assist-textarea { margin: 0; padding: 7px 8px 6px 30px; width: 100%; height: 34px; resize: none; border-top: 2px solid {$lightgreyborder}; border-top-left-radius: 3px; border-top-right-radius: 3px; } .conpherence-message-pane .remarkup-assist-textarea:focus { outline: none; } .device .conpherence-message-pane .aphront-form-control-submit { padding: 0; position: absolute; top: -2px; right: 12px; } .device .conpherence-message-pane .aphront-form-control-textarea { float: left; height: 24px; width: 100%; } .conpherence-message .phabricator-remarkup .remarkup-code-block pre { max-height: 200px; } .conpherence-transaction-collapsed .conpherence-transaction-image, .conpherence-transaction-collapsed .conpherence-transaction-header { display: none; } .conpherence-message-pane .conpherence-transaction-collapsed.conpherence-transaction-view { margin-top: 0; margin-bottom: 0; } + +/* this causes scrolling issues on iDevices */ +.device .conpherence-layout + .phabricator-standard-page-footer { + display: none; +} + +/***** Thread Loading *********************************************************/ + +.conpherence-layout .conpherence-loading-mask { + height: 0; + opacity: 0; + top: 0; + right: 0; + left: 240px; + bottom: 0; + transition: all 0.3s; + position: fixed; + background-color: #fff; +} + +.conpherence-layout.loading .conpherence-loading-mask { + opacity: 1; + height: auto; +} + + +/***** Thread Search **********************************************************/ + +.conpherence-search-main { + opacity: 0; + transition: all 0.2s; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + height: 0; +} + +.show-searchbar .conpherence-search-main { + opacity: 1; + height: auto; +} + +.conpherence-search-form-view { + display: none; +} + +.show-searchbar .conpherence-search-form-view { + display: block; + height: 54px; + background: {$lightbluebackground}; + position: absolute; + top: 1px; + left: 0; + right: 0; +} + +.conpherence-search-form-view input.conpherence-search-input { + padding-left: 8px; + width: calc(100% - 24px); + border-radius: 20px; + margin: 12px; +} + +.conpherence-search-results { + position: absolute; + background: #fff; + top: 54px; + left: 0; + right: 0; + bottom: 0; + overflow-y: auto; +} diff --git a/webroot/rsrc/css/application/conpherence/participant-pane.css b/webroot/rsrc/css/application/conpherence/participant-pane.css index 94bedce84d..c72d098226 100644 --- a/webroot/rsrc/css/application/conpherence/participant-pane.css +++ b/webroot/rsrc/css/application/conpherence/participant-pane.css @@ -1,118 +1,118 @@ /** * @provides conpherence-participant-pane-css */ .conpherence-participant-pane { position: fixed; right: 0px; top: 103px; bottom: 0; width: 240px; border-width: 0 0 0 1px; border-color: {$thinblueborder}; border-style: solid; overflow-y: auto; -webkit-overflow-scrolling: touch; } -.device .conpherence-participant-pane { +.device-phone .conpherence-participant-pane { background-color: {$page.background}; } .conpherence-participant-pane .aphront-form-input { margin: 0; width: 100%; } .conpherence-participant-pane .aphront-form-inset { border: 0; } .conpherence-participant-pane .widgets-header.phui-header-shell { padding: 8px 12px 6px; border: none; } .conpherence-participant-pane .widgets-header .phui-header-header { font-size: {$biggerfontsize}; } .conpherence-participant-pane .widgets-header .phui-icon-view.disabled { color: {$lightgreytext}; } .conpherence-participant-pane .widgets-body { position: fixed; overflow-y: auto; bottom: 0; top: 102px; width: 240px; } .conpherence-participant-pane .person-entry { padding: 4px 8px 4px 12px; } .conpherence-participant-pane .person-entry:hover { background-color: {$lightgreybackground}; } .conpherence-participant-pane .person-entry a { float: left; line-height: 22px; color: {$bluetext}; font-weight: bold; } .conpherence-participant-pane .person-entry:hover a { color: #000; } .conpherence-participant-pane .person-entry a img { height: 24px; width: 24px; border-radius: 3px; } .conpherence-participant-pane .person-entry .pic { float: left; width: 30px; } .conpherence-participant-pane .person-entry .remove { float: right; width: 20px; height: 20px; font-size: 18px; } .person-entry .remove:hover .phui-icon-view { color: {$red}; } .conpherence-participant-pane .person-entry .remove:hover { text-decoration: none; } .conpherence-participant-pane .person-entry .remove .close-icon { color: #bfbfbf; } .conpherence-participant-pane .person-entry .remove:hover .close-icon { color: #000; } /****** Hide Widgets **********************************************************/ .hide-widgets .conpherence-participant-pane { display: none; } .hide-widgets .conpherence-message-pane, .hide-widgets .loading .messages-loading-mask, .hide-widgets .loading .messages-loading-icon, .hide-widgets .conpherence-no-threads, .hide-widgets .conpherence-message-pane .conpherence-messages, .hide-widgets .conpherence-message-pane .phui-form-view { right: 0; } diff --git a/webroot/rsrc/css/application/conpherence/transaction.css b/webroot/rsrc/css/application/conpherence/transaction.css index 62454c448e..6e52a8c30c 100644 --- a/webroot/rsrc/css/application/conpherence/transaction.css +++ b/webroot/rsrc/css/application/conpherence/transaction.css @@ -1,48 +1,69 @@ /** * @provides conpherence-transaction-css */ .conpherence-transaction-view { position: relative; } .conpherence-transaction-content { overflow: auto; } .conpherence-transaction-header .phui-link-person { font-weight: bold; font-size: {$biggerfontsize}; color: #000; } .conpherence-transaction-view.date-marker { border-top: 1px solid {$sh-violetborder}; } .conpherence-transaction-view.date-marker .date { position: relative; top: -11px; background-color: #fff; color: {$sh-violettext}; font-weight: bold; } +/***** Thread Search **********************************************************/ + .conpherence-fulltext-results { - margin: 0 8px 8px; - background: {$lightgreybackground}; - border: 1px solid {$lightgreyborder}; + padding: 8px 0; +} + +.conpherence-fulltext-results + .conpherence-fulltext-results { + border-top: 2px solid {$thinblueborder}; + margin-top: -8px; } .conpherence-fulltext-result { margin: 0 0 1px; padding: 8px; } .conpherence-fulltext-match { background: {$lightyellow}; } .conpherence-fulltext-results .epoch-link { float: right; } + +.conpherence-message-pane .conpherence-fulltext-results + .conpherence-transaction-view.conpherence-fulltext-result { + margin-left: 0; + margin-right: 0; +} + +.conpherence-message-pane .conpherence-search-room-results .phui-object-box { + border: none; + margin: 0; +} + +.conpherence-message-pane .conpherence-search-room-results + .phui-object-box .phui-header-shell { + display: none; +} diff --git a/webroot/rsrc/css/application/conpherence/update.css b/webroot/rsrc/css/application/conpherence/update.css deleted file mode 100644 index 8b29c085ed..0000000000 --- a/webroot/rsrc/css/application/conpherence/update.css +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @provides conpherence-update-css - */ - -.aphront-dialog-view .conpherence-dialogue-drag-photo { - border: 1px dashed #bfbfbf; - padding: 10px 0px 10px 10px; -} - -.aphront-dialog-view .conpherence-dialogue-upload-photo { - background: {$lightgreen}; - border-color: {$green}; -} diff --git a/webroot/rsrc/css/application/search/application-search-view.css b/webroot/rsrc/css/application/search/application-search-view.css index 4a573f5111..1320df9c0f 100644 --- a/webroot/rsrc/css/application/search/application-search-view.css +++ b/webroot/rsrc/css/application/search/application-search-view.css @@ -1,55 +1,65 @@ /** * @provides application-search-view-css */ .application-search-view { background-color: #fff; } .application-search-view .application-search-results.phui-object-box { margin: 0; padding: 0 16px 24px; } +.device-phone .application-search-view + .application-search-results.phui-object-box { + padding: 0 12px 24px; +} + .application-search-view .application-search-results .phui-profile-header { padding: 16px 8px; border-bottom: 1px solid {$thinblueborder}; } .application-search-view .phui-object-box.phui-object-box-collapsed .phui-header-shell { padding: 20px 8px; } .application-search-results .phui-profile-header.phui-header-shell .phui-header-header { font-size: 20px; } .device-phone.application-search-view .application-search-results .phui-profile-header { padding: 12px 0; } +.device-phone .application-search-results + .phui-profile-header.phui-header-shell { + padding: 12px 0 12px 4px; +} + .device-phone .application-search-results .phui-profile-header.phui-header-shell .phui-header-header { font-size: 16px; } .device-phone.application-search-view .application-search-results.phui-object-box { padding: 0 12px; } .application-search-view .phui-box-border { border: none; } .application-search-pager { margin: 0 16px 16px 16px; padding: 8px; } .device-phone .application-search-pager { margin: 12px; } diff --git a/webroot/rsrc/css/core/z-index.css b/webroot/rsrc/css/core/z-index.css index 3447a18de4..3bfff11070 100644 --- a/webroot/rsrc/css/core/z-index.css +++ b/webroot/rsrc/css/core/z-index.css @@ -1,175 +1,183 @@ /** * @provides phabricator-zindex-css */ .keyboard-focus-focus-reticle { z-index: 1; } .device .phabricator-action-list-view.phabricator-action-list-toggle, .device-desktop .phui-document-content .phabricator-action-list-view.phabricator-action-list-toggle { z-index: 1; } .device-desktop .phui-timeline-minor-event .phui-timeline-image { z-index: 2; } .differential-reticle { z-index: 2; } .differential-changeset { z-index: 2; } .pholio-new-inline-comment { z-index: 2; } .slowvote-bar { z-index: 2; } div.phui-calendar-day-event { z-index: 2; } .slowvote-above-the-bar { z-index: 3; } .phui-timeline-icon-fill { z-index: 3; } .phui-crumbs-view { z-index: 3; } .phabricator-nav-local { z-index: 4; } .project-board-header { z-index: 4; } .conpherence-layout .conpherence-no-threads { z-index: 4; } .conpherence-menu-pane { z-index: 4; } .phabricator-nav-drag { z-index: 4; } -.loading .messages-loading-mask, -.loading .widgets-loading-mask { - z-index: 5; +.conpherence-message-pane .conpherence-search-main { + z-index: 4; } .dark-console { z-index: 5; } .phui-calendar-date-number { z-index: 5; } .phabricator-main-menu { z-index: 6; } .aphront-developer-error-callout { z-index: 6; } +.loading .messages-loading-mask, +.loading .widgets-loading-mask { + z-index: 6; +} + .conpherence-durable-column { z-index: 7; } .jx-scrollbar-bar { z-index: 8; } .differential-haunt-mode-1 .differential-add-comment-panel, .differential-haunt-mode-2 .differential-add-comment-panel { z-index: 8; } .device-desktop .phabricator-notification-menu { z-index: 9; } .jx-mask { z-index: 10; } .jx-notification-container { z-index: 11; } .phabricator-global-upload-instructions { z-index: 11; } .lightbox-attachment { z-index: 12; } div.jx-typeahead-results { z-index: 13; } .jx-client-dialog { z-index: 14; } .fancy-datepicker { z-index: 15; } .drag-frame { z-index: 16; } .jx-hovercard-container { z-index: 17; } .pholio-device-lightbox { z-index: 20; } .phuix-autocomplete { z-index: 21; } .conpherence-participant-pane { z-index: 25; } +.conpherence-layout .conpherence-loading-mask { + z-index: 30; +} + .phuix-dropdown-menu { z-index: 32; } .busy { z-index: 40; } .remarkup-control-fullscreen-mode { z-index: 50; } .jx-tooltip-container { z-index: 51; } .audible .aural-only { z-index: 100; } diff --git a/webroot/rsrc/css/phui/phui-feed-story.css b/webroot/rsrc/css/phui/phui-feed-story.css index d971202ebe..3fdfeb5a57 100644 --- a/webroot/rsrc/css/phui/phui-feed-story.css +++ b/webroot/rsrc/css/phui/phui-feed-story.css @@ -1,108 +1,107 @@ /** * @provides phui-feed-story-css */ .phui-object-box .phui-box.phui-feed-story { border-bottom: 1px solid {$thinblueborder}; } .phui-object-box .phui-box.phui-feed-story:last-child { border: none; } .phui-feed-story-head .phui-feed-story-actor { width: 35px; height: 35px; float: left; margin-right: 8px; border-radius: 3px; - box-shadow: {$borderinset}; } .phui-feed-story-head .phui-feed-story-actor-image { background-size: 35px; } .phui-feed-story-head .phui-feed-story-actor-icon { text-align: center; vertical-align: middle; font-size: 24px; line-height: 32px; color: #fff; background-color: #c4cde0; } .phui-feed-story-head { padding: 12px 4px; overflow: hidden; color: {$greytext}; word-break: break-word; } .phui-feed-story-head .phui-link-person { color: {$darkgreytext}; font-weight: bold; } .phui-feed-story-body { margin: 4px 4px 8px; padding-bottom: 8px; color: {$darkgreytext}; word-break: break-word; max-height: 300px; overflow: hidden; } .phui-feed-story-foot { font-size: {$smallerfontsize}; padding: 0 4px 12px; } .phui-feed-story-foot, .phui-feed-story-foot a { color: {$greytext}; } .phui-feed-story-foot .phui-icon-view { margin-right: 5px; } .phui-feed-story-bigtext-post { line-height: 18px; color: {$darkgreytext}; } .phui-feed-story-bigtext-post h3 { font-size: {$biggestfontsize}; line-height: 18px; color: {$darkgreytext}; margin: 0 0 5px 0; } .phui-feed-token-bar { margin-top: 8px; border-top: 1px solid #e7e7e7; padding-top: 8px; } .phui-feed-token-bar .phui-icon-view { margin-right: 2px; display: inline-block; } .phui-feed-story-action-list { float: right; padding-top: 4px; } .phui-feed-story-action-item { float: right; padding-left: 2px; height: 18px; width: 18px; font-size: 18px; } .phui-feed-story-action-list .phui-icon-view { display: block; } diff --git a/webroot/rsrc/css/phui/phui-icon.css b/webroot/rsrc/css/phui/phui-icon.css index 338ff4e4c3..1ceb4c3855 100644 --- a/webroot/rsrc/css/phui/phui-icon.css +++ b/webroot/rsrc/css/phui/phui-icon.css @@ -1,119 +1,129 @@ /** * @provides phui-icon-view-css */ .phui-icon-example .phui-icon-view { display: inline-block; vertical-align: top; } .phui-icon-view.sprite-tokens { height: 18px; width: 18px; display: inline-block; vertical-align: top; } .phui-icon-view.sprite-login { height: 28px; width: 28px; } .phui-icon-view.phuihead-medium { height: 50px; width: 50px; } .phui-icon-view.phuihead-small { height: 35px; width: 35px; background-size: 35px; } .phui-icon-has-text:before { margin-right: 4px; } a.phui-icon-view:hover { text-decoration: none; color: {$sky}; } /* - Icon in a Circle ------------------------------------------------------- */ .phui-icon-circle { border: 1px solid {$lightblueborder}; border-radius: 24px; height: 24px; width: 24px; text-align: center; display: inline-block; cursor: pointer; } .phui-icon-circle.circle-medium { height: 36px; width: 36px; border-radius: 36px; } .phui-icon-circle .phui-icon-view { height: 24px; width: 24px; font-size: 11px; line-height: 24px; color: {$lightblueborder}; cursor: pointer; } .phui-icon-circle.circle-medium .phui-icon-view { font-size: 18px; line-height: 36px; } a.phui-icon-circle.hover-sky:hover { text-decoration: none; border-color: {$sky}; cursor: pointer; } a.phui-icon-circle.hover-sky:hover .phui-icon-view { color: {$sky}; } a.phui-icon-circle.hover-violet:hover { text-decoration: none; border-color: {$violet}; cursor: pointer; } a.phui-icon-circle.hover-violet:hover .phui-icon-view { color: {$violet}; } a.phui-icon-circle.hover-pink:hover { text-decoration: none; border-color: {$pink}; cursor: pointer; } a.phui-icon-circle.hover-pink:hover .phui-icon-view { color: {$pink}; } +a.phui-icon-circle.hover-green:hover { + text-decoration: none; + border-color: {$green}; + cursor: pointer; +} + +a.phui-icon-circle.hover-green:hover .phui-icon-view { + color: {$green}; +} + /* - Icon in a Square ------------------------------------------------------- */ .phui-icon-view.phui-icon-square { height: 40px; width: 40px; color: #fff; font-size: 26px; text-align: center; line-height: 38px; border-radius: 3px; } a.phui-icon-view.phui-icon-square:hover { text-decoration: none; color: #fff; } diff --git a/webroot/rsrc/css/phui/phui-two-column-view.css b/webroot/rsrc/css/phui/phui-two-column-view.css index 57f8d81934..e8f1ce0de5 100644 --- a/webroot/rsrc/css/phui/phui-two-column-view.css +++ b/webroot/rsrc/css/phui/phui-two-column-view.css @@ -1,240 +1,240 @@ /** * @provides phui-two-column-view-css */ .phui-two-column-view .phui-two-column-header { background-color: #fff; border-bottom: 1px solid rgba({$alphagrey}, .12); margin-bottom: 24px; } .device .phui-two-column-view .phui-two-column-header { margin-bottom: 12px; } .phui-two-column-view.with-subheader .phui-two-column-header { margin-bottom: 0; } .phui-two-column-header .phui-header-header { font-size: 20px; font-family: 'Aleo', {$fontfamily}; color: #000; } .device-phone .phui-two-column-header .phui-header-header { - font-size: 18px; + font-size: 16px; } .phui-two-column-view .phui-two-column-header .phui-header-shell { padding: 24px 32px 28px; border: none; } .phui-two-column-view .phui-two-column-header .phui-profile-header.phui-header-shell { padding-bottom: 20px; } .device .phui-two-column-view .phui-two-column-header .phui-header-shell { padding: 12px 12px 16px; } .phui-two-column-header .phui-header-subheader { margin-top: 12px; } .phui-two-column-subheader { padding: 12px 32px; } .device .phui-two-column-subheader { padding: 12px 16px; } .device-desktop .phui-two-column-content { padding: 0 32px; } .device .phui-two-column-content { padding: 0 12px; } .device-desktop .phui-two-column-view .phui-main-column { float: left; width: calc(100% - 320px); } .device-desktop .phui-two-column-view .phui-side-column { float: right; width: 300px; } .device-desktop .phui-two-column-view.phui-side-column-left .phui-main-column { float: right; width: calc(100% - 280px); } .device-desktop .phui-two-column-view.phui-side-column-left .phui-side-column { float: left; width: 260px; } .device .phui-side-column { margin-bottom: 20px; } .phui-two-column-view .phui-two-column-content .phui-object-box { margin: 0 0 20px 0; } /* Timeline */ .phui-two-column-view .phui-timeline-view { padding: 0; background-position: 80px; } .phui-two-column-view .phui-main-column .phui-object-box + .phui-timeline-view { margin-top: -20px; } .device .phui-two-column-view .phui-timeline-view { background-position: 16px; padding: 0; } .device-phone .phui-two-column-view .phui-timeline-event-view { margin: 0; } .phui-main-column > .phui-timeline-view:first-child { border-top: 1px solid {$thinblueborder}; } .device-phone .phui-main-column .phui-timeline-older-transactions-are-hidden { margin: 0; } /* Main Column Properties */ .device-desktop .phui-main-column .phui-property-list-key { margin-left: 0; width: 160px; } .device-desktop .phui-main-column .phui-property-list-value { margin-left: 8px; width: calc(100% - 200px); } /* Property / Action List */ .phui-two-column-properties .phabricator-action-list-view { padding-top: 4px; padding-bottom: 12px; } .device-desktop .phui-two-column-view .phui-property-list-container { padding: 16px 0; } .device-desktop .phui-two-column-view .phui-property-list-properties-wrap.phui-property-list-stacked { padding: 0 16px; } .device .phui-two-column-view .phui-property-list-container { padding: 12px 8px; } .phui-two-column-view .phui-property-list-container .keyboard-shortcuts-available { display: none; } .device .phui-two-column-content .phui-two-column-properties.phui-object-box { padding: 0 12px; } .phui-two-column-properties .phabricator-action-view-icon { top: 8px; left: 8px; } .phabricator-action-view button.phabricator-action-view-item, .phabricator-action-view-item { padding: 5px 4px 5px 28px; } .device-desktop .phui-two-column-properties .phabricator-action-view:hover .phabricator-action-view-item { text-decoration: none; background-color: rgba({$alphablue}, .08); color: {$sky}; border-radius: 3px; } .device-desktop .phui-two-column-properties .phabricator-action-view:hover .phabricator-action-view-icon { color: {$sky}; } .phui-two-column-view .phui-property-list-section-header, .phui-two-column-view .phui-property-list-text-content { margin: 0 16px; } .device .phui-two-column-view .phui-property-list-section-header, .device .phui-two-column-view .phui-property-list-text-content { margin: 0 8px; } /* Info View */ .phui-two-column-view .phui-info-view { margin: 0 0 20px 0; padding: 16px; } .device .phui-two-column-view .phui-info-view { margin: 0 0 20px 0; padding: 12px; } .phui-two-column-view .phui-side-column .phui-object-item-empty .phui-info-view { margin-bottom: 0; } .phui-two-column-view .phui-box-blue-property .phui-header-shell + .phui-info-view { margin: 16px; } .device .phui-two-column-view .phui-box-blue-property .phui-header-shell + .phui-info-view { margin: 8px; } /* Navigation */ .phui-two-column-view .side-has-nav .phabricator-nav-local { width: auto; position: static; margin: 0; } .device .phui-two-column-view .side-has-nav { display: none; } /* Document View */ .phui-two-column-view .phui-two-column-content .phui-document-fluid .phui-document-view { margin: 0 0 20px 0; } diff --git a/webroot/rsrc/favicons/dark/apple-touch-icon-114x114.png b/webroot/rsrc/favicons/dark/apple-touch-icon-114x114.png deleted file mode 100644 index ddb29bcde2..0000000000 Binary files a/webroot/rsrc/favicons/dark/apple-touch-icon-114x114.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/apple-touch-icon-120x120.png b/webroot/rsrc/favicons/dark/apple-touch-icon-120x120.png deleted file mode 100644 index b641cd6558..0000000000 Binary files a/webroot/rsrc/favicons/dark/apple-touch-icon-120x120.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/apple-touch-icon-144x144.png b/webroot/rsrc/favicons/dark/apple-touch-icon-144x144.png deleted file mode 100644 index d2cf49d293..0000000000 Binary files a/webroot/rsrc/favicons/dark/apple-touch-icon-144x144.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/apple-touch-icon-152x152.png b/webroot/rsrc/favicons/dark/apple-touch-icon-152x152.png deleted file mode 100644 index 41a146e9f3..0000000000 Binary files a/webroot/rsrc/favicons/dark/apple-touch-icon-152x152.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/apple-touch-icon-57x57.png b/webroot/rsrc/favicons/dark/apple-touch-icon-57x57.png deleted file mode 100644 index a5141404ce..0000000000 Binary files a/webroot/rsrc/favicons/dark/apple-touch-icon-57x57.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/apple-touch-icon-60x60.png b/webroot/rsrc/favicons/dark/apple-touch-icon-60x60.png deleted file mode 100644 index c8dc8def04..0000000000 Binary files a/webroot/rsrc/favicons/dark/apple-touch-icon-60x60.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/apple-touch-icon-72x72.png b/webroot/rsrc/favicons/dark/apple-touch-icon-72x72.png deleted file mode 100644 index 78ae78918b..0000000000 Binary files a/webroot/rsrc/favicons/dark/apple-touch-icon-72x72.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/apple-touch-icon-76x76.png b/webroot/rsrc/favicons/dark/apple-touch-icon-76x76.png deleted file mode 100644 index 060cfb4838..0000000000 Binary files a/webroot/rsrc/favicons/dark/apple-touch-icon-76x76.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/favicon-128.png b/webroot/rsrc/favicons/dark/favicon-128.png deleted file mode 100644 index 01165d4f83..0000000000 Binary files a/webroot/rsrc/favicons/dark/favicon-128.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/favicon-16x16.png b/webroot/rsrc/favicons/dark/favicon-16x16.png deleted file mode 100644 index e98657cc57..0000000000 Binary files a/webroot/rsrc/favicons/dark/favicon-16x16.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/favicon-196x196.png b/webroot/rsrc/favicons/dark/favicon-196x196.png deleted file mode 100644 index 78cbe52e78..0000000000 Binary files a/webroot/rsrc/favicons/dark/favicon-196x196.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/favicon-32x32.png b/webroot/rsrc/favicons/dark/favicon-32x32.png deleted file mode 100644 index c2955ad83a..0000000000 Binary files a/webroot/rsrc/favicons/dark/favicon-32x32.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/favicon-96x96.png b/webroot/rsrc/favicons/dark/favicon-96x96.png deleted file mode 100644 index 9cc09dd833..0000000000 Binary files a/webroot/rsrc/favicons/dark/favicon-96x96.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/favicon.ico b/webroot/rsrc/favicons/dark/favicon.ico deleted file mode 100644 index ce3d048bd4..0000000000 Binary files a/webroot/rsrc/favicons/dark/favicon.ico and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/mstile-144x144.png b/webroot/rsrc/favicons/dark/mstile-144x144.png deleted file mode 100644 index d2cf49d293..0000000000 Binary files a/webroot/rsrc/favicons/dark/mstile-144x144.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/mstile-150x150.png b/webroot/rsrc/favicons/dark/mstile-150x150.png deleted file mode 100644 index b56a239e02..0000000000 Binary files a/webroot/rsrc/favicons/dark/mstile-150x150.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/mstile-310x150.png b/webroot/rsrc/favicons/dark/mstile-310x150.png deleted file mode 100644 index 99163350dd..0000000000 Binary files a/webroot/rsrc/favicons/dark/mstile-310x150.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/mstile-310x310.png b/webroot/rsrc/favicons/dark/mstile-310x310.png deleted file mode 100644 index 136a8e4034..0000000000 Binary files a/webroot/rsrc/favicons/dark/mstile-310x310.png and /dev/null differ diff --git a/webroot/rsrc/favicons/dark/mstile-70x70.png b/webroot/rsrc/favicons/dark/mstile-70x70.png deleted file mode 100644 index 01165d4f83..0000000000 Binary files a/webroot/rsrc/favicons/dark/mstile-70x70.png and /dev/null differ diff --git a/webroot/rsrc/favicons/favicon-mention.ico b/webroot/rsrc/favicons/favicon-mention.ico new file mode 100644 index 0000000000..6e27ce8339 Binary files /dev/null and b/webroot/rsrc/favicons/favicon-mention.ico differ diff --git a/webroot/rsrc/favicons/favicon-message.ico b/webroot/rsrc/favicons/favicon-message.ico new file mode 100644 index 0000000000..07408f3182 Binary files /dev/null and b/webroot/rsrc/favicons/favicon-message.ico differ diff --git a/webroot/rsrc/favicons/red/apple-touch-icon-114x114.png b/webroot/rsrc/favicons/red/apple-touch-icon-114x114.png deleted file mode 100644 index 9d8293ec39..0000000000 Binary files a/webroot/rsrc/favicons/red/apple-touch-icon-114x114.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/apple-touch-icon-120x120.png b/webroot/rsrc/favicons/red/apple-touch-icon-120x120.png deleted file mode 100644 index 89f65a0e2e..0000000000 Binary files a/webroot/rsrc/favicons/red/apple-touch-icon-120x120.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/apple-touch-icon-144x144.png b/webroot/rsrc/favicons/red/apple-touch-icon-144x144.png deleted file mode 100644 index b514bdc033..0000000000 Binary files a/webroot/rsrc/favicons/red/apple-touch-icon-144x144.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/apple-touch-icon-152x152.png b/webroot/rsrc/favicons/red/apple-touch-icon-152x152.png deleted file mode 100644 index df893974a5..0000000000 Binary files a/webroot/rsrc/favicons/red/apple-touch-icon-152x152.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/apple-touch-icon-57x57.png b/webroot/rsrc/favicons/red/apple-touch-icon-57x57.png deleted file mode 100644 index c8b423e6c0..0000000000 Binary files a/webroot/rsrc/favicons/red/apple-touch-icon-57x57.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/apple-touch-icon-60x60.png b/webroot/rsrc/favicons/red/apple-touch-icon-60x60.png deleted file mode 100644 index 4ef5b42ccf..0000000000 Binary files a/webroot/rsrc/favicons/red/apple-touch-icon-60x60.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/apple-touch-icon-72x72.png b/webroot/rsrc/favicons/red/apple-touch-icon-72x72.png deleted file mode 100644 index 75d9ba8407..0000000000 Binary files a/webroot/rsrc/favicons/red/apple-touch-icon-72x72.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/apple-touch-icon-76x76.png b/webroot/rsrc/favicons/red/apple-touch-icon-76x76.png deleted file mode 100644 index bd7593a772..0000000000 Binary files a/webroot/rsrc/favicons/red/apple-touch-icon-76x76.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/favicon-128.png b/webroot/rsrc/favicons/red/favicon-128.png deleted file mode 100644 index c9a9df6314..0000000000 Binary files a/webroot/rsrc/favicons/red/favicon-128.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/favicon-16x16.png b/webroot/rsrc/favicons/red/favicon-16x16.png deleted file mode 100644 index a98536fb93..0000000000 Binary files a/webroot/rsrc/favicons/red/favicon-16x16.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/favicon-196x196.png b/webroot/rsrc/favicons/red/favicon-196x196.png deleted file mode 100644 index f4a9c2a69f..0000000000 Binary files a/webroot/rsrc/favicons/red/favicon-196x196.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/favicon-32x32.png b/webroot/rsrc/favicons/red/favicon-32x32.png deleted file mode 100644 index 7bc7c159db..0000000000 Binary files a/webroot/rsrc/favicons/red/favicon-32x32.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/favicon-96x96.png b/webroot/rsrc/favicons/red/favicon-96x96.png deleted file mode 100644 index 4a874510f6..0000000000 Binary files a/webroot/rsrc/favicons/red/favicon-96x96.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/favicon.ico b/webroot/rsrc/favicons/red/favicon.ico deleted file mode 100644 index 1d9437706e..0000000000 Binary files a/webroot/rsrc/favicons/red/favicon.ico and /dev/null differ diff --git a/webroot/rsrc/favicons/red/mstile-144x144.png b/webroot/rsrc/favicons/red/mstile-144x144.png deleted file mode 100644 index b514bdc033..0000000000 Binary files a/webroot/rsrc/favicons/red/mstile-144x144.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/mstile-150x150.png b/webroot/rsrc/favicons/red/mstile-150x150.png deleted file mode 100644 index 63cba86e5a..0000000000 Binary files a/webroot/rsrc/favicons/red/mstile-150x150.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/mstile-310x150.png b/webroot/rsrc/favicons/red/mstile-310x150.png deleted file mode 100644 index ca5a1cb9a3..0000000000 Binary files a/webroot/rsrc/favicons/red/mstile-310x150.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/mstile-310x310.png b/webroot/rsrc/favicons/red/mstile-310x310.png deleted file mode 100644 index abb890254f..0000000000 Binary files a/webroot/rsrc/favicons/red/mstile-310x310.png and /dev/null differ diff --git a/webroot/rsrc/favicons/red/mstile-70x70.png b/webroot/rsrc/favicons/red/mstile-70x70.png deleted file mode 100644 index c9a9df6314..0000000000 Binary files a/webroot/rsrc/favicons/red/mstile-70x70.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/apple-touch-icon-114x114.png b/webroot/rsrc/favicons/yellow/apple-touch-icon-114x114.png deleted file mode 100644 index 81ca69890a..0000000000 Binary files a/webroot/rsrc/favicons/yellow/apple-touch-icon-114x114.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/apple-touch-icon-120x120.png b/webroot/rsrc/favicons/yellow/apple-touch-icon-120x120.png deleted file mode 100644 index 8ca5ddb2d2..0000000000 Binary files a/webroot/rsrc/favicons/yellow/apple-touch-icon-120x120.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/apple-touch-icon-144x144.png b/webroot/rsrc/favicons/yellow/apple-touch-icon-144x144.png deleted file mode 100644 index 73fcc43063..0000000000 Binary files a/webroot/rsrc/favicons/yellow/apple-touch-icon-144x144.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/apple-touch-icon-152x152.png b/webroot/rsrc/favicons/yellow/apple-touch-icon-152x152.png deleted file mode 100644 index 3de0817a02..0000000000 Binary files a/webroot/rsrc/favicons/yellow/apple-touch-icon-152x152.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/apple-touch-icon-57x57.png b/webroot/rsrc/favicons/yellow/apple-touch-icon-57x57.png deleted file mode 100644 index a41af6d514..0000000000 Binary files a/webroot/rsrc/favicons/yellow/apple-touch-icon-57x57.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/apple-touch-icon-60x60.png b/webroot/rsrc/favicons/yellow/apple-touch-icon-60x60.png deleted file mode 100644 index 45a8e345f6..0000000000 Binary files a/webroot/rsrc/favicons/yellow/apple-touch-icon-60x60.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/apple-touch-icon-72x72.png b/webroot/rsrc/favicons/yellow/apple-touch-icon-72x72.png deleted file mode 100644 index 8f4f1b35c3..0000000000 Binary files a/webroot/rsrc/favicons/yellow/apple-touch-icon-72x72.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/apple-touch-icon-76x76.png b/webroot/rsrc/favicons/yellow/apple-touch-icon-76x76.png deleted file mode 100644 index 1f386e2377..0000000000 Binary files a/webroot/rsrc/favicons/yellow/apple-touch-icon-76x76.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/favicon-128.png b/webroot/rsrc/favicons/yellow/favicon-128.png deleted file mode 100644 index a7411cc7db..0000000000 Binary files a/webroot/rsrc/favicons/yellow/favicon-128.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/favicon-16x16.png b/webroot/rsrc/favicons/yellow/favicon-16x16.png deleted file mode 100644 index 50847ee4c5..0000000000 Binary files a/webroot/rsrc/favicons/yellow/favicon-16x16.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/favicon-196x196.png b/webroot/rsrc/favicons/yellow/favicon-196x196.png deleted file mode 100644 index 577a45d64a..0000000000 Binary files a/webroot/rsrc/favicons/yellow/favicon-196x196.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/favicon-32x32.png b/webroot/rsrc/favicons/yellow/favicon-32x32.png deleted file mode 100644 index 9b92b3ff80..0000000000 Binary files a/webroot/rsrc/favicons/yellow/favicon-32x32.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/favicon-96x96.png b/webroot/rsrc/favicons/yellow/favicon-96x96.png deleted file mode 100644 index 4070e92109..0000000000 Binary files a/webroot/rsrc/favicons/yellow/favicon-96x96.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/favicon.ico b/webroot/rsrc/favicons/yellow/favicon.ico deleted file mode 100644 index 7728c042e3..0000000000 Binary files a/webroot/rsrc/favicons/yellow/favicon.ico and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/mstile-144x144.png b/webroot/rsrc/favicons/yellow/mstile-144x144.png deleted file mode 100644 index 73fcc43063..0000000000 Binary files a/webroot/rsrc/favicons/yellow/mstile-144x144.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/mstile-150x150.png b/webroot/rsrc/favicons/yellow/mstile-150x150.png deleted file mode 100644 index 3d090a694a..0000000000 Binary files a/webroot/rsrc/favicons/yellow/mstile-150x150.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/mstile-310x150.png b/webroot/rsrc/favicons/yellow/mstile-310x150.png deleted file mode 100644 index 08d4855c67..0000000000 Binary files a/webroot/rsrc/favicons/yellow/mstile-310x150.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/mstile-310x310.png b/webroot/rsrc/favicons/yellow/mstile-310x310.png deleted file mode 100644 index 9b95754168..0000000000 Binary files a/webroot/rsrc/favicons/yellow/mstile-310x310.png and /dev/null differ diff --git a/webroot/rsrc/favicons/yellow/mstile-70x70.png b/webroot/rsrc/favicons/yellow/mstile-70x70.png deleted file mode 100644 index a7411cc7db..0000000000 Binary files a/webroot/rsrc/favicons/yellow/mstile-70x70.png and /dev/null differ diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js index b564350ff2..f12be7a22b 100644 --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js @@ -1,242 +1,255 @@ /** * @provides javelin-behavior-aphlict-dropdown * @requires javelin-behavior * javelin-request * javelin-stratcom * javelin-vector * javelin-dom * javelin-uri * javelin-behavior-device * phabricator-title + * phabricator-favicon */ JX.behavior('aphlict-dropdown', function(config, statics) { // Track the current globally visible menu. statics.visible = statics.visible || null; var dropdown = JX.$(config.dropdownID); var bubble = JX.$(config.bubbleID); var icon = JX.DOM.scry(bubble, 'span', 'menu-icon')[0]; + var favicon = config.favicon; + var message_favicon = config.message_favicon; var count; if (config.countID) { count = JX.$(config.countID); } var request = null; var dirty = config.local ? false : true; + function _updateFavicon(new_count) { + if ((config.countType == 'messages') && (new_count)) { + JX.Favicon.setFavicon(message_favicon); + } else if (config.countType == 'messages') { + JX.Favicon.setFavicon(favicon); + } + } + if (config.countType) { JX.Title.setCount(config.countType, config.countNumber); + _updateFavicon(config.countNumber); } function _updateCount(number) { if (config.countType) { JX.Title.setCount(config.countType, number); + _updateFavicon(number); } else { return; } JX.DOM.setContent(count, number); if (number === 0) { JX.DOM.alterClass(bubble, config.unreadClass, false); } else { JX.DOM.alterClass(bubble, config.unreadClass, true); } } function refresh() { if (dirty) { JX.DOM.setContent(dropdown, config.loadingText); JX.DOM.alterClass( dropdown, 'phabricator-notification-menu-loading', true); } if (request) { // Already fetching. return; } request = new JX.Request(config.uri, function(response) { var number = response.number; _updateCount(number); dirty = false; JX.DOM.alterClass( dropdown, 'phabricator-notification-menu-loading', false); JX.DOM.setContent(dropdown, JX.$H(response.content)); request = null; }); request.send(); } JX.Stratcom.listen( 'quicksand-redraw', null, function (e) { var data = e.getData(); if (config.local && config.applicationClass) { var local_dropdowns = data.newResponse.aphlictDropdowns; if (local_dropdowns[config.applicationClass]) { JX.DOM.replace( dropdown, JX.$H(local_dropdowns[config.applicationClass])); dropdown = JX.$(config.dropdownID); if (dropdown.childNodes.length === 0) { JX.DOM.hide(bubble); } else { JX.DOM.show(bubble); } } else { JX.DOM.hide(bubble); } return; } if (!data.fromServer) { return; } var new_data = data.newResponse.aphlictDropdownData; update_counts(new_data); }); JX.Stratcom.listen( 'conpherence-redraw-aphlict', null, function (e) { update_counts(e.getData()); }); function update_counts(new_data) { var updated = false; for (var ii = 0; ii < new_data.length; ii++) { if (new_data[ii].countType != config.countType) { continue; } if (!new_data[ii].isInstalled) { continue; } updated = true; _updateCount(parseInt(new_data[ii].count)); } if (updated) { dirty = true; } } function set_visible(menu, icon) { if (menu) { statics.visible = {menu: menu, icon: icon}; if (icon) { JX.DOM.alterClass(icon, 'menu-icon-selected', true); } } else { if (statics.visible) { JX.DOM.hide(statics.visible.menu); if (statics.visible.icon) { JX.DOM.alterClass(statics.visible.icon, 'menu-icon-selected', false); } } statics.visible = null; } } JX.Stratcom.listen( 'click', null, function(e) { if (!e.getNode('phabricator-notification-menu')) { // Click outside the dropdown; hide it. set_visible(null); return; } if (e.getNode('tag:a')) { // User clicked a link. Hide the menu, then follow the link. set_visible(null); return; } if (!e.getNode('notification')) { // User clicked somewhere in the dead area of the menu, like the header // or footer. return; } // If the user clicked a notification (but missed a link) and it has a // primary URI, go there. var href = e.getNodeData('notification').href; if (href) { JX.$U(href).go(); e.kill(); set_visible(null); } }); JX.DOM.listen( bubble, 'click', null, function(e) { if (!e.isNormalClick()) { return; } if (config.desktop && JX.Device.getDevice() != 'desktop') { return; } e.kill(); // If a menu is currently open, close it. if (statics.visible) { var previously_visible = statics.visible; set_visible(null); // If the menu we just closed was the menu attached to the clicked // icon, we're all done -- clicking the icon for an open menu just // closes it. Otherwise, we closed some other menu and still need to // open the one the user just clicked. if (previously_visible.menu === dropdown) { return; } } if (dirty) { refresh(); } var p = JX.$V(bubble); JX.DOM.show(dropdown); p.y = null; if (config.containerDivID) { var pc = JX.$V(JX.$(config.containerDivID)); p.x -= (JX.Vector.getDim(dropdown).x - JX.Vector.getDim(bubble).x + pc.x); } else if (config.right) { p.x -= (JX.Vector.getDim(dropdown).x - JX.Vector.getDim(bubble).x); } else { p.x -= 6; } p.setPos(dropdown); set_visible(dropdown, icon); } ); JX.Stratcom.listen('notification-panel-update', null, function() { if (config.local) { return; } dirty = true; refresh(); }); JX.Stratcom.listen('notification-panel-close', null, function() { set_visible(null); }); }); diff --git a/webroot/rsrc/js/application/conpherence/ConpherenceThreadManager.js b/webroot/rsrc/js/application/conpherence/ConpherenceThreadManager.js index 0a39863c74..831cceab59 100644 --- a/webroot/rsrc/js/application/conpherence/ConpherenceThreadManager.js +++ b/webroot/rsrc/js/application/conpherence/ConpherenceThreadManager.js @@ -1,523 +1,514 @@ /** * @provides conpherence-thread-manager * @requires javelin-dom * javelin-util * javelin-stratcom * javelin-install * javelin-aphlict * javelin-workflow * javelin-router * javelin-behavior-device * javelin-vector */ JX.install('ConpherenceThreadManager', { construct : function() { if (__DEV__) { if (JX.ConpherenceThreadManager._instance) { JX.$E('ConpherenceThreadManager object is a singleton.'); } } JX.ConpherenceThreadManager._instance = this; return this; }, members: { _loadThreadURI: null, _loadedThreadID: null, _loadedThreadPHID: null, _latestTransactionID: null, _transactionIDMap: null, _transactionCache: null, _canEditLoadedThread: null, _updating: null, - _minimalDisplay: false, _messagesRootCallback: JX.bag, _willLoadThreadCallback: JX.bag, _didLoadThreadCallback: JX.bag, _didUpdateThreadCallback: JX.bag, _willSendMessageCallback: JX.bag, _didSendMessageCallback: JX.bag, _willUpdateWorkflowCallback: JX.bag, _didUpdateWorkflowCallback: JX.bag, setLoadThreadURI: function(uri) { this._loadThreadURI = uri; return this; }, getLoadThreadURI: function() { return this._loadThreadURI; }, isThreadLoaded: function() { return Boolean(this._loadedThreadID); }, isThreadIDLoaded: function(thread_id) { return this._loadedThreadID == thread_id; }, getLoadedThreadID: function() { return this._loadedThreadID; }, setLoadedThreadID: function(id) { this._loadedThreadID = id; return this; }, getLoadedThreadPHID: function() { return this._loadedThreadPHID; }, setLoadedThreadPHID: function(phid) { this._loadedThreadPHID = phid; return this; }, getLatestTransactionID: function() { return this._latestTransactionID; }, setLatestTransactionID: function(id) { this._latestTransactionID = id; return this; }, _updateTransactionIDMap: function(transactions) { var loaded_id = this.getLoadedThreadID(); if (!this._transactionIDMap[loaded_id]) { this._transactionIDMap[this._loadedThreadID] = {}; } var loaded_transaction_ids = this._transactionIDMap[loaded_id]; var transaction; for (var ii = 0; ii < transactions.length; ii++) { transaction = transactions[ii]; loaded_transaction_ids[JX.Stratcom.getData(transaction).id] = 1; } this._transactionIDMap[this._loadedThreadID] = loaded_transaction_ids; return this; }, _updateTransactionCache: function(transactions) { var transaction; for (var ii = 0; ii < transactions.length; ii++) { transaction = transactions[ii]; this._transactionCache[JX.Stratcom.getData(transaction).id] = transaction; } return this; }, _getLoadedTransactions: function() { var loaded_id = this.getLoadedThreadID(); var loaded_tx_ids = JX.keys(this._transactionIDMap[loaded_id]); loaded_tx_ids.sort(function (a, b) { var x = parseFloat(a); var y = parseFloat(b); if (x > y) { return 1; } if (x < y) { return -1; } return 0; }); var transactions = []; for (var ii = 0; ii < loaded_tx_ids.length; ii++) { transactions.push(this._transactionCache[loaded_tx_ids[ii]]); } return transactions; }, _deleteTransactionCaches: function(id) { delete this._transactionCache[id]; delete this._transactionIDMap[this._loadedThreadID][id]; return this; }, setCanEditLoadedThread: function(bool) { this._canEditLoadedThread = bool; return this; }, getCanEditLoadedThread: function() { if (this._canEditLoadedThread === null) { return false; } return this._canEditLoadedThread; }, - setMinimalDisplay: function(bool) { - this._minimalDisplay = bool; - return this; - }, - setMessagesRootCallback: function(callback) { this._messagesRootCallback = callback; return this; }, setWillLoadThreadCallback: function(callback) { this._willLoadThreadCallback = callback; return this; }, setDidLoadThreadCallback: function(callback) { this._didLoadThreadCallback = callback; return this; }, setDidUpdateThreadCallback: function(callback) { this._didUpdateThreadCallback = callback; return this; }, setWillSendMessageCallback: function(callback) { this._willSendMessageCallback = callback; return this; }, setDidSendMessageCallback: function(callback) { this._didSendMessageCallback = callback; return this; }, setWillUpdateWorkflowCallback: function(callback) { this._willUpdateWorkflowCallback = callback; return this; }, setDidUpdateWorkflowCallback: function(callback) { this._didUpdateWorkflowCallback = callback; return this; }, _getParams: function(base_params) { - if (this._minimalDisplay) { - base_params.minimal_display = true; - } if (this._latestTransactionID) { base_params.latest_transaction_id = this._latestTransactionID; } return base_params; }, start: function() { this._transactionIDMap = {}; this._transactionCache = {}; JX.Stratcom.listen( 'aphlict-server-message', null, JX.bind(this, function(e) { var message = e.getData(); if (message.type != 'message') { // Not a message event. return; } if (message.threadPHID != this._loadedThreadPHID) { // Message event for some thread other than the visible one. return; } if (message.messageID <= this._latestTransactionID) { // Message event for something we already know about. return; } // If this notification tells us about a message which is newer than // the newest one we know to exist, update our latest knownID so we // can properly update later. if (this._updating && this._updating.threadPHID == this._loadedThreadPHID) { if (message.messageID > this._updating.knownID) { this._updating.knownID = message.messageID; // We're currently updating, so wait for the update to complete. // this.syncWorkflow has us covered in this case. if (this._updating.active) { return; } } } this._updateThread(); })); JX.Stratcom.listen( 'click', 'show-older-messages', JX.bind(this, function(e) { e.kill(); var data = e.getNodeData('show-older-messages'); var node = e.getNode('show-older-messages'); JX.DOM.setContent(node, 'Loading...'); JX.DOM.alterClass( node, 'conpherence-show-more-messages-loading', true); new JX.Workflow(this._getMoreMessagesURI(), data) .setHandler(JX.bind(this, function(r) { this._deleteTransactionCaches(JX.Stratcom.getData(node).id); JX.DOM.remove(node); this._updateTransactions(r); })).start(); })); JX.Stratcom.listen( 'click', 'show-newer-messages', JX.bind(this, function(e) { e.kill(); var data = e.getNodeData('show-newer-messages'); var node = e.getNode('show-newer-messages'); JX.DOM.setContent(node, 'Loading...'); JX.DOM.alterClass( node, 'conpherence-show-more-messages-loading', true); new JX.Workflow(this._getMoreMessagesURI(), data) .setHandler(JX.bind(this, function(r) { this._deleteTransactionCaches(JX.Stratcom.getData(node).id); JX.DOM.remove(node); this._updateTransactions(r); })).start(); })); }, _shouldUpdateDOM: function(r) { if (this._updating && this._updating.threadPHID == this._loadedThreadPHID) { if (r.non_update) { return false; } // we have a different, more current update in progress so // return early if (r.latest_transaction_id < this._updating.knownID) { return false; } } return true; }, _updateDOM: function(r) { this._updateTransactions(r); this._updating.knownID = r.latest_transaction_id; this._latestTransactionID = r.latest_transaction_id; JX.Stratcom.invoke( 'conpherence-redraw-aphlict', null, r.aphlictDropdownData); }, _updateTransactions: function(r) { var new_transactions = JX.$H(r.transactions).getFragment().childNodes; this._updateTransactionIDMap(new_transactions); this._updateTransactionCache(new_transactions); var transactions = this._getLoadedTransactions(); JX.DOM.setContent(this._messagesRootCallback(), transactions); }, cacheCurrentTransactions: function() { var root = this._messagesRootCallback(); var transactions = JX.DOM.scry( root , 'div', 'conpherence-transaction-view'); this._updateTransactionIDMap(transactions); this._updateTransactionCache(transactions); }, _updateThread: function() { var params = this._getParams({ action: 'load', }); var workflow = new JX.Workflow(this._getUpdateURI()) .setData(params) .setHandler(JX.bind(this, function(r) { if (this._shouldUpdateDOM(r)) { this._updateDOM(r); this._didUpdateThreadCallback(r); } })); this.syncWorkflow(workflow, 'finally'); }, syncWorkflow: function(workflow, stage) { this._updating = { threadPHID: this._loadedThreadPHID, knownID: this._latestTransactionID, active: true }; workflow.listen(stage, JX.bind(this, function() { // TODO - do we need to handle if we switch threads somehow? var need_sync = this._updating && (this._updating.knownID > this._latestTransactionID); if (need_sync) { return this._updateThread(); } this._updating.active = false; })); workflow.start(); }, runUpdateWorkflowFromLink: function(link, params) { params = this._getParams(params); this._willUpdateWorkflowCallback(); var workflow = new JX.Workflow.newFromLink(link) .setData(params) .setHandler(JX.bind(this, function(r) { if (this._shouldUpdateDOM(r)) { this._updateDOM(r); this._didUpdateWorkflowCallback(r); } })); this.syncWorkflow(workflow, params.stage); }, loadThreadByID: function(thread_id, force_reload) { if (this.isThreadLoaded() && this.isThreadIDLoaded(thread_id) && !force_reload) { return; } this._willLoadThreadCallback(); var params = {}; // We pick a thread from the server if not specified if (thread_id) { params.id = thread_id; } params = this._getParams(params); var handler = JX.bind(this, function(r) { var client = JX.Aphlict.getInstance(); if (client) { var old_subs = client.getSubscriptions(); var new_subs = []; for (var ii = 0; ii < old_subs.length; ii++) { if (old_subs[ii] == this._loadedThreadPHID) { continue; } else { new_subs.push(old_subs[ii]); } } new_subs.push(r.threadPHID); client.clearSubscriptions(client.getSubscriptions()); client.setSubscriptions(new_subs); } this._loadedThreadID = r.threadID; this._loadedThreadPHID = r.threadPHID; this._latestTransactionID = r.latestTransactionID; this._canEditLoadedThread = r.canEdit; JX.Stratcom.invoke( 'conpherence-redraw-aphlict', null, r.aphlictDropdownData); this._didLoadThreadCallback(r); this.cacheCurrentTransactions(); if (force_reload) { JX.Stratcom.invoke('hashchange'); } }); // should this be sync'd too? new JX.Workflow(this.getLoadThreadURI()) .setData(params) .setHandler(handler) .start(); }, sendMessage: function(form, params) { var inputs = JX.DOM.scry(form, 'input'); var block_empty = true; for (var i = 0; i < inputs.length; i++) { if (inputs[i].type != 'hidden') { continue; } if (inputs[i].name == 'action' && inputs[i].value == 'join_room') { block_empty = false; continue; } } // don't bother sending up text if there is nothing to submit var textarea = JX.DOM.find(form, 'textarea'); if (block_empty && !textarea.value.length) { return; } params = this._getParams(params); var keep_enabled = true; var workflow = JX.Workflow.newFromForm(form, params, keep_enabled) .setHandler(JX.bind(this, function(r) { if (this._shouldUpdateDOM(r)) { this._updateDOM(r); this._didSendMessageCallback(r); } else if (r.non_update) { this._didSendMessageCallback(r, true); } })); this.syncWorkflow(workflow, 'finally'); this._willSendMessageCallback(); }, handleDraftKeydown: function(e) { var form = e.getNode('tag:form'); var data = e.getNodeData('tag:form'); if (!data.preview) { data.preview = new JX.PhabricatorShapedRequest( this._getUpdateURI(), JX.bag, JX.bind(this, function () { var data = JX.DOM.convertFormToDictionary(form); data.action = 'draft'; data = this._getParams(data); return data; })); } data.preview.trigger(); }, _getUpdateURI: function() { return '/conpherence/update/' + this._loadedThreadID + '/'; }, _getMoreMessagesURI: function() { return '/conpherence/' + this._loadedThreadID + '/'; } }, statics: { _instance: null, getInstance: function() { var self = JX.ConpherenceThreadManager; if (!self._instance) { return null; } return self._instance; } } }); diff --git a/webroot/rsrc/js/application/conpherence/behavior-conpherence-search.js b/webroot/rsrc/js/application/conpherence/behavior-conpherence-search.js new file mode 100644 index 0000000000..39ddd29f65 --- /dev/null +++ b/webroot/rsrc/js/application/conpherence/behavior-conpherence-search.js @@ -0,0 +1,82 @@ +/** + * @provides javelin-behavior-conpherence-search + * @requires javelin-behavior + * javelin-dom + * javelin-util + * javelin-workflow + * javelin-stratcom + */ + +JX.behavior('conpherence-search', function() { + + var shown = true; + var request = null; + + function _toggleSearch(e) { + e.kill(); + var node = JX.$('conpherence-main-layout'); + + shown = !shown; + JX.DOM.alterClass(node, 'show-searchbar', !shown); + if (!shown) { + JX.$('conpherence-search-input').focus(); + } else { + var form_root = JX.DOM.find(document, 'div', 'conpherence-form'); + var textarea = JX.DOM.find(form_root, 'textarea'); + textarea.focus(); + } + JX.Stratcom.invoke('resize'); + } + + function _doSearch(e) { + e.kill(); + var search_text = JX.$('conpherence-search-input').value; + var search_uri = JX.$('conpherence-search-form').action; + var search_node = JX.$('conpherence-search-results'); + + if (request || !search_text) { + return; + } + + request = new JX.Request(search_uri, function(response) { + JX.DOM.setContent(search_node, JX.$H(response)); + request = null; + }); + request.setData({fulltext: search_text}); + request.send(); + } + + function _viewResult(e) { + e.kill(); + var uri = e.getNode('tag:a'); + _toggleSearch(e); + JX.$U(uri).go(); + } + + JX.Stratcom.listen( + ['submit', 'didSyntheticSubmit'], + 'conpherence-search-input', + _doSearch); + + JX.Stratcom.listen( + 'keydown', + 'conpherence-search-input', + function(e) { + if (e.getSpecialKey() != 'return') { + return; + } + e.kill(); + _doSearch(e); + }); + + JX.Stratcom.listen( + 'click', + 'conpherence-search-result-jump', + _viewResult); + + JX.Stratcom.listen( + 'click', + 'conpherence-search-toggle', + _toggleSearch); + +}); diff --git a/webroot/rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js b/webroot/rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js deleted file mode 100644 index 7980bf3871..0000000000 --- a/webroot/rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @provides javelin-behavior-conpherence-drag-and-drop-photo - * @requires javelin-behavior - * javelin-dom - * javelin-workflow - * phabricator-drag-and-drop-file-upload - */ - -JX.behavior('conpherence-drag-and-drop-photo', function(config) { - - var target = JX.$(config.target); - var form_pane = JX.$(config.form_pane); - - function onupload(f) { - var data = { - 'file_id' : f.getID(), - 'action' : 'metadata' - }; - - var form = JX.DOM.find(form_pane, 'form'); - var workflow = JX.Workflow.newFromForm(form, data); - workflow.start(); - } - - if (JX.PhabricatorDragAndDropFileUpload.isSupported()) { - var drop = new JX.PhabricatorDragAndDropFileUpload(target) - .setURI(config.upload_uri); - drop.listen('didBeginDrag', function() { - JX.DOM.alterClass(target, config.activated_class, true); - }); - drop.listen('didEndDrag', function() { - JX.DOM.alterClass(target, config.activated_class, false); - }); - drop.listen('didUpload', onupload); - drop.start(); - } - -}); diff --git a/webroot/rsrc/js/application/conpherence/behavior-durable-column.js b/webroot/rsrc/js/application/conpherence/behavior-durable-column.js index a7fe3fbef7..c6c82bc3be 100644 --- a/webroot/rsrc/js/application/conpherence/behavior-durable-column.js +++ b/webroot/rsrc/js/application/conpherence/behavior-durable-column.js @@ -1,365 +1,364 @@ /** * @provides javelin-behavior-durable-column * @requires javelin-behavior * javelin-dom * javelin-stratcom * javelin-behavior-device * javelin-scrollbar * javelin-quicksand * phabricator-keyboard-shortcut * conpherence-thread-manager */ JX.behavior('durable-column', function(config, statics) { // TODO: Currently, updating the column sends the entire column back. This // includes the `durable-column` behavior itself, which tries to re-initialize // the column. Detect this and bail. // // If ThreadManager gets separated into a UI part and a thread part (which // seems likely), responses may no longer ship back the entire column. This // might let us remove this check. if (statics.initialized) { return; } else { statics.initialized = true; } var userVisible = config.visible; var userMinimize = config.minimize; var show = null; var loadThreadID = null; var scrollbar = null; var margin = JX.Scrollbar.getScrollbarControlMargin(); var quick = JX.$('phabricator-standard-page-body'); function _getColumnNode() { return JX.$('conpherence-durable-column'); } function _getColumnScrollNode() { var column = _getColumnNode(); return JX.DOM.find(column, 'div', 'conpherence-durable-column-main'); } function _updateColumnVisibility() { var new_value = (userVisible); if (new_value !== show) { show = new_value; _drawColumn(show); } } function _toggleColumn() { userVisible = !userVisible; _updateColumnVisibility(); new JX.Request(config.visibleURI) .setData({value: (show ? 1 : 0)}) .send(); } function _minimizeColumn(e) { e.kill(); userMinimize = !userMinimize; JX.DOM.alterClass(document.body, 'minimize-column', userMinimize); JX.Stratcom.invoke('resize'); if (!userMinimize) { var messages = _getColumnMessagesNode(); scrollbar.scrollTo(messages.scrollHeight); } new JX.Request(config.minimizeURI) .setData({value: (userMinimize ? 1 : 0)}) .send(); } function _drawColumn(visible) { JX.DOM.alterClass( document.body, 'with-durable-column', visible); var column = _getColumnNode(); if (visible) { JX.DOM.show(column); threadManager.loadThreadByID(loadThreadID); } else { JX.DOM.hide(column); } JX.Quicksand.setFrame(visible ? quick : null); JX.Stratcom.invoke('resize'); } JX.Stratcom.listen( 'click', 'conpherence-persist-column', _toggleColumn); JX.Stratcom.listen( 'click', 'conpherence-minimize-window', _minimizeColumn); scrollbar = new JX.Scrollbar(_getColumnScrollNode()); JX.Quicksand.setFrame(userVisible ? quick : null); JX.Quicksand.start(config.quicksandConfig); /* Conpherence Thread Manager configuration - lots of display * callbacks. */ var threadManager = new JX.ConpherenceThreadManager(); - threadManager.setMinimalDisplay(true); threadManager.setMessagesRootCallback(function() { return _getColumnMessagesNode(); }); threadManager.setLoadThreadURI('/conpherence/columnview/'); threadManager.setWillLoadThreadCallback(function() { _markLoading(true); }); threadManager.setDidLoadThreadCallback(function(r) { var column = _getColumnNode(); var new_column = JX.$H(r.content); JX.DOM.replace(column, new_column); if (show) { JX.DOM.show(_getColumnNode()); } else { JX.DOM.hide(_getColumnNode()); } var messages = _getColumnMessagesNode(); scrollbar = new JX.Scrollbar(_getColumnScrollNode()); scrollbar.scrollTo(messages.scrollHeight); _markLoading(false); loadThreadID = threadManager.getLoadedThreadID(); }); threadManager.setDidUpdateThreadCallback(function(r) { var messages = _getColumnMessagesNode(); scrollbar.scrollTo(messages.scrollHeight); }); threadManager.setWillSendMessageCallback(function() { // Wipe the textarea immediately so the user can start typing more text. var textarea = _getColumnTextareaNode(); textarea.value = ''; _focusColumnTextareaNode(); }); threadManager.setDidSendMessageCallback(function(r, non_update) { if (non_update) { return; } var messages = _getColumnMessagesNode(); scrollbar.scrollTo(messages.scrollHeight); }); threadManager.setWillUpdateWorkflowCallback(function() { JX.Stratcom.invoke('notification-panel-close'); }); threadManager.setDidUpdateWorkflowCallback(function(r) { var messages = _getColumnMessagesNode(); scrollbar.scrollTo(messages.scrollHeight); JX.DOM.setContent(_getColumnTitleNode(), r.conpherence_title); }); threadManager.start(); JX.Stratcom.listen( 'click', 'conpherence-durable-column-header-action', function (e) { e.kill(); var data = e.getNodeData('conpherence-durable-column-header-action'); var action = data.action; var link = e.getNode('tag:a'); var params = null; switch (action) { case 'metadata': threadManager.runUpdateWorkflowFromLink( link, { action: action, force_ajax: true, stage: 'submit' }); break; case 'add_person': threadManager.runUpdateWorkflowFromLink( link, { action: action, stage: 'submit' }); break; case 'go_conpherence': JX.$U(link.href).go(); break; case 'hide_column': JX.Stratcom.invoke('notification-panel-close'); _toggleColumn(); break; } }); JX.Stratcom.listen( 'click', 'conpherence-durable-column-thread-icon', function (e) { e.kill(); var icons = JX.DOM.scry( JX.$('conpherence-durable-column'), 'a', 'conpherence-durable-column-thread-icon'); var data = e.getNodeData('conpherence-durable-column-thread-icon'); var cdata = null; for (var i = 0; i < icons.length; i++) { cdata = JX.Stratcom.getData(icons[i]); JX.DOM.alterClass( icons[i], 'selected', cdata.threadID == data.threadID); } JX.DOM.setContent(_getColumnTitleNode(), JX.$H(data.threadTitle)); threadManager.loadThreadByID(data.threadID); }); JX.Stratcom.listen('resize', null, _updateColumnVisibility); function _getColumnBodyNode() { var column = JX.$('conpherence-durable-column'); return JX.DOM.find( column, 'div', 'conpherence-durable-column-body'); } function _getColumnMessagesNode() { var column = JX.$('conpherence-durable-column'); return JX.DOM.find( column, 'div', 'conpherence-durable-column-transactions'); } function _getColumnTitleNode() { var column = JX.$('conpherence-durable-column'); return JX.DOM.find( column, 'div', 'conpherence-durable-column-header-text'); } function _getColumnFormNode() { var column = JX.$('conpherence-durable-column'); return JX.DOM.find( column, 'form', 'conpherence-message-form'); } function _getColumnTextareaNode() { var column = JX.$('conpherence-durable-column'); return JX.DOM.find( column, 'textarea', 'conpherence-durable-column-textarea'); } function _focusColumnTextareaNode() { var textarea = _getColumnTextareaNode(); setTimeout(function() { JX.DOM.focus(textarea); }, 1); } function _markLoading(loading) { var column = _getColumnNode(); JX.DOM.alterClass(column, 'loading', loading); } function _sendMessage(e) { e.kill(); var form = _getColumnFormNode(); - threadManager.sendMessage(form, { minimal_display: true }); + threadManager.sendMessage(form, {}); } JX.Stratcom.listen( 'click', 'conpherence-send-message', _sendMessage); JX.Stratcom.listen( ['submit', 'didSyntheticSubmit'], 'conpherence-message-form', _sendMessage); // Send on enter if the shift key is not held. JX.Stratcom.listen( 'keydown', 'conpherence-message-form', function(e) { if (e.getSpecialKey() != 'return') { return; } var raw = e.getRawEvent(); if (raw.shiftKey) { // If the shift key is pressed, let the browser write a newline into // the textarea. return; } // From here on, interpret this as a "send" action, not a literal // newline. e.kill(); _sendMessage(e); }); JX.Stratcom.listen( ['keydown'], 'conpherence-durable-column-textarea', function (e) { threadManager.handleDraftKeydown(e); }); // HTML5 placeholders are rendered as long as the input is empty, even if the // input is currently focused. This is undesirable for the chat input, // especially immediately after sending a message. Hide the placeholder while // the input is focused. JX.Stratcom.listen( ['focus', 'blur'], 'conpherence-durable-column-textarea', function (e) { var node = e.getTarget(); if (e.getType() == 'focus') { if (node.placeholder) { node.placeholderStorage = node.placeholder; node.placeholder = ''; } } else { if (node.placeholderStorage) { node.placeholder = node.placeholderStorage; node.placeholderStorage = ''; } } }); JX.Stratcom.listen( 'quicksand-redraw', null, function (e) { var new_data = e.getData().newResponse; var new_classes = new_data.bodyClasses; if (userMinimize) { new_classes = new_classes + ' minimize-column'; } document.body.className = new_classes; JX.Title.setTitle(new_data.title); }); _updateColumnVisibility(); }); diff --git a/webroot/rsrc/js/application/conpherence/behavior-menu.js b/webroot/rsrc/js/application/conpherence/behavior-menu.js index 50add23158..1621126a5e 100644 --- a/webroot/rsrc/js/application/conpherence/behavior-menu.js +++ b/webroot/rsrc/js/application/conpherence/behavior-menu.js @@ -1,520 +1,449 @@ /** * @provides javelin-behavior-conpherence-menu * @requires javelin-behavior * javelin-dom * javelin-util * javelin-stratcom * javelin-workflow * javelin-behavior-device * javelin-history * javelin-vector * javelin-scrollbar * phabricator-title * phabricator-shaped-request * conpherence-thread-manager */ JX.behavior('conpherence-menu', function(config) { /** * State for displayed thread. */ var _thread = { selected: null, visible: null, node: null }; var scrollbar = null; // TODO - move more logic into the ThreadManager var threadManager = new JX.ConpherenceThreadManager(); threadManager.setMessagesRootCallback(function() { return scrollbar.getContentNode(); }); threadManager.setWillLoadThreadCallback(function() { - markThreadLoading(true); + markThreadsLoading(true); }); threadManager.setDidLoadThreadCallback(function(r) { var header = JX.$H(r.header); + var search = JX.$H(r.search); var messages = JX.$H(r.transactions); var form = JX.$H(r.form); var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var header_root = JX.DOM.find(root, 'div', 'conpherence-header-pane'); + var search_root = JX.DOM.find(root, 'div', 'conpherence-search-main'); var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); JX.DOM.setContent(header_root, header); + JX.DOM.setContent(search_root, search); JX.DOM.setContent(scrollbar.getContentNode(), messages); JX.DOM.setContent(form_root, form); - markThreadLoading(false); + markThreadsLoading(false); didRedrawThread(true); }); threadManager.setDidUpdateThreadCallback(function(r) { _scrollMessageWindow(); }); threadManager.setWillSendMessageCallback(function () { var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); markThreadLoading(true); JX.DOM.alterClass(form_root, 'loading', true); }); threadManager.setDidSendMessageCallback(function (r, non_update) { var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); var textarea = JX.DOM.find(form_root, 'textarea'); if (!non_update) { _scrollMessageWindow(); textarea.value = ''; } markThreadLoading(false); setTimeout(function() { JX.DOM.focus(textarea); }, 100); }); threadManager.start(); /** * Current role of this behavior. The two possible roles are to show a 'list' * of threads or a specific 'thread'. On devices, this behavior stays in the * 'list' role indefinitely, treating clicks normally and the next page * loads the behavior with role = 'thread'. On desktop, this behavior * auto-loads a thread as part of the 'list' role. As the thread loads the * role is changed to 'thread'. */ var _currentRole = null; /** * When _oldDevice is null the code is executing for the first time. */ var _oldDevice = null; /** * Initializes this behavior based on all the configuraton jonx and the * result of JX.Device.getDevice(); */ function init() { _currentRole = config.role; if (_currentRole == 'thread') { markThreadsLoading(true); } else { markThreadLoading(true); } markWidgetLoading(true); onDeviceChange(); var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var messages_root = JX.DOM.find(root, 'div', 'conpherence-message-pane'); var messages = JX.DOM.find(messages_root, 'div', 'conpherence-messages'); scrollbar = new JX.Scrollbar(messages); scrollbar.setAsScrollFrame(); } init(); /** * Selecting threads */ function selectThreadByID(id, update_page_data) { var thread = JX.$(id); selectThread(thread, update_page_data); } function selectThread(node, update_page_data) { if (_thread.node) { JX.DOM.alterClass(_thread.node, 'conpherence-selected', false); } JX.DOM.alterClass(node, 'conpherence-selected', true); JX.DOM.alterClass(node, 'hide-unread-count', true); _thread.node = node; var data = JX.Stratcom.getData(node); _thread.selected = data.threadID; if (update_page_data) { updatePageData(data); } redrawThread(); } function updatePageData(data) { var uri = '/Z' + _thread.selected; JX.History.replace(uri); if (data.title) { JX.Title.setTitle(data.title); } else if (_thread.node) { var threadData = JX.Stratcom.getData(_thread.node); JX.Title.setTitle(threadData.title); } } JX.Stratcom.listen( 'conpherence-update-page-data', null, function (e) { updatePageData(e.getData()); } ); function redrawThread() { if (!_thread.node) { return; } if (_thread.visible == _thread.selected) { return; } var data = JX.Stratcom.getData(_thread.node); if (_thread.visible !== null || !config.hasThread) { threadManager.setLoadThreadURI('/conpherence/' + data.threadID + '/'); threadManager.loadThreadByID(data.threadID); } else if (config.hasThread) { // we loaded the thread via the server so let the thread manager know threadManager.setLoadedThreadID(config.selectedThreadID); threadManager.setLoadedThreadPHID(config.selectedThreadPHID); threadManager.setLatestTransactionID(config.latestTransactionID); threadManager.setCanEditLoadedThread(config.canEditSelectedThread); threadManager.cacheCurrentTransactions(); _scrollMessageWindow(); _focusTextarea(); } else { didRedrawThread(); } if (_thread.visible !== null || !config.hasWidgets) { reloadWidget(data); - } else { - JX.Stratcom.invoke( - 'conpherence-update-widgets', - null, - { - widget : getDefaultWidget(), - buildSelectors : false, - toggleWidget : true, - threadID : _thread.selected - }); } _thread.visible = _thread.selected; } function markThreadsLoading(loading) { - var root = JX.DOM.find(document, 'div', 'conpherence-layout'); - var menu = JX.DOM.find(root, 'div', 'conpherence-menu-pane'); - JX.DOM.alterClass(menu, 'loading', loading); + var root = JX.$('conpherence-main-layout'); + JX.DOM.alterClass(root, 'loading', loading); } function markThreadLoading(loading) { - var root = JX.DOM.find(document, 'div', 'conpherence-layout'); - var header_root = JX.DOM.find(root, 'div', 'conpherence-header-pane'); - var messages_root = JX.DOM.find(root, 'div', 'conpherence-message-pane'); - var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); - - JX.DOM.alterClass(header_root, 'loading', loading); - JX.DOM.alterClass(messages_root, 'loading', loading); - JX.DOM.alterClass(form_root, 'loading', loading); - try { var textarea = JX.DOM.find(form, 'textarea'); textarea.disabled = loading; var button = JX.DOM.find(form, 'button'); button.disabled = loading; } catch (ex) { // haven't loaded it yet! } } function markWidgetLoading(loading) { var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var widgets_root = JX.DOM.find(root, 'div', 'conpherence-participant-pane'); JX.DOM.alterClass(widgets_root, 'loading', loading); } function reloadWidget(data) { markWidgetLoading(true); if (!data.widget) { data.widget = getDefaultWidget(); } var widget_uri = config.baseURI + 'participant/' + data.threadID + '/'; new JX.Workflow(widget_uri, {}) .setHandler(JX.bind(null, onWidgetResponse, data.threadID, data.widget)) .start(); } JX.Stratcom.listen( 'conpherence-reload-widget', null, function (e) { var data = e.getData(); if (data.threadID != _thread.selected) { return; } reloadWidget(data); } ); function onWidgetResponse(thread_id, widget, response) { // we got impatient and this is no longer the right answer :/ if (_thread.selected != thread_id) { return; } var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var widgets_root = JX.DOM.find(root, 'div', 'conpherence-widgets-holder'); JX.DOM.setContent(widgets_root, JX.$H(response.widgets)); - - JX.Stratcom.invoke( - 'conpherence-update-widgets', - null, - { - widget : widget, - buildSelectors : true, - toggleWidget : true, - threadID : _thread.selected - }); - - markWidgetLoading(false); } function getDefaultWidget() { - var device = JX.Device.getDevice(); - var widget = 'conpherence-message-pane'; - if (device == 'desktop') { - widget = 'widgets-people'; - var uri = JX.$U(location.href); - var params = uri.getQueryParams(); - if ('settings' in params) { - widget = 'widgets-settings'; - } - } - return widget; + return 'widgets-people'; } /** * This function is a wee bit tricky. Internally, we want to scroll the * message window and let other stuff - notably widgets - redraw / build if * necessary. Externally, we want a hook to scroll the message window * - notably when the widget selector is used to invoke the message pane. * The following three functions get 'er done. */ function didRedrawThread(build_device_widget_selector) { _scrollMessageWindow(); _focusTextarea(); JX.Stratcom.invoke( 'conpherence-did-redraw-thread', null, { widget : getDefaultWidget(), threadID : _thread.selected, buildDeviceWidgetSelector : build_device_widget_selector }); } var _firstScroll = true; function _scrollMessageWindow() { if (_firstScroll) { _firstScroll = false; // We want to let the standard #anchor tech take over after we make sure // we don't have to present the user with a "load older message?" dialog if (window.location.hash) { var hash = window.location.hash.replace(/^#/, ''); try { JX.$('anchor-' + hash); } catch (ex) { var uri = '/conpherence/' + _thread.selected + '/' + hash + '/'; threadManager.setLoadThreadURI(uri); threadManager.loadThreadByID(_thread.selected, true); _firstScroll = true; return; } return; } } scrollbar.scrollTo(scrollbar.getViewportNode().scrollHeight); } function _focusTextarea() { var root = JX.DOM.find(document, 'div', 'conpherence-layout'); var form_root = JX.DOM.find(root, 'div', 'conpherence-form'); try { var textarea = JX.DOM.find(form_root, 'textarea'); // We may have a draft so do this JS trick so we end up focused at the // end of the draft. var textarea_value = textarea.value; textarea.value = ''; JX.DOM.focus(textarea); textarea.value = textarea_value; } catch (ex) { // no textarea? no problem } } JX.Stratcom.listen( 'conpherence-redraw-thread', null, function () { _scrollMessageWindow(); } ); JX.Stratcom.listen( 'click', 'conpherence-menu-click', function(e) { if (!e.isNormalClick()) { return; } // On devices, just follow the link normally. if (JX.Device.getDevice() != 'desktop') { return; } e.kill(); selectThread(e.getNode('conpherence-menu-click'), true); }); - JX.Stratcom.listen('click', 'conpherence-edit-metadata', function (e) { - e.kill(); - var root = e.getNode('conpherence-layout'); - var form = JX.DOM.find(root, 'form', 'conpherence-pontificate'); - var data = e.getNodeData('conpherence-edit-metadata'); - var header = JX.DOM.find(root, 'div', 'conpherence-header-pane'); - var messages = scrollbar.getContentNode(); - - new JX.Workflow.newFromForm(form, data) - .setHandler(JX.bind(this, function(r) { - JX.DOM.appendContent(messages, JX.$H(r.transactions)); - _scrollMessageWindow(); - - JX.DOM.setContent( - header, - JX.$H(r.header) - ); - - try { - // update the menu entry - JX.DOM.replace( - JX.$(r.conpherence_phid + '-nav-item'), - JX.$H(r.nav_item) - ); - selectThreadByID(r.conpherence_phid + '-nav-item'); - } catch (ex) { - // Ignore; this view may not have a menu. - } - })) - .start(); - }); - /** * On devices, we just show a thread list, so we don't want to automatically * select or load any threads. On desktop, we automatically select the first * thread, changing the _currentRole from list to thread. */ function onDeviceChange() { var new_device = JX.Device.getDevice(); if (new_device === _oldDevice) { return; } if (_oldDevice === null) { _oldDevice = new_device; if (_currentRole == 'list') { if (new_device != 'desktop') { return; } } else { loadThreads(); return; } } var update_toggled_widget = new_device == 'desktop' || _oldDevice == 'desktop'; _oldDevice = new_device; if (_thread.visible !== null && update_toggled_widget) { JX.Stratcom.invoke( 'conpherence-did-redraw-thread', null, { widget : getDefaultWidget(), threadID : _thread.selected }); } if (_currentRole == 'list' && new_device == 'desktop') { // this selects a thread and loads it didLoadThreads(); _currentRole = 'thread'; var root = JX.DOM.find(document, 'div', 'conpherence-layout'); JX.DOM.alterClass(root, 'conpherence-role-list', false); JX.DOM.alterClass(root, 'conpherence-role-thread', true); } } JX.Stratcom.listen('phabricator-device-change', null, onDeviceChange); function loadThreads() { markThreadsLoading(true); var uri = config.baseURI + 'thread/' + config.selectedThreadID + '/'; new JX.Workflow(uri) .setHandler(onLoadThreadsResponse) .start(); } function onLoadThreadsResponse(r) { var layout = JX.$(config.layoutID); var menu = JX.DOM.find(layout, 'div', 'conpherence-menu-pane'); JX.DOM.setContent(menu, JX.$H(r)); config.selectedID && selectThreadByID(config.selectedID); markThreadsLoading(false); } function didLoadThreads() { // If there's no thread selected yet, select the current thread or the // first thread. if (!_thread.selected) { if (config.selectedID) { selectThreadByID(config.selectedID, true); } else { var layout = JX.$(config.layoutID); var threads = JX.DOM.scry(layout, 'a', 'conpherence-menu-click'); if (threads.length) { selectThread(threads[0]); } else { var nothreads = JX.DOM.find(layout, 'div', 'conpherence-no-threads'); nothreads.style.display = 'block'; markThreadLoading(false); markWidgetLoading(false); } } } } JX.Stratcom.listen( ['click'], 'conpherence-menu-see-more', function (e) { e.kill(); var sigil = e.getNodeData('conpherence-menu-see-more').moreSigil; var root = JX.$('conpherence-menu-pane'); var more = JX.DOM.scry(root, 'li', sigil); for (var i = 0; i < more.length; i++) { JX.DOM.alterClass(more[i], 'hidden', false); } JX.DOM.hide(e.getNode('conpherence-menu-see-more')); }); JX.Stratcom.listen( ['keydown'], 'conpherence-pontificate', function (e) { threadManager.handleDraftKeydown(e); }); }); diff --git a/webroot/rsrc/js/application/conpherence/behavior-toggle-widget.js b/webroot/rsrc/js/application/conpherence/behavior-toggle-widget.js index 1b36f8ff79..0022273c0e 100644 --- a/webroot/rsrc/js/application/conpherence/behavior-toggle-widget.js +++ b/webroot/rsrc/js/application/conpherence/behavior-toggle-widget.js @@ -1,29 +1,45 @@ /** * @provides javelin-behavior-toggle-widget * @requires javelin-behavior * javelin-dom * javelin-util * javelin-workflow * javelin-stratcom */ JX.behavior('toggle-widget', function(config) { + var device; + + function init() { + device = JX.Device.getDevice(); + if (device != 'phone') { + var node = JX.$('conpherence-main-layout'); + JX.DOM.alterClass(node, 'hide-widgets', !config.show); + JX.Stratcom.invoke('resize'); + } else { + config.show = 0; + } + } + init(); + function _toggleColumn(e) { e.kill(); var node = JX.$('conpherence-main-layout'); config.show = !config.show; JX.DOM.alterClass(node, 'hide-widgets', !config.show); JX.Stratcom.invoke('resize'); - new JX.Request(config.settingsURI) - .setData({value: (config.show ? 1 : 0)}) - .send(); + if (device != 'phone') { + new JX.Request(config.settingsURI) + .setData({value: (config.show ? 1 : 0)}) + .send(); + } } JX.Stratcom.listen( 'click', 'conpherence-widget-toggle', _toggleColumn); }); diff --git a/webroot/rsrc/js/core/Favicon.js b/webroot/rsrc/js/core/Favicon.js new file mode 100644 index 0000000000..fb494dfbbd --- /dev/null +++ b/webroot/rsrc/js/core/Favicon.js @@ -0,0 +1,35 @@ +/** + * @provides phabricator-favicon + * @requires javelin-install + * javelin-dom + */ +JX.install('Favicon', { + statics: { + _favicon: null, + + setFavicon: function(favicon) { + var self = JX.Favicon; + self._favicon = favicon; + self._update(); + }, + + _update: function() { + var self = JX.Favicon; + var cur_favicon = JX.$('favicon'); + + if (self._favicon === null) { + self._favicon = cur_favicon.href; + } + + var new_favicon = JX.$N( + 'link', + {href: self._favicon, + id: 'favicon', + rel: 'shortcut icon', + }); + + JX.DOM.replace(cur_favicon, new_favicon); + + } + } +}); diff --git a/webroot/rsrc/js/core/Title.js b/webroot/rsrc/js/core/Title.js index 08ca5e2f25..f99f948e39 100644 --- a/webroot/rsrc/js/core/Title.js +++ b/webroot/rsrc/js/core/Title.js @@ -1,49 +1,49 @@ /** - * @requires javelin-install * @provides phabricator-title - * @javelin + * @requires javelin-install */ /** * Update the document title to show a notification/message count. */ JX.install('Title', { statics: { _counts: {}, _title: null, setCount: function(k, v) { var self = JX.Title; self._counts[k] = v; self._update(); }, setTitle: function(title) { var self = JX.Title; self._title = title; self._update(); }, _update: function() { var self = JX.Title; if (self._title === null) { self._title = document.title; } var sum = 0; for (var k in self._counts) { sum += parseInt(self._counts[k], 10) || 0; } var title; if (sum) { title = '(' + sum + ') ' + self._title; } else { title = self._title; } document.title = title; + } } }); diff --git a/webroot/rsrc/js/core/behavior-global-drag-and-drop.js b/webroot/rsrc/js/core/behavior-global-drag-and-drop.js index a291772b6e..08b0fd1226 100644 --- a/webroot/rsrc/js/core/behavior-global-drag-and-drop.js +++ b/webroot/rsrc/js/core/behavior-global-drag-and-drop.js @@ -1,107 +1,119 @@ /** * @provides javelin-behavior-global-drag-and-drop * @requires javelin-behavior * javelin-dom * javelin-uri * javelin-mask * phabricator-drag-and-drop-file-upload */ JX.behavior('global-drag-and-drop', function(config, statics) { if (!JX.PhabricatorDragAndDropFileUpload.isSupported()) { return; } function init() { statics.pending = 0; statics.files = []; statics.errors = false; statics.enabled = true; if (config.ifSupported) { JX.$(config.ifSupported).style.display = ''; } var page = JX.$('phabricator-standard-page'); statics.drop = new JX.PhabricatorDragAndDropFileUpload(page) .setURI(config.uploadURI) .setViewPolicy(config.viewPolicy) .setChunkThreshold(config.chunkThreshold); install_extra_listeners(); statics.drop.start(); return true; } function install_extra_listeners() { statics.drop.listen('didBeginDrag', function() { if (!statics.enabled) { return; } JX.Mask.show('global-upload-mask'); JX.DOM.show(JX.$(config.instructions)); }); statics.drop.listen('didEndDrag', function() { if (!statics.enabled) { return; } JX.Mask.hide('global-upload-mask'); JX.DOM.hide(JX.$(config.instructions)); }); statics.drop.listen('willUpload', function() { if (!statics.enabled) { return; } statics.pending++; }); statics.drop.listen('didUpload', function(f) { if (!statics.enabled) { return; } statics.files.push(f); statics.pending--; if (statics.pending === 0 && !statics.errors) { // If whatever the user dropped in has finished uploading, send them to // their uploads. var uri; - uri = JX.$U(config.browseURI); + var is_submit = !!config.submitURI; + + if (is_submit) { + uri = JX.$U(config.submitURI); + } else { + uri = JX.$U(config.browseURI); + } + var ids = []; for (var ii = 0; ii < statics.files.length; ii++) { ids.push(statics.files[ii].getID()); } uri.setQueryParam('h', ids.join(',')); statics.files = []; - uri.go(); + if (is_submit) { + new JX.Workflow(uri) + .start(); + } else { + uri.go(); + } } }); statics.drop.listen('didError', function() { if (!statics.enabled) { return; } statics.pending--; statics.errors = true; }); JX.Stratcom.listen( 'quicksand-redraw', null, function (e) { var data = e.getData(); var toggle = data.newResponse.globalDragAndDrop; statics.enabled = toggle; statics.drop.setIsEnabled(toggle); }); } statics.init = statics.init || init(); });