Page MenuHomestyx hydra

No OneTemporary

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
index fed195555c..05d7f3d8d9 100644
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -1,2238 +1,2238 @@
<?php
/**
* This file is automatically generated. Use 'bin/celerity map' to rebuild it.
*
* @generated
*/
return array(
'names' => array(
'core.pkg.css' => 'd7ecac6d',
'core.pkg.js' => '3bbe23c6',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '02273347',
'differential.pkg.js' => 'ebef29b1',
'diffusion.pkg.css' => '591664fa',
'diffusion.pkg.js' => '0115b37c',
'maniphest.pkg.css' => '68d4dd3d',
'maniphest.pkg.js' => '2f4f52c2',
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
'rsrc/css/aphront/dark-console.css' => '6378ef3d',
'rsrc/css/aphront/dialog-view.css' => '9b32db0a',
'rsrc/css/aphront/lightbox-attachment.css' => '7acac05d',
'rsrc/css/aphront/list-filter-view.css' => 'b2161041',
'rsrc/css/aphront/multi-column.css' => 'fd18389d',
'rsrc/css/aphront/notification.css' => '9c279160',
'rsrc/css/aphront/pager-view.css' => '2e3539af',
'rsrc/css/aphront/panel-view.css' => '8427b78d',
'rsrc/css/aphront/phabricator-nav-view.css' => '7aeaf435',
'rsrc/css/aphront/table-view.css' => '0b4cd283',
'rsrc/css/aphront/tokenizer.css' => '86a13f7f',
'rsrc/css/aphront/tooltip.css' => '7672b60f',
'rsrc/css/aphront/two-column.css' => '16ab3ad2',
'rsrc/css/aphront/typeahead-browse.css' => 'd8581d2c',
'rsrc/css/aphront/typeahead.css' => '0e403212',
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
'rsrc/css/application/auth/auth.css' => '44975d4b',
'rsrc/css/application/base/main-menu-view.css' => '663e3810',
'rsrc/css/application/base/notification-menu.css' => '3c9d8aa1',
'rsrc/css/application/base/phabricator-application-launch-view.css' => '16ca323f',
'rsrc/css/application/base/standard-page-view.css' => '61e68a55',
'rsrc/css/application/calendar/calendar-icon.css' => '98ce946d',
'rsrc/css/application/chatlog/chatlog.css' => '852140ff',
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
'rsrc/css/application/config/config-options.css' => '7fedf08b',
'rsrc/css/application/config/config-template.css' => '8e6c6fcd',
'rsrc/css/application/config/config-welcome.css' => '6abd79be',
'rsrc/css/application/config/setup-issue.css' => '22270af2',
'rsrc/css/application/config/unhandled-exception.css' => '37d4f9a2',
'rsrc/css/application/conpherence/durable-column.css' => '4331cbe9',
'rsrc/css/application/conpherence/menu.css' => 'f389e048',
'rsrc/css/application/conpherence/message-pane.css' => '5bb4b76d',
'rsrc/css/application/conpherence/notification.css' => '919974b6',
'rsrc/css/application/conpherence/transaction.css' => '42a457f6',
'rsrc/css/application/conpherence/update.css' => '1099a660',
'rsrc/css/application/conpherence/widget-pane.css' => '2af42ebe',
'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4',
'rsrc/css/application/countdown/timer.css' => '86b7b0a0',
'rsrc/css/application/dashboard/dashboard.css' => '17937d22',
'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a',
'rsrc/css/application/differential/add-comment.css' => 'c47f8c40',
'rsrc/css/application/differential/changeset-view.css' => 'e19cfd6e',
'rsrc/css/application/differential/core.css' => '7ac3cabc',
'rsrc/css/application/differential/phui-inline-comment.css' => 'aa16f165',
'rsrc/css/application/differential/results-table.css' => '181aa9d9',
'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' => '63f3ef4a',
'rsrc/css/application/diffusion/diffusion-icons.css' => '9c5828da',
'rsrc/css/application/diffusion/diffusion-readme.css' => '2106ea08',
'rsrc/css/application/diffusion/diffusion-source.css' => '66fdf661',
'rsrc/css/application/feed/feed.css' => 'b513b5f4',
'rsrc/css/application/files/global-drag-and-drop.css' => '697324ad',
'rsrc/css/application/flag/flag.css' => '5337623f',
'rsrc/css/application/harbormaster/harbormaster.css' => '49d64eb4',
'rsrc/css/application/herald/herald-test.css' => '778b008e',
'rsrc/css/application/herald/herald.css' => '826075fa',
'rsrc/css/application/home/home.css' => 'e34bf140',
'rsrc/css/application/maniphest/batch-editor.css' => '8f380ebc',
'rsrc/css/application/maniphest/report.css' => 'f6931fdf',
'rsrc/css/application/maniphest/task-edit.css' => '8e23031b',
'rsrc/css/application/maniphest/task-summary.css' => 'ab2fc691',
'rsrc/css/application/objectselector/object-selector.css' => '029a133d',
'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b',
'rsrc/css/application/paste/paste.css' => 'eb997ddd',
'rsrc/css/application/people/people-profile.css' => '25970776',
'rsrc/css/application/phame/phame.css' => '88bd4705',
'rsrc/css/application/pholio/pholio-edit.css' => '3ad9d1ee',
'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49',
'rsrc/css/application/pholio/pholio.css' => '95174bdd',
'rsrc/css/application/phortune/phortune-credit-card-form.css' => '8391eb02',
'rsrc/css/application/phortune/phortune.css' => '9149f103',
'rsrc/css/application/phrequent/phrequent.css' => 'ffc185ad',
'rsrc/css/application/phriction/phriction-document-css.css' => '0d16bc9a',
'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/comments.css' => '6cdccea7',
'rsrc/css/application/ponder/feed.css' => 'e62615b6',
'rsrc/css/application/ponder/post.css' => '9d415218',
'rsrc/css/application/ponder/vote.css' => '8ed6ed8b',
'rsrc/css/application/profile/profile-view.css' => '1a20dcbf',
'rsrc/css/application/projects/project-icon.css' => 'c2ecb7f1',
'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/search-results.css' => '15c71110',
'rsrc/css/application/slowvote/slowvote.css' => '266df6a1',
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
'rsrc/css/core/core.css' => 'aaea7a7a',
'rsrc/css/core/remarkup.css' => '07b7dc54',
'rsrc/css/core/syntax.css' => '9fd11da8',
'rsrc/css/core/z-index.css' => 'c4732d32',
'rsrc/css/diviner/diviner-shared.css' => '38813222',
'rsrc/css/font/font-awesome.css' => 'e2e712fe',
'rsrc/css/font/font-source-sans-pro.css' => '8906c07b',
'rsrc/css/font/phui-font-icon-base.css' => '3dad2ae3',
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
'rsrc/css/layout/phabricator-hovercard-view.css' => 'dd9121a9',
'rsrc/css/layout/phabricator-side-menu-view.css' => 'c1db9e9c',
'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894',
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'd1cf6f93',
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338',
'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0',
'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893',
'rsrc/css/phui/phui-action-header-view.css' => '89c497e7',
'rsrc/css/phui/phui-action-list.css' => '4f4d09f2',
'rsrc/css/phui/phui-action-panel.css' => '3ee9afd5',
'rsrc/css/phui/phui-box.css' => '7b3a2eed',
'rsrc/css/phui/phui-button.css' => 'de610129',
'rsrc/css/phui/phui-crumbs-view.css' => '594d719e',
'rsrc/css/phui/phui-document.css' => '94d5dcd8',
'rsrc/css/phui/phui-feed-story.css' => 'c9f3a0b5',
'rsrc/css/phui/phui-fontkit.css' => 'dd8ddf27',
'rsrc/css/phui/phui-form-view.css' => '808329f2',
'rsrc/css/phui/phui-form.css' => '25876baf',
'rsrc/css/phui/phui-header-view.css' => '2dd74fe0',
'rsrc/css/phui/phui-icon.css' => 'bc766998',
'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8',
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
'rsrc/css/phui/phui-info-view.css' => 'c6f0aef8',
'rsrc/css/phui/phui-list.css' => '2e25ebfb',
'rsrc/css/phui/phui-object-box.css' => '7d160002',
'rsrc/css/phui/phui-object-item-list-view.css' => 'f3a22696',
'rsrc/css/phui/phui-pinboard-view.css' => 'eaab2b1b',
'rsrc/css/phui/phui-property-list-view.css' => '5b671934',
'rsrc/css/phui/phui-remarkup-preview.css' => '19ad512b',
'rsrc/css/phui/phui-spacing.css' => '042804d6',
'rsrc/css/phui/phui-status.css' => '888cedb8',
'rsrc/css/phui/phui-tag-view.css' => '402691cc',
'rsrc/css/phui/phui-text.css' => 'cf019f54',
'rsrc/css/phui/phui-timeline-view.css' => 'a85542c8',
'rsrc/css/phui/phui-workboard-view.css' => '5c4c53e9',
'rsrc/css/phui/phui-workpanel-view.css' => 'e495a5cc',
'rsrc/css/sprite-gradient.css' => '4bdb98a7',
'rsrc/css/sprite-login.css' => 'a3526809',
'rsrc/css/sprite-main-header.css' => '28d01b0b',
'rsrc/css/sprite-menu.css' => '9ef76324',
'rsrc/css/sprite-projects.css' => 'b0d9e24f',
'rsrc/css/sprite-tokens.css' => '1706b943',
'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '5fb6fb0e',
'rsrc/externals/font/fontawesome/fontawesome-webfont.ttf' => 'a653cb11',
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => '80526fc8',
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff2' => '4924d54d',
'rsrc/externals/font/sourcesans/SourceSansPro-It.woff' => '3f21af52',
'rsrc/externals/font/sourcesans/SourceSansPro-It.woff2' => '30a7cf60',
'rsrc/externals/font/sourcesans/SourceSansPro-Regular.woff2' => 'e89b04b1',
'rsrc/externals/font/sourcesans/SourceSansPro-Semibold.woff' => '67cce9ea',
'rsrc/externals/font/sourcesans/SourceSansPro-Semibold.woff2' => 'ec2ed916',
'rsrc/externals/font/sourcesans/SourceSansPro-SemiboldIt.woff' => 'bd1ce81d',
'rsrc/externals/font/sourcesans/SourceSansPro-SemiboldIt.woff2' => 'd9928416',
'rsrc/externals/font/sourcesans/SourceSansPro.woff' => '3614608c',
'rsrc/externals/javelin/core/Event.js' => '85ea0626',
'rsrc/externals/javelin/core/Stratcom.js' => '6c53634d',
'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' => '147805fa',
'rsrc/externals/javelin/lib/History.js' => 'd4505101',
'rsrc/externals/javelin/lib/JSON.js' => '69adf288',
'rsrc/externals/javelin/lib/Leader.js' => '331b1611',
'rsrc/externals/javelin/lib/Mask.js' => '8a41885b',
'rsrc/externals/javelin/lib/Quicksand.js' => '4cebc641',
'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' => '6eff08aa',
'rsrc/externals/javelin/lib/Vector.js' => '2caa8fb8',
'rsrc/externals/javelin/lib/WebSocket.js' => 'e292eaf4',
'rsrc/externals/javelin/lib/Workflow.js' => '5b2e3e2b',
'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' => 'ab5f468d',
'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' => '8b3fd187',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '2818f5ce',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa',
'rsrc/externals/raphael/g.raphael.js' => '40dde778',
'rsrc/externals/raphael/g.raphael.line.js' => '40da039e',
'rsrc/externals/raphael/raphael.js' => '51ee6b43',
'rsrc/favicons/apple-touch-icon-120x120.png' => '43742962',
'rsrc/favicons/apple-touch-icon-152x152.png' => '669eaec3',
'rsrc/favicons/apple-touch-icon-76x76.png' => 'ecdef672',
'rsrc/favicons/favicon-128.png' => '47cdff03',
'rsrc/favicons/favicon-16x16.png' => 'ee2523ac',
'rsrc/favicons/favicon-32x32.png' => 'b6a8150e',
'rsrc/favicons/favicon-96x96.png' => '8f7ea177',
'rsrc/image/BFCFDA.png' => 'd5ec91f4',
'rsrc/image/actions/edit.png' => '2fc41442',
'rsrc/image/avatar.png' => '3eb28cd9',
'rsrc/image/checker_dark.png' => 'd8e65881',
'rsrc/image/checker_light.png' => 'a0155918',
'rsrc/image/checker_lighter.png' => 'd5da91b6',
'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/folder.png' => '95a435af',
'rsrc/image/icon/fatcow/folder_go.png' => '001cbc94',
'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_link.png' => 'a90023c7',
'rsrc/image/icon/fatcow/page_white_put.png' => '08c95a0c',
'rsrc/image/icon/fatcow/page_white_text.png' => '1e1f79c3',
'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/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/washington.png' => '40dd301c',
'rsrc/image/phrequent_active.png' => 'a466a8ed',
'rsrc/image/phrequent_inactive.png' => 'bfc15a69',
'rsrc/image/sprite-gradient.png' => 'ec15a417',
'rsrc/image/sprite-login-X2.png' => 'a15918f0',
'rsrc/image/sprite-login.png' => '8cee4f6e',
'rsrc/image/sprite-main-header.png' => '39419fa6',
'rsrc/image/sprite-menu-X2.png' => '1c90d7bc',
'rsrc/image/sprite-menu.png' => '619781ee',
'rsrc/image/sprite-projects-X2.png' => '8c91c839',
'rsrc/image/sprite-projects.png' => 'ef9dc9b5',
'rsrc/image/sprite-tokens-X2.png' => 'b4776580',
'rsrc/image/sprite-tokens.png' => '25b75533',
'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' => '995ad707',
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'b1a59974',
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761',
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
'rsrc/js/application/calendar/behavior-day-view.js' => '5c46cff2',
'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8',
- 'rsrc/js/application/calendar/behavior-recurring-edit.js' => '9c751e15',
+ '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' => '16c695bf',
'rsrc/js/application/conpherence/behavior-menu.js' => '43b24a10',
'rsrc/js/application/conpherence/behavior-pontificate.js' => '21ba5861',
'rsrc/js/application/conpherence/behavior-quicksand-blacklist.js' => '7927a7d3',
'rsrc/js/application/conpherence/behavior-widget-pane.js' => '93568464',
'rsrc/js/application/countdown/timer.js' => 'e4cc26b3',
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e',
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '82439934',
'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' => '58562350',
'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => 'd4c87bf4',
'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' => '2035b9cb',
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '037b59eb',
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
'rsrc/js/application/differential/behavior-populate.js' => '8694b1df',
'rsrc/js/application/differential/behavior-show-field-details.js' => 'bba9eedf',
'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' => '9007c197',
'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' => '2b228192',
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781',
'rsrc/js/application/files/behavior-icon-composer.js' => '8ef9ab58',
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
'rsrc/js/application/herald/HeraldRuleEditor.js' => '271ffdd7',
'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec',
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
'rsrc/js/application/maniphest/behavior-batch-editor.js' => 'f5d1233b',
'rsrc/js/application/maniphest/behavior-batch-selector.js' => '7b98d7c5',
'rsrc/js/application/maniphest/behavior-line-chart.js' => '88f0c5b3',
'rsrc/js/application/maniphest/behavior-list-edit.js' => 'a9f88de2',
'rsrc/js/application/maniphest/behavior-subpriorityeditor.js' => '84845b5b',
'rsrc/js/application/maniphest/behavior-transaction-controls.js' => '44168bad',
'rsrc/js/application/maniphest/behavior-transaction-expand.js' => '5fefb143',
'rsrc/js/application/maniphest/behavior-transaction-preview.js' => '4c95d29e',
'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/phame/phame-post-preview.js' => 'be807912',
'rsrc/js/application/pholio/behavior-pholio-mock-edit.js' => '246dc085',
'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' => '9a340b3d',
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c',
'rsrc/js/application/ponder/behavior-votebox.js' => '4e9b766b',
'rsrc/js/application/projects/behavior-project-boards.js' => 'ba4fa35c',
'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' => 'bea81850',
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'dbbf48b6',
'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' => '07de8873',
'rsrc/js/core/DraggableList.js' => 'a16ec1c6',
'rsrc/js/core/FileUpload.js' => '477359c8',
'rsrc/js/core/Hovercard.js' => '14ac66f5',
'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2',
'rsrc/js/core/KeyboardShortcutManager.js' => 'c1700f6f',
'rsrc/js/core/MultirowRowManager.js' => 'b5d57730',
'rsrc/js/core/Notification.js' => '0c6946e7',
'rsrc/js/core/Prefab.js' => '6920d200',
'rsrc/js/core/ShapedRequest.js' => '7cbe244b',
'rsrc/js/core/TextAreaUtils.js' => '5c93c52c',
'rsrc/js/core/Title.js' => 'df5e11d2',
'rsrc/js/core/ToolTip.js' => '1d298e3a',
'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-choose-control.js' => '6153c708',
'rsrc/js/core/behavior-crop.js' => 'fa0f4fc2',
'rsrc/js/core/behavior-dark-console.js' => 'f411b6ae',
'rsrc/js/core/behavior-device.js' => 'a205cf28',
'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '6d49590e',
'rsrc/js/core/behavior-error-log.js' => '6882e80a',
'rsrc/js/core/behavior-fancy-datepicker.js' => '510b5809',
'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-high-security-warning.js' => 'a464fe03',
'rsrc/js/core/behavior-history-install.js' => '7ee2b591',
'rsrc/js/core/behavior-hovercard.js' => 'f36e01af',
'rsrc/js/core/behavior-keyboard-pager.js' => 'a8da01f0',
'rsrc/js/core/behavior-keyboard-shortcuts.js' => 'd75709e6',
'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' => '49b73b36',
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
'rsrc/js/core/behavior-phabricator-nav.js' => '14d7a8b8',
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '095ed313',
'rsrc/js/core/behavior-refresh-csrf.js' => '7814b593',
'rsrc/js/core/behavior-remarkup-preview.js' => 'f7379f45',
'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' => '048330fa',
'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6',
'rsrc/js/core/behavior-time-typeahead.js' => '8bfbb401',
'rsrc/js/core/behavior-toggle-class.js' => '5d7c9f33',
'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884',
'rsrc/js/core/behavior-tooltip.js' => '3ee3408b',
'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' => '54733475',
'rsrc/js/phui/behavior-phui-object-box-tabs.js' => '2bfa2836',
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
),
'symbols' => array(
'almanac-css' => 'dbb9b3af',
'aphront-bars' => '231ac33c',
'aphront-dark-console-css' => '6378ef3d',
'aphront-dialog-view-css' => '9b32db0a',
'aphront-list-filter-view-css' => 'b2161041',
'aphront-multi-column-view-css' => 'fd18389d',
'aphront-pager-view-css' => '2e3539af',
'aphront-panel-view-css' => '8427b78d',
'aphront-table-view-css' => '0b4cd283',
'aphront-tokenizer-control-css' => '86a13f7f',
'aphront-tooltip-css' => '7672b60f',
'aphront-two-column-view-css' => '16ab3ad2',
'aphront-typeahead-control-css' => '0e403212',
'auth-css' => '44975d4b',
'calendar-icon-css' => '98ce946d',
'changeset-view-manager' => '58562350',
'conduit-api-css' => '7bc725c4',
'config-options-css' => '7fedf08b',
'config-welcome-css' => '6abd79be',
'conpherence-durable-column-view' => '4331cbe9',
'conpherence-menu-css' => 'f389e048',
'conpherence-message-pane-css' => '5bb4b76d',
'conpherence-notification-css' => '919974b6',
'conpherence-thread-manager' => '01774ab2',
'conpherence-transaction-css' => '42a457f6',
'conpherence-update-css' => '1099a660',
'conpherence-widget-pane-css' => '2af42ebe',
'differential-changeset-view-css' => 'e19cfd6e',
'differential-core-view-css' => '7ac3cabc',
'differential-inline-comment-editor' => 'd4c87bf4',
'differential-results-table-css' => '181aa9d9',
'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' => '63f3ef4a',
'diffusion-icons-css' => '9c5828da',
'diffusion-readme-css' => '2106ea08',
'diffusion-source-css' => '66fdf661',
'diviner-shared-css' => '38813222',
'font-fontawesome' => 'e2e712fe',
'font-source-sans-pro' => '8906c07b',
'global-drag-and-drop-css' => '697324ad',
'harbormaster-css' => '49d64eb4',
'herald-css' => '826075fa',
'herald-rule-editor' => '271ffdd7',
'herald-test-css' => '778b008e',
'homepage-panel-css' => 'e34bf140',
'inline-comment-summary-css' => '51efda3a',
'javelin-aphlict' => '5359e785',
'javelin-behavior' => '61cbc29a',
'javelin-behavior-aphlict-dropdown' => '995ad707',
'javelin-behavior-aphlict-listen' => 'b1a59974',
'javelin-behavior-aphlict-status' => 'ea681761',
'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884',
'javelin-behavior-aphront-crop' => 'fa0f4fc2',
'javelin-behavior-aphront-drag-and-drop-textarea' => '6d49590e',
'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-choose-control' => '6153c708',
'javelin-behavior-config-reorder-fields' => 'b6993408',
'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a',
'javelin-behavior-conpherence-menu' => '43b24a10',
'javelin-behavior-conpherence-pontificate' => '21ba5861',
'javelin-behavior-conpherence-widget-pane' => '93568464',
'javelin-behavior-countdown-timer' => 'e4cc26b3',
'javelin-behavior-dark-console' => 'f411b6ae',
'javelin-behavior-dashboard-async-panel' => '469c0d9e',
'javelin-behavior-dashboard-move-panels' => '82439934',
'javelin-behavior-dashboard-query-panel-select' => '453c5375',
'javelin-behavior-dashboard-tab-panel' => 'd4eecc63',
'javelin-behavior-day-view' => '5c46cff2',
'javelin-behavior-device' => 'a205cf28',
'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' => '2035b9cb',
'javelin-behavior-differential-edit-inline-comments' => '037b59eb',
'javelin-behavior-differential-feedback-preview' => 'b064af76',
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
'javelin-behavior-differential-populate' => '8694b1df',
'javelin-behavior-differential-show-field-details' => 'bba9eedf',
'javelin-behavior-differential-toggle-files' => 'ca3f91eb',
'javelin-behavior-differential-user-select' => 'a8d8459d',
'javelin-behavior-diffusion-commit-branches' => 'bdaf4d04',
'javelin-behavior-diffusion-commit-graph' => '9007c197',
'javelin-behavior-diffusion-jump-to' => '73d09eef',
'javelin-behavior-diffusion-locate-file' => '6d3e1947',
'javelin-behavior-diffusion-pull-lastmodified' => '2b228192',
'javelin-behavior-doorkeeper-tag' => 'e5822781',
'javelin-behavior-durable-column' => '16c695bf',
'javelin-behavior-error-log' => '6882e80a',
'javelin-behavior-event-all-day' => '38dcf3c8',
'javelin-behavior-fancy-datepicker' => '510b5809',
'javelin-behavior-global-drag-and-drop' => 'c8e57404',
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
'javelin-behavior-high-security-warning' => 'a464fe03',
'javelin-behavior-history-install' => '7ee2b591',
'javelin-behavior-icon-composer' => '8ef9ab58',
'javelin-behavior-launch-icon-composer' => '48086888',
'javelin-behavior-lightbox-attachments' => 'f8ba29d7',
'javelin-behavior-line-chart' => '88f0c5b3',
'javelin-behavior-load-blame' => '42126667',
'javelin-behavior-maniphest-batch-editor' => 'f5d1233b',
'javelin-behavior-maniphest-batch-selector' => '7b98d7c5',
'javelin-behavior-maniphest-list-editor' => 'a9f88de2',
'javelin-behavior-maniphest-subpriority-editor' => '84845b5b',
'javelin-behavior-maniphest-transaction-controls' => '44168bad',
'javelin-behavior-maniphest-transaction-expand' => '5fefb143',
'javelin-behavior-maniphest-transaction-preview' => '4c95d29e',
'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-hovercards' => 'f36e01af',
'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0',
'javelin-behavior-phabricator-keyboard-shortcuts' => 'd75709e6',
'javelin-behavior-phabricator-line-linker' => '1499a8cb',
'javelin-behavior-phabricator-nav' => '14d7a8b8',
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
'javelin-behavior-phabricator-object-selector' => '49b73b36',
'javelin-behavior-phabricator-oncopy' => '2926fff2',
'javelin-behavior-phabricator-remarkup-assist' => '095ed313',
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
'javelin-behavior-phabricator-search-typeahead' => '048330fa',
'javelin-behavior-phabricator-show-older-transactions' => 'dbbf48b6',
'javelin-behavior-phabricator-tooltips' => '3ee3408b',
'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6',
'javelin-behavior-phabricator-transaction-list' => '13c739ea',
'javelin-behavior-phabricator-watch-anchor' => '9f36c42d',
'javelin-behavior-phame-post-preview' => 'be807912',
'javelin-behavior-pholio-mock-edit' => '246dc085',
'javelin-behavior-pholio-mock-view' => 'fbe497e7',
'javelin-behavior-phui-dropdown-menu' => '54733475',
'javelin-behavior-phui-object-box-tabs' => '2bfa2836',
'javelin-behavior-policy-control' => '9a340b3d',
'javelin-behavior-policy-rule-editor' => '5e9f347c',
'javelin-behavior-ponder-votebox' => '4e9b766b',
'javelin-behavior-project-boards' => 'ba4fa35c',
'javelin-behavior-project-create' => '065227cc',
'javelin-behavior-quicksand-blacklist' => '7927a7d3',
- 'javelin-behavior-recurring-edit' => '9c751e15',
+ 'javelin-behavior-recurring-edit' => '5f1c4d5f',
'javelin-behavior-refresh-csrf' => '7814b593',
'javelin-behavior-releeph-preview-branch' => 'b2b4fbaf',
'javelin-behavior-releeph-request-state-change' => 'a0b57eb8',
'javelin-behavior-releeph-request-typeahead' => 'de2e896f',
'javelin-behavior-remarkup-preview' => 'f7379f45',
'javelin-behavior-reorder-applications' => '76b9fc3e',
'javelin-behavior-reorder-columns' => 'e1d25dfb',
'javelin-behavior-repository-crossreference' => 'bea81850',
'javelin-behavior-scrollbar' => '834a1173',
'javelin-behavior-search-reorder-queries' => 'e9581f08',
'javelin-behavior-select-on-click' => '4e3e79a6',
'javelin-behavior-slowvote-embed' => '887ad43f',
'javelin-behavior-stripe-payment-form' => '3f5d6dbf',
'javelin-behavior-test-payment-form' => 'fc91ab6c',
'javelin-behavior-time-typeahead' => '8bfbb401',
'javelin-behavior-toggle-class' => '5d7c9f33',
'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' => '147805fa',
'javelin-dynval' => 'f6555212',
'javelin-event' => '85ea0626',
'javelin-fx' => '54b612ba',
'javelin-history' => 'd4505101',
'javelin-install' => '05270951',
'javelin-json' => '69adf288',
'javelin-leader' => '331b1611',
'javelin-magical-init' => '3010e992',
'javelin-mask' => '8a41885b',
'javelin-quicksand' => '4cebc641',
'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' => '6c53634d',
'javelin-tokenizer' => 'ab5f468d',
'javelin-typeahead' => '70baed2f',
'javelin-typeahead-composite-source' => '503e17fd',
'javelin-typeahead-normalizer' => 'e6e25838',
'javelin-typeahead-ondemand-source' => '8b3fd187',
'javelin-typeahead-preloaded-source' => '54f314a0',
'javelin-typeahead-source' => '2818f5ce',
'javelin-typeahead-static-source' => '6c0e62fa',
'javelin-uri' => '6eff08aa',
'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-workflow' => '5b2e3e2b',
'lightbox-attachment-css' => '7acac05d',
'maniphest-batch-editor' => '8f380ebc',
'maniphest-report-css' => 'f6931fdf',
'maniphest-task-edit-css' => '8e23031b',
'maniphest-task-summary-css' => 'ab2fc691',
'multirow-row-manager' => 'b5d57730',
'owners-path-editor' => 'aa1733d0',
'owners-path-editor-css' => '2f00933b',
'paste-css' => 'eb997ddd',
'path-typeahead' => 'f7fc67ec',
'people-profile-css' => '25970776',
'phabricator-action-list-view-css' => '4f4d09f2',
'phabricator-application-launch-view-css' => '16ca323f',
'phabricator-busy' => '59a7976a',
'phabricator-chatlog-css' => '852140ff',
'phabricator-content-source-view-css' => '4b8b05d4',
'phabricator-core-css' => 'aaea7a7a',
'phabricator-countdown-css' => '86b7b0a0',
'phabricator-dashboard-css' => '17937d22',
'phabricator-drag-and-drop-file-upload' => '07de8873',
'phabricator-draggable-list' => 'a16ec1c6',
'phabricator-fatal-config-template-css' => '8e6c6fcd',
'phabricator-feed-css' => 'b513b5f4',
'phabricator-file-upload' => '477359c8',
'phabricator-filetree-view-css' => 'fccf9f82',
'phabricator-flag-css' => '5337623f',
'phabricator-hovercard' => '14ac66f5',
'phabricator-hovercard-view-css' => 'dd9121a9',
'phabricator-keyboard-shortcut' => '1ae869f2',
'phabricator-keyboard-shortcut-manager' => 'c1700f6f',
'phabricator-main-menu-view' => '663e3810',
'phabricator-nav-view-css' => '7aeaf435',
'phabricator-notification' => '0c6946e7',
'phabricator-notification-css' => '9c279160',
'phabricator-notification-menu-css' => '3c9d8aa1',
'phabricator-object-selector-css' => '029a133d',
'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => '6920d200',
'phabricator-profile-css' => '1a20dcbf',
'phabricator-remarkup-css' => '07b7dc54',
'phabricator-search-results-css' => '15c71110',
'phabricator-shaped-request' => '7cbe244b',
'phabricator-side-menu-view-css' => 'c1db9e9c',
'phabricator-slowvote-css' => '266df6a1',
'phabricator-source-code-view-css' => '2ceee894',
'phabricator-standard-page-view' => '61e68a55',
'phabricator-textareautils' => '5c93c52c',
'phabricator-title' => 'df5e11d2',
'phabricator-tooltip' => '1d298e3a',
'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' => 'c4732d32',
'phame-css' => '88bd4705',
'pholio-css' => '95174bdd',
'pholio-edit-css' => '3ad9d1ee',
'pholio-inline-comments-css' => '8e545e49',
'phortune-credit-card-form' => '2290aeef',
'phortune-credit-card-form-css' => '8391eb02',
'phortune-css' => '9149f103',
'phrequent-css' => 'ffc185ad',
'phriction-document-css' => '0d16bc9a',
'phui-action-header-view-css' => '89c497e7',
'phui-action-panel-css' => '3ee9afd5',
'phui-box-css' => '7b3a2eed',
'phui-button-css' => 'de610129',
'phui-calendar-css' => 'ccabe893',
'phui-calendar-day-css' => 'd1cf6f93',
'phui-calendar-list-css' => 'c1c7f338',
'phui-calendar-month-css' => '476be7e0',
'phui-crumbs-view-css' => '594d719e',
'phui-document-view-css' => '94d5dcd8',
'phui-feed-story-css' => 'c9f3a0b5',
'phui-font-icon-base-css' => '3dad2ae3',
'phui-fontkit-css' => 'dd8ddf27',
'phui-form-css' => '25876baf',
'phui-form-view-css' => '808329f2',
'phui-header-view-css' => '2dd74fe0',
'phui-icon-view-css' => 'bc766998',
'phui-image-mask-css' => '5a8b09c8',
'phui-info-panel-css' => '27ea50a1',
'phui-info-view-css' => 'c6f0aef8',
'phui-inline-comment-view-css' => 'aa16f165',
'phui-list-view-css' => '2e25ebfb',
'phui-object-box-css' => '7d160002',
'phui-object-item-list-view-css' => 'f3a22696',
'phui-pinboard-view-css' => 'eaab2b1b',
'phui-property-list-view-css' => '5b671934',
'phui-remarkup-preview-css' => '19ad512b',
'phui-spacing-css' => '042804d6',
'phui-status-list-view-css' => '888cedb8',
'phui-tag-view-css' => '402691cc',
'phui-text-css' => 'cf019f54',
'phui-timeline-view-css' => 'a85542c8',
'phui-workboard-view-css' => '5c4c53e9',
'phui-workpanel-view-css' => 'e495a5cc',
'phuix-action-list-view' => 'b5c256b8',
'phuix-action-view' => '8cf6d262',
'phuix-dropdown-menu' => 'bd4c8dca',
'policy-css' => '957ea14c',
'policy-edit-css' => '815c66f7',
'policy-transaction-detail-css' => '82100a43',
'ponder-comment-table-css' => '6cdccea7',
'ponder-feed-view-css' => 'e62615b6',
'ponder-post-css' => '9d415218',
'ponder-vote-css' => '8ed6ed8b',
'project-icon-css' => 'c2ecb7f1',
'raphael-core' => '51ee6b43',
'raphael-g' => '40dde778',
'raphael-g-line' => '40da039e',
'releeph-core' => '9b3c5733',
'releeph-preview-branch' => 'b7a6f4a5',
'releeph-request-differential-create-dialog' => '8d8b92cd',
'releeph-request-typeahead-css' => '667a48ae',
'setup-issue-css' => '22270af2',
'sprite-gradient-css' => '4bdb98a7',
'sprite-login-css' => 'a3526809',
'sprite-main-header-css' => '28d01b0b',
'sprite-menu-css' => '9ef76324',
'sprite-projects-css' => 'b0d9e24f',
'sprite-tokens-css' => '1706b943',
'syntax-highlighting-css' => '9fd11da8',
'tokens-css' => '3d0f239e',
'typeahead-browse-css' => 'd8581d2c',
'unhandled-exception-css' => '37d4f9a2',
),
'requires' => array(
'01774ab2' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
'javelin-aphlict',
'javelin-workflow',
'javelin-router',
'javelin-behavior-device',
'javelin-vector',
),
'029a133d' => array(
'aphront-dialog-view-css',
),
'037b59eb' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-util',
'javelin-vector',
'differential-inline-comment-editor',
),
'048330fa' => array(
'javelin-behavior',
'javelin-typeahead-ondemand-source',
'javelin-typeahead',
'javelin-dom',
'javelin-uri',
'javelin-util',
'javelin-stratcom',
'phabricator-prefab',
),
'05270951' => array(
'javelin-util',
'javelin-magical-init',
),
'065227cc' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
),
'07de8873' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-dom',
'javelin-uri',
'phabricator-file-upload',
),
'087e919c' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
),
'095ed313' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phabricator-phtize',
'phabricator-textareautils',
'javelin-workflow',
'javelin-vector',
),
'0a3f3021' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'javelin-router',
),
'0c6946e7' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
'phabricator-notification-css',
),
'0f764c35' => array(
'javelin-install',
'javelin-util',
),
'13c739ea' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'javelin-uri',
'phabricator-textareautils',
),
'147805fa' => array(
'javelin-magical-init',
'javelin-install',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
),
'1499a8cb' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-history',
),
'14ac66f5' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
'javelin-request',
'javelin-uri',
),
'14d7a8b8' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-dom',
'javelin-magical-init',
'javelin-vector',
'javelin-request',
'javelin-util',
),
'16c695bf' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-behavior-device',
'javelin-scrollbar',
'javelin-quicksand',
'phabricator-keyboard-shortcut',
'conpherence-thread-manager',
),
'1ad0a787' => array(
'javelin-install',
'javelin-reactor',
'javelin-util',
'javelin-reactor-node-calmer',
),
'1ae869f2' => array(
'javelin-install',
'javelin-util',
'phabricator-keyboard-shortcut-manager',
),
'1d298e3a' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-vector',
),
'1def2711' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
'2035b9cb' => 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',
),
'21ba5861' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-workflow',
'javelin-stratcom',
'conpherence-thread-manager',
),
'2290aeef' => array(
'javelin-install',
'javelin-dom',
'javelin-json',
'javelin-workflow',
'javelin-util',
),
'246dc085' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-workflow',
'javelin-quicksand',
'phabricator-phtize',
'phabricator-drag-and-drop-file-upload',
'phabricator-draggable-list',
),
'271ffdd7' => array(
'multirow-row-manager',
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-json',
'phabricator-prefab',
),
'2818f5ce' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-typeahead-normalizer',
),
'2926fff2' => array(
'javelin-behavior',
'javelin-dom',
),
'29274e2b' => array(
'javelin-install',
'javelin-util',
),
'2b228192' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-workflow',
'javelin-json',
),
'2b8de964' => array(
'javelin-install',
'javelin-util',
),
'2bfa2836' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'2c426492' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-keyboard-shortcut',
),
'2caa8fb8' => array(
'javelin-install',
'javelin-event',
),
'331b1611' => array(
'javelin-install',
),
'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',
),
'3ee3408b' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'phabricator-tooltip',
),
'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',
),
'43b24a10' => 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',
),
'44168bad' => array(
'javelin-behavior',
'javelin-dom',
'phabricator-prefab',
),
'44959b73' => array(
'javelin-util',
'javelin-uri',
'javelin-install',
),
'453c5375' => array(
'javelin-behavior',
'javelin-dom',
),
'469c0d9e' => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
),
'477359c8' => array(
'javelin-install',
'javelin-dom',
'phabricator-notification',
),
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',
),
'49b73b36' => array(
'javelin-behavior',
'javelin-dom',
'javelin-request',
'javelin-util',
),
'4c95d29e' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-json',
'javelin-stratcom',
'phabricator-shaped-request',
),
'4cebc641' => array(
'javelin-install',
),
'4e3e79a6' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'4e9b766b' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-request',
),
'4fdb476d' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'503e17fd' => array(
'javelin-install',
'javelin-typeahead-source',
'javelin-util',
),
'510b5809' => array(
'javelin-behavior',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
),
'519705ea' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
'5359e785' => array(
'javelin-install',
'javelin-util',
'javelin-websocket',
'javelin-leader',
'javelin-json',
),
54733475 => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phuix-dropdown-menu',
),
'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',
),
58562350 => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
'javelin-workflow',
'javelin-router',
'javelin-behavior-device',
'javelin-vector',
),
'59a7976a' => array(
'javelin-install',
'javelin-dom',
'javelin-fx',
),
'59b251eb' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
),
'5b2e3e2b' => array(
'javelin-stratcom',
'javelin-request',
'javelin-dom',
'javelin-vector',
'javelin-install',
'javelin-util',
'javelin-mask',
'javelin-uri',
'javelin-routable',
),
'5c54cbf3' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'5c93c52c' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
),
'5d7c9f33' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'5e9f347c' => array(
'javelin-behavior',
'multirow-row-manager',
'javelin-dom',
'javelin-util',
'phabricator-prefab',
'javelin-json',
),
'5fefb143' => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
'javelin-stratcom',
),
60479091 => array(
'phabricator-busy',
'javelin-behavior',
),
'60821bc7' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'6153c708' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-workflow',
),
'61cbc29a' => array(
'javelin-magical-init',
'javelin-util',
),
'62dfea03' => array(
'javelin-install',
'javelin-util',
),
'635de1ec' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
),
'6882e80a' => array(
'javelin-dom',
),
'6920d200' => 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',
),
'69adf288' => array(
'javelin-install',
),
'6c0e62fa' => array(
'javelin-install',
'javelin-typeahead-source',
),
'6c2b09a2' => array(
'javelin-install',
'javelin-util',
),
'6c53634d' => array(
'javelin-install',
'javelin-event',
'javelin-util',
'javelin-magical-init',
),
'6d3e1947' => array(
'javelin-behavior',
'javelin-diffusion-locate-file-source',
'javelin-dom',
'javelin-typeahead',
'javelin-uri',
),
'6d49590e' => array(
'javelin-behavior',
'javelin-dom',
'phabricator-drag-and-drop-file-upload',
'phabricator-textareautils',
),
'6eff08aa' => array(
'javelin-install',
'javelin-util',
'javelin-stratcom',
),
'70baed2f' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
'javelin-util',
),
'7319e029' => array(
'javelin-behavior',
'javelin-dom',
),
'73d09eef' => array(
'javelin-behavior',
'javelin-vector',
'javelin-dom',
),
'76b9fc3e' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'76f4ebed' => array(
'javelin-install',
'javelin-reactor',
'javelin-util',
),
'7814b593' => array(
'javelin-request',
'javelin-behavior',
'javelin-dom',
'javelin-router',
'javelin-util',
'phabricator-busy',
),
'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',
),
82439934 => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
),
'834a1173' => array(
'javelin-behavior',
'javelin-scrollbar',
),
'84845b5b' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
),
'85ea0626' => array(
'javelin-install',
),
'8694b1df' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-tooltip',
'changeset-view-manager',
),
'86a13f7f' => array(
'aphront-typeahead-control-css',
'phui-tag-view-css',
),
'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',
),
'88f0c5b3' => array(
'javelin-behavior',
'javelin-dom',
'javelin-vector',
),
'8906c07b' => array(
'phui-fontkit-css',
),
'8a41885b' => array(
'javelin-install',
'javelin-dom',
),
'8b3fd187' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-typeahead-source',
),
'8bfbb401' => array(
'javelin-behavior',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
'javelin-typeahead-static-source',
),
'8ce821c5' => array(
'phabricator-notification',
'javelin-stratcom',
'javelin-behavior',
),
'8cf6d262' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
),
'8ef9ab58' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'9007c197' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
93568464 => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-util',
'phabricator-notification',
'javelin-behavior-device',
'phuix-dropdown-menu',
'phuix-action-list-view',
'phuix-action-view',
'conpherence-thread-manager',
),
'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',
),
'988040b4' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
'995ad707' => array(
'javelin-behavior',
'javelin-request',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
'javelin-uri',
'javelin-behavior-device',
'phabricator-title',
),
'9a340b3d' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phuix-dropdown-menu',
'phuix-action-list-view',
'phuix-action-view',
'javelin-workflow',
),
'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',
),
'a16ec1c6' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
'javelin-vector',
'javelin-magical-init',
),
'a205cf28' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
'javelin-install',
),
'a464fe03' => array(
'javelin-behavior',
'javelin-uri',
'phabricator-notification',
),
'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',
),
'ab5f468d' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
),
'b064af76' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-request',
'javelin-util',
'phabricator-shaped-request',
),
'b1a59974' => 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',
),
'b1f0ccee' => array(
'javelin-install',
'javelin-dom',
'javelin-reactor-dom',
),
'b23b49e6' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-request',
'phabricator-shaped-request',
),
'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',
),
'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',
),
'ba4fa35c' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
),
'bba9eedf' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'bd4c8dca' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-vector',
'javelin-stratcom',
),
'bdaf4d04' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-request',
),
'be807912' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-shaped-request',
),
'bea81850' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-uri',
),
'c1700f6f' => array(
'javelin-install',
'javelin-util',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
),
'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',
),
'ca3f91eb' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-phtize',
),
'cf86d16a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
'phabricator-drag-and-drop-file-upload',
),
'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',
),
'd4c87bf4' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
'javelin-request',
'javelin-workflow',
),
'd4eecc63' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'd75709e6' => array(
'javelin-behavior',
'javelin-workflow',
'javelin-json',
'javelin-dom',
'phabricator-keyboard-shortcut',
),
'd835b03a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-shaped-request',
),
'dbbf48b6' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phabricator-busy',
),
'de2e896f' => array(
'javelin-behavior',
'javelin-dom',
'javelin-typeahead',
'javelin-typeahead-ondemand-source',
'javelin-dom',
),
'df5e11d2' => array(
'javelin-install',
),
'e10f8e18' => array(
'javelin-behavior',
'javelin-dom',
'phabricator-prefab',
),
'e19cfd6e' => array(
'phui-inline-comment-view-css',
),
'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',
),
'e379b58e' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
'javelin-uri',
),
'e4cc26b3' => array(
'javelin-behavior',
'javelin-dom',
),
'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',
),
'ea681761' => array(
'javelin-behavior',
'javelin-aphlict',
'phabricator-phtize',
'javelin-dom',
),
'efe49472' => array(
'javelin-install',
'javelin-util',
),
'f36e01af' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-vector',
'phabricator-hovercard',
),
'f411b6ae' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-util',
'javelin-dom',
'javelin-request',
'phabricator-keyboard-shortcut',
),
'f5d1233b' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-prefab',
'multirow-row-manager',
'javelin-json',
),
'f6555212' => array(
'javelin-install',
'javelin-reactornode',
'javelin-util',
'javelin-reactor',
),
'f7379f45' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-shaped-request',
),
'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',
),
'fa0f4fc2' => array(
'javelin-behavior',
'javelin-dom',
'javelin-vector',
'javelin-magical-init',
),
'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',
),
),
'packages' => array(
'core.pkg.css' => array(
'phabricator-core-css',
'phabricator-zindex-css',
'phui-button-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',
'phabricator-remarkup-css',
'syntax-highlighting-css',
'aphront-pager-view-css',
'aphront-tooltip-css',
'phabricator-flag-css',
'phui-info-view-css',
'sprite-gradient-css',
'sprite-menu-css',
'phabricator-main-menu-view',
'phabricator-notification-css',
'phabricator-notification-menu-css',
'lightbox-attachment-css',
'phui-header-view-css',
'phabricator-filetree-view-css',
'phabricator-nav-view-css',
'phabricator-side-menu-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',
'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',
'phui-font-icon-base-css',
'sprite-main-header-css',
'phui-box-css',
'phui-object-box-css',
'phui-timeline-view-css',
'sprite-tokens-css',
'tokens-css',
'phui-status-list-view-css',
'phui-feed-story-css',
'phabricator-feed-css',
'phabricator-dashboard-css',
'aphront-multi-column-view-css',
'phui-action-header-view-css',
'conpherence-durable-column-view',
),
'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',
'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',
'phabricator-hovercard',
'javelin-behavior-phabricator-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-scrollbar',
'javelin-behavior-scrollbar',
'javelin-behavior-durable-column',
'conpherence-thread-manager',
),
'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-results-table-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',
),
'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-transaction-controls',
'javelin-behavior-maniphest-transaction-preview',
'javelin-behavior-maniphest-transaction-expand',
'javelin-behavior-maniphest-subpriority-editor',
'javelin-behavior-maniphest-list-editor',
),
),
);
diff --git a/src/applications/diffusion/herald/HeraldPreCommitAdapter.php b/src/applications/diffusion/herald/HeraldPreCommitAdapter.php
index d1fc7c6be4..8e8f89a88e 100644
--- a/src/applications/diffusion/herald/HeraldPreCommitAdapter.php
+++ b/src/applications/diffusion/herald/HeraldPreCommitAdapter.php
@@ -1,119 +1,113 @@
<?php
abstract class HeraldPreCommitAdapter extends HeraldAdapter {
private $log;
private $hookEngine;
public function setPushLog(PhabricatorRepositoryPushLog $log) {
$this->log = $log;
return $this;
}
public function setHookEngine(DiffusionCommitHookEngine $engine) {
$this->hookEngine = $engine;
return $this;
}
public function getHookEngine() {
return $this->hookEngine;
}
public function getAdapterApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
public function getObject() {
return $this->log;
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return true;
default:
return false;
}
}
public function canTriggerOnObject($object) {
if ($object instanceof PhabricatorRepository) {
return true;
}
if ($object instanceof PhabricatorProject) {
return true;
}
return false;
}
public function explainValidTriggerObjects() {
return pht('This rule can trigger for **repositories** or **projects**.');
}
public function getTriggerObjectPHIDs() {
return array_merge(
array(
$this->hookEngine->getRepository()->getPHID(),
$this->getPHID(),
),
$this->hookEngine->getRepository()->getProjectPHIDs());
}
public function getActions($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
return array_merge(
array(
self::ACTION_BLOCK,
self::ACTION_EMAIL,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return array_merge(
array(
self::ACTION_EMAIL,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
}
}
public function getPHID() {
return $this->getObject()->getPHID();
}
public function applyHeraldEffects(array $effects) {
assert_instances_of($effects, 'HeraldEffect');
$result = array();
foreach ($effects as $effect) {
$action = $effect->getAction();
switch ($action) {
- case self::ACTION_NOTHING:
- $result[] = new HeraldApplyTranscript(
- $effect,
- true,
- pht('Did nothing.'));
- break;
case self::ACTION_BLOCK:
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Blocked push.'));
break;
default:
$result[] = $this->applyStandardEffect($effect);
break;
}
}
return $result;
}
}
diff --git a/src/applications/herald/adapter/HeraldAdapter.php b/src/applications/herald/adapter/HeraldAdapter.php
index 702c477300..00b357ff07 100644
--- a/src/applications/herald/adapter/HeraldAdapter.php
+++ b/src/applications/herald/adapter/HeraldAdapter.php
@@ -1,1677 +1,1685 @@
<?php
/**
* @task customfield Custom Field Integration
*/
abstract class HeraldAdapter {
const FIELD_TITLE = 'title';
const FIELD_BODY = 'body';
const FIELD_AUTHOR = 'author';
const FIELD_ASSIGNEE = 'assignee';
const FIELD_REVIEWER = 'reviewer';
const FIELD_REVIEWERS = 'reviewers';
const FIELD_COMMITTER = 'committer';
const FIELD_CC = 'cc';
const FIELD_TAGS = 'tags';
const FIELD_DIFF_FILE = 'diff-file';
const FIELD_DIFF_CONTENT = 'diff-content';
const FIELD_DIFF_ADDED_CONTENT = 'diff-added-content';
const FIELD_DIFF_REMOVED_CONTENT = 'diff-removed-content';
const FIELD_DIFF_ENORMOUS = 'diff-enormous';
const FIELD_REPOSITORY = 'repository';
const FIELD_REPOSITORY_PROJECTS = 'repository-projects';
const FIELD_RULE = 'rule';
const FIELD_AFFECTED_PACKAGE = 'affected-package';
const FIELD_AFFECTED_PACKAGE_OWNER = 'affected-package-owner';
const FIELD_CONTENT_SOURCE = 'contentsource';
const FIELD_ALWAYS = 'always';
const FIELD_AUTHOR_PROJECTS = 'authorprojects';
const FIELD_PROJECTS = 'projects';
const FIELD_PUSHER = 'pusher';
const FIELD_PUSHER_PROJECTS = 'pusher-projects';
const FIELD_DIFFERENTIAL_REVISION = 'differential-revision';
const FIELD_DIFFERENTIAL_REVIEWERS = 'differential-reviewers';
const FIELD_DIFFERENTIAL_CCS = 'differential-ccs';
const FIELD_DIFFERENTIAL_ACCEPTED = 'differential-accepted';
const FIELD_IS_MERGE_COMMIT = 'is-merge-commit';
const FIELD_BRANCHES = 'branches';
const FIELD_AUTHOR_RAW = 'author-raw';
const FIELD_COMMITTER_RAW = 'committer-raw';
const FIELD_IS_NEW_OBJECT = 'new-object';
const FIELD_APPLICATION_EMAIL = 'applicaton-email';
const FIELD_TASK_PRIORITY = 'taskpriority';
const FIELD_TASK_STATUS = 'taskstatus';
const FIELD_PUSHER_IS_COMMITTER = 'pusher-is-committer';
const FIELD_PATH = 'path';
const CONDITION_CONTAINS = 'contains';
const CONDITION_NOT_CONTAINS = '!contains';
const CONDITION_IS = 'is';
const CONDITION_IS_NOT = '!is';
const CONDITION_IS_ANY = 'isany';
const CONDITION_IS_NOT_ANY = '!isany';
const CONDITION_INCLUDE_ALL = 'all';
const CONDITION_INCLUDE_ANY = 'any';
const CONDITION_INCLUDE_NONE = 'none';
const CONDITION_IS_ME = 'me';
const CONDITION_IS_NOT_ME = '!me';
const CONDITION_REGEXP = 'regexp';
const CONDITION_RULE = 'conditions';
const CONDITION_NOT_RULE = '!conditions';
const CONDITION_EXISTS = 'exists';
const CONDITION_NOT_EXISTS = '!exists';
const CONDITION_UNCONDITIONALLY = 'unconditionally';
const CONDITION_NEVER = 'never';
const CONDITION_REGEXP_PAIR = 'regexp-pair';
const CONDITION_HAS_BIT = 'bit';
const CONDITION_NOT_BIT = '!bit';
const CONDITION_IS_TRUE = 'true';
const CONDITION_IS_FALSE = 'false';
const ACTION_ADD_CC = 'addcc';
const ACTION_REMOVE_CC = 'remcc';
const ACTION_EMAIL = 'email';
const ACTION_NOTHING = 'nothing';
const ACTION_AUDIT = 'audit';
const ACTION_FLAG = 'flag';
const ACTION_ASSIGN_TASK = 'assigntask';
const ACTION_ADD_PROJECTS = 'addprojects';
const ACTION_REMOVE_PROJECTS = 'removeprojects';
const ACTION_ADD_REVIEWERS = 'addreviewers';
const ACTION_ADD_BLOCKING_REVIEWERS = 'addblockingreviewers';
const ACTION_APPLY_BUILD_PLANS = 'applybuildplans';
const ACTION_BLOCK = 'block';
const ACTION_REQUIRE_SIGNATURE = 'signature';
const VALUE_TEXT = 'text';
const VALUE_NONE = 'none';
const VALUE_EMAIL = 'email';
const VALUE_USER = 'user';
const VALUE_TAG = 'tag';
const VALUE_RULE = 'rule';
const VALUE_REPOSITORY = 'repository';
const VALUE_OWNERS_PACKAGE = 'package';
const VALUE_PROJECT = 'project';
const VALUE_FLAG_COLOR = 'flagcolor';
const VALUE_CONTENT_SOURCE = 'contentsource';
const VALUE_USER_OR_PROJECT = 'userorproject';
const VALUE_BUILD_PLAN = 'buildplan';
const VALUE_TASK_PRIORITY = 'taskpriority';
const VALUE_TASK_STATUS = 'taskstatus';
const VALUE_LEGAL_DOCUMENTS = 'legaldocuments';
const VALUE_APPLICATION_EMAIL = 'applicationemail';
private $contentSource;
private $isNewObject;
private $applicationEmail;
private $customFields = false;
private $customActions = null;
private $queuedTransactions = array();
private $emailPHIDs = array();
private $forcedEmailPHIDs = array();
public function getEmailPHIDs() {
return array_values($this->emailPHIDs);
}
public function getForcedEmailPHIDs() {
return array_values($this->forcedEmailPHIDs);
}
public function getCustomActions() {
if ($this->customActions === null) {
$custom_actions = id(new PhutilSymbolLoader())
->setAncestorClass('HeraldCustomAction')
->loadObjects();
foreach ($custom_actions as $key => $object) {
if (!$object->appliesToAdapter($this)) {
unset($custom_actions[$key]);
}
}
$this->customActions = array();
foreach ($custom_actions as $action) {
$key = $action->getActionKey();
if (array_key_exists($key, $this->customActions)) {
throw new Exception(
pht(
"More than one Herald custom action implementation ".
"handles the action key: '%s'.",
$key));
}
$this->customActions[$key] = $action;
}
}
return $this->customActions;
}
public function setContentSource(PhabricatorContentSource $content_source) {
$this->contentSource = $content_source;
return $this;
}
public function getContentSource() {
return $this->contentSource;
}
public function getIsNewObject() {
if (is_bool($this->isNewObject)) {
return $this->isNewObject;
}
throw new Exception(
pht(
'You must %s to a boolean first!',
'setIsNewObject()'));
}
public function setIsNewObject($new) {
$this->isNewObject = (bool)$new;
return $this;
}
public function setApplicationEmail(
PhabricatorMetaMTAApplicationEmail $email) {
$this->applicationEmail = $email;
return $this;
}
public function getApplicationEmail() {
return $this->applicationEmail;
}
abstract public function getPHID();
abstract public function getHeraldName();
public function getHeraldField($field_name) {
switch ($field_name) {
case self::FIELD_RULE:
return null;
case self::FIELD_CONTENT_SOURCE:
return $this->getContentSource()->getSource();
case self::FIELD_ALWAYS:
return true;
case self::FIELD_IS_NEW_OBJECT:
return $this->getIsNewObject();
case self::FIELD_CC:
$object = $this->getObject();
if (!($object instanceof PhabricatorSubscribableInterface)) {
throw new Exception(
pht(
'Adapter object (of class "%s") does not implement interface '.
'"%s", so the subscribers field value can not be determined.',
get_class($object),
'PhabricatorSubscribableInterface'));
}
$phid = $object->getPHID();
return PhabricatorSubscribersQuery::loadSubscribersForPHID($phid);
case self::FIELD_APPLICATION_EMAIL:
$value = array();
// while there is only one match by implementation, we do set
// comparisons on phids, so return an array with just the phid
if ($this->getApplicationEmail()) {
$value[] = $this->getApplicationEmail()->getPHID();
}
return $value;
default:
if ($this->isHeraldCustomKey($field_name)) {
return $this->getCustomFieldValue($field_name);
}
throw new Exception(pht("Unknown field '%s'!", $field_name));
}
}
abstract public function applyHeraldEffects(array $effects);
protected function handleCustomHeraldEffect(HeraldEffect $effect) {
$custom_action = idx($this->getCustomActions(), $effect->getAction());
if ($custom_action !== null) {
return $custom_action->applyEffect(
$this,
$this->getObject(),
$effect);
}
return null;
}
public function isAvailableToUser(PhabricatorUser $viewer) {
$applications = id(new PhabricatorApplicationQuery())
->setViewer($viewer)
->withInstalled(true)
->withClasses(array($this->getAdapterApplicationClass()))
->execute();
return !empty($applications);
}
public function queueTransaction($transaction) {
$this->queuedTransactions[] = $transaction;
}
public function getQueuedTransactions() {
return $this->queuedTransactions;
}
protected function newTransaction() {
$object = $this->newObject();
if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
throw new Exception(
pht(
'Unable to build a new transaction for adapter object; it does '.
'not implement "%s".',
'PhabricatorApplicationTransactionInterface'));
}
return $object->getApplicationTransactionTemplate();
}
/**
* NOTE: You generally should not override this; it exists to support legacy
* adapters which had hard-coded content types.
*/
public function getAdapterContentType() {
return get_class($this);
}
abstract public function getAdapterContentName();
abstract public function getAdapterContentDescription();
abstract public function getAdapterApplicationClass();
abstract public function getObject();
/**
* Return a new characteristic object for this adapter.
*
* The adapter will use this object to test for interfaces, generate
* transactions, and interact with custom fields.
*
* Adapters must return an object from this method to enable custom
* field rules and various implicit actions.
*
* Normally, you'll return an empty version of the adapted object:
*
* return new ApplicationObject();
*
* @return null|object Template object.
*/
protected function newObject() {
return null;
}
public function supportsRuleType($rule_type) {
return false;
}
public function canTriggerOnObject($object) {
return false;
}
public function explainValidTriggerObjects() {
return pht('This adapter can not trigger on objects.');
}
public function getTriggerObjectPHIDs() {
return array($this->getPHID());
}
public function getAdapterSortKey() {
return sprintf(
'%08d%s',
$this->getAdapterSortOrder(),
$this->getAdapterContentName());
}
public function getAdapterSortOrder() {
return 1000;
}
/* -( Fields )------------------------------------------------------------- */
public function getFields() {
$fields = array();
$fields[] = self::FIELD_ALWAYS;
$fields[] = self::FIELD_RULE;
$custom_fields = $this->getCustomFields();
if ($custom_fields) {
foreach ($custom_fields->getFields() as $custom_field) {
$key = $custom_field->getFieldKey();
$fields[] = $this->getHeraldKeyFromCustomKey($key);
}
}
return $fields;
}
public function getFieldNameMap() {
return array(
self::FIELD_TITLE => pht('Title'),
self::FIELD_BODY => pht('Body'),
self::FIELD_AUTHOR => pht('Author'),
self::FIELD_ASSIGNEE => pht('Assignee'),
self::FIELD_COMMITTER => pht('Committer'),
self::FIELD_REVIEWER => pht('Reviewer'),
self::FIELD_REVIEWERS => pht('Reviewers'),
self::FIELD_CC => pht('CCs'),
self::FIELD_TAGS => pht('Tags'),
self::FIELD_DIFF_FILE => pht('Any changed filename'),
self::FIELD_DIFF_CONTENT => pht('Any changed file content'),
self::FIELD_DIFF_ADDED_CONTENT => pht('Any added file content'),
self::FIELD_DIFF_REMOVED_CONTENT => pht('Any removed file content'),
self::FIELD_DIFF_ENORMOUS => pht('Change is enormous'),
self::FIELD_REPOSITORY => pht('Repository'),
self::FIELD_REPOSITORY_PROJECTS => pht('Repository\'s projects'),
self::FIELD_RULE => pht('Another Herald rule'),
self::FIELD_AFFECTED_PACKAGE => pht('Any affected package'),
self::FIELD_AFFECTED_PACKAGE_OWNER =>
pht("Any affected package's owner"),
self::FIELD_CONTENT_SOURCE => pht('Content Source'),
self::FIELD_ALWAYS => pht('Always'),
self::FIELD_AUTHOR_PROJECTS => pht("Author's projects"),
self::FIELD_PROJECTS => pht('Projects'),
self::FIELD_PUSHER => pht('Pusher'),
self::FIELD_PUSHER_PROJECTS => pht("Pusher's projects"),
self::FIELD_DIFFERENTIAL_REVISION => pht('Differential revision'),
self::FIELD_DIFFERENTIAL_REVIEWERS => pht('Differential reviewers'),
self::FIELD_DIFFERENTIAL_CCS => pht('Differential CCs'),
self::FIELD_DIFFERENTIAL_ACCEPTED
=> pht('Accepted Differential revision'),
self::FIELD_IS_MERGE_COMMIT => pht('Commit is a merge'),
self::FIELD_BRANCHES => pht('Commit\'s branches'),
self::FIELD_AUTHOR_RAW => pht('Raw author name'),
self::FIELD_COMMITTER_RAW => pht('Raw committer name'),
self::FIELD_IS_NEW_OBJECT => pht('Is newly created?'),
self::FIELD_APPLICATION_EMAIL => pht('Receiving email address'),
self::FIELD_TASK_PRIORITY => pht('Task priority'),
self::FIELD_TASK_STATUS => pht('Task status'),
self::FIELD_PUSHER_IS_COMMITTER => pht('Pusher same as committer'),
self::FIELD_PATH => pht('Path'),
) + $this->getCustomFieldNameMap();
}
/* -( Conditions )--------------------------------------------------------- */
public function getConditionNameMap() {
return array(
self::CONDITION_CONTAINS => pht('contains'),
self::CONDITION_NOT_CONTAINS => pht('does not contain'),
self::CONDITION_IS => pht('is'),
self::CONDITION_IS_NOT => pht('is not'),
self::CONDITION_IS_ANY => pht('is any of'),
self::CONDITION_IS_TRUE => pht('is true'),
self::CONDITION_IS_FALSE => pht('is false'),
self::CONDITION_IS_NOT_ANY => pht('is not any of'),
self::CONDITION_INCLUDE_ALL => pht('include all of'),
self::CONDITION_INCLUDE_ANY => pht('include any of'),
self::CONDITION_INCLUDE_NONE => pht('do not include'),
self::CONDITION_IS_ME => pht('is myself'),
self::CONDITION_IS_NOT_ME => pht('is not myself'),
self::CONDITION_REGEXP => pht('matches regexp'),
self::CONDITION_RULE => pht('matches:'),
self::CONDITION_NOT_RULE => pht('does not match:'),
self::CONDITION_EXISTS => pht('exists'),
self::CONDITION_NOT_EXISTS => pht('does not exist'),
self::CONDITION_UNCONDITIONALLY => '', // don't show anything!
self::CONDITION_NEVER => '', // don't show anything!
self::CONDITION_REGEXP_PAIR => pht('matches regexp pair'),
self::CONDITION_HAS_BIT => pht('has bit'),
self::CONDITION_NOT_BIT => pht('lacks bit'),
);
}
public function getConditionsForField($field) {
switch ($field) {
case self::FIELD_TITLE:
case self::FIELD_BODY:
case self::FIELD_COMMITTER_RAW:
case self::FIELD_AUTHOR_RAW:
case self::FIELD_PATH:
return array(
self::CONDITION_CONTAINS,
self::CONDITION_NOT_CONTAINS,
self::CONDITION_IS,
self::CONDITION_IS_NOT,
self::CONDITION_REGEXP,
);
case self::FIELD_REVIEWER:
case self::FIELD_PUSHER:
case self::FIELD_TASK_PRIORITY:
case self::FIELD_TASK_STATUS:
return array(
self::CONDITION_IS_ANY,
self::CONDITION_IS_NOT_ANY,
);
case self::FIELD_REPOSITORY:
case self::FIELD_ASSIGNEE:
case self::FIELD_AUTHOR:
case self::FIELD_COMMITTER:
return array(
self::CONDITION_IS_ANY,
self::CONDITION_IS_NOT_ANY,
self::CONDITION_EXISTS,
self::CONDITION_NOT_EXISTS,
);
case self::FIELD_TAGS:
case self::FIELD_REVIEWERS:
case self::FIELD_CC:
case self::FIELD_AUTHOR_PROJECTS:
case self::FIELD_PROJECTS:
case self::FIELD_AFFECTED_PACKAGE:
case self::FIELD_AFFECTED_PACKAGE_OWNER:
case self::FIELD_PUSHER_PROJECTS:
case self::FIELD_REPOSITORY_PROJECTS:
return array(
self::CONDITION_INCLUDE_ALL,
self::CONDITION_INCLUDE_ANY,
self::CONDITION_INCLUDE_NONE,
self::CONDITION_EXISTS,
self::CONDITION_NOT_EXISTS,
);
case self::FIELD_APPLICATION_EMAIL:
return array(
self::CONDITION_INCLUDE_ANY,
self::CONDITION_INCLUDE_NONE,
self::CONDITION_EXISTS,
self::CONDITION_NOT_EXISTS,
);
case self::FIELD_DIFF_FILE:
case self::FIELD_BRANCHES:
return array(
self::CONDITION_CONTAINS,
self::CONDITION_REGEXP,
);
case self::FIELD_DIFF_CONTENT:
case self::FIELD_DIFF_ADDED_CONTENT:
case self::FIELD_DIFF_REMOVED_CONTENT:
return array(
self::CONDITION_CONTAINS,
self::CONDITION_REGEXP,
self::CONDITION_REGEXP_PAIR,
);
case self::FIELD_RULE:
return array(
self::CONDITION_RULE,
self::CONDITION_NOT_RULE,
);
case self::FIELD_CONTENT_SOURCE:
return array(
self::CONDITION_IS,
self::CONDITION_IS_NOT,
);
case self::FIELD_ALWAYS:
return array(
self::CONDITION_UNCONDITIONALLY,
);
case self::FIELD_DIFFERENTIAL_REVIEWERS:
return array(
self::CONDITION_EXISTS,
self::CONDITION_NOT_EXISTS,
self::CONDITION_INCLUDE_ALL,
self::CONDITION_INCLUDE_ANY,
self::CONDITION_INCLUDE_NONE,
);
case self::FIELD_DIFFERENTIAL_CCS:
return array(
self::CONDITION_INCLUDE_ALL,
self::CONDITION_INCLUDE_ANY,
self::CONDITION_INCLUDE_NONE,
);
case self::FIELD_DIFFERENTIAL_REVISION:
case self::FIELD_DIFFERENTIAL_ACCEPTED:
return array(
self::CONDITION_EXISTS,
self::CONDITION_NOT_EXISTS,
);
case self::FIELD_IS_MERGE_COMMIT:
case self::FIELD_DIFF_ENORMOUS:
case self::FIELD_IS_NEW_OBJECT:
case self::FIELD_PUSHER_IS_COMMITTER:
return array(
self::CONDITION_IS_TRUE,
self::CONDITION_IS_FALSE,
);
default:
if ($this->isHeraldCustomKey($field)) {
return $this->getCustomFieldConditions($field);
}
throw new Exception(
pht(
"This adapter does not define conditions for field '%s'!",
$field));
}
}
public function doesConditionMatch(
HeraldEngine $engine,
HeraldRule $rule,
HeraldCondition $condition,
$field_value) {
$condition_type = $condition->getFieldCondition();
$condition_value = $condition->getValue();
switch ($condition_type) {
case self::CONDITION_CONTAINS:
// "Contains" can take an array of strings, as in "Any changed
// filename" for diffs.
foreach ((array)$field_value as $value) {
if (stripos($value, $condition_value) !== false) {
return true;
}
}
return false;
case self::CONDITION_NOT_CONTAINS:
return (stripos($field_value, $condition_value) === false);
case self::CONDITION_IS:
return ($field_value == $condition_value);
case self::CONDITION_IS_NOT:
return ($field_value != $condition_value);
case self::CONDITION_IS_ME:
return ($field_value == $rule->getAuthorPHID());
case self::CONDITION_IS_NOT_ME:
return ($field_value != $rule->getAuthorPHID());
case self::CONDITION_IS_ANY:
if (!is_array($condition_value)) {
throw new HeraldInvalidConditionException(
pht('Expected condition value to be an array.'));
}
$condition_value = array_fuse($condition_value);
return isset($condition_value[$field_value]);
case self::CONDITION_IS_NOT_ANY:
if (!is_array($condition_value)) {
throw new HeraldInvalidConditionException(
pht('Expected condition value to be an array.'));
}
$condition_value = array_fuse($condition_value);
return !isset($condition_value[$field_value]);
case self::CONDITION_INCLUDE_ALL:
if (!is_array($field_value)) {
throw new HeraldInvalidConditionException(
pht('Object produced non-array value!'));
}
if (!is_array($condition_value)) {
throw new HeraldInvalidConditionException(
pht('Expected condition value to be an array.'));
}
$have = array_select_keys(array_fuse($field_value), $condition_value);
return (count($have) == count($condition_value));
case self::CONDITION_INCLUDE_ANY:
return (bool)array_select_keys(
array_fuse($field_value),
$condition_value);
case self::CONDITION_INCLUDE_NONE:
return !array_select_keys(
array_fuse($field_value),
$condition_value);
case self::CONDITION_EXISTS:
case self::CONDITION_IS_TRUE:
return (bool)$field_value;
case self::CONDITION_NOT_EXISTS:
case self::CONDITION_IS_FALSE:
return !$field_value;
case self::CONDITION_UNCONDITIONALLY:
return (bool)$field_value;
case self::CONDITION_NEVER:
return false;
case self::CONDITION_REGEXP:
foreach ((array)$field_value as $value) {
// We add the 'S' flag because we use the regexp multiple times.
// It shouldn't cause any troubles if the flag is already there
// - /.*/S is evaluated same as /.*/SS.
$result = @preg_match($condition_value.'S', $value);
if ($result === false) {
throw new HeraldInvalidConditionException(
pht('Regular expression is not valid!'));
}
if ($result) {
return true;
}
}
return false;
case self::CONDITION_REGEXP_PAIR:
// Match a JSON-encoded pair of regular expressions against a
// dictionary. The first regexp must match the dictionary key, and the
// second regexp must match the dictionary value. If any key/value pair
// in the dictionary matches both regexps, the condition is satisfied.
$regexp_pair = null;
try {
$regexp_pair = phutil_json_decode($condition_value);
} catch (PhutilJSONParserException $ex) {
throw new HeraldInvalidConditionException(
pht('Regular expression pair is not valid JSON!'));
}
if (count($regexp_pair) != 2) {
throw new HeraldInvalidConditionException(
pht('Regular expression pair is not a pair!'));
}
$key_regexp = array_shift($regexp_pair);
$value_regexp = array_shift($regexp_pair);
foreach ((array)$field_value as $key => $value) {
$key_matches = @preg_match($key_regexp, $key);
if ($key_matches === false) {
throw new HeraldInvalidConditionException(
pht('First regular expression is invalid!'));
}
if ($key_matches) {
$value_matches = @preg_match($value_regexp, $value);
if ($value_matches === false) {
throw new HeraldInvalidConditionException(
pht('Second regular expression is invalid!'));
}
if ($value_matches) {
return true;
}
}
}
return false;
case self::CONDITION_RULE:
case self::CONDITION_NOT_RULE:
$rule = $engine->getRule($condition_value);
if (!$rule) {
throw new HeraldInvalidConditionException(
pht('Condition references a rule which does not exist!'));
}
$is_not = ($condition_type == self::CONDITION_NOT_RULE);
$result = $engine->doesRuleMatch($rule, $this);
if ($is_not) {
$result = !$result;
}
return $result;
case self::CONDITION_HAS_BIT:
return (($condition_value & $field_value) === (int)$condition_value);
case self::CONDITION_NOT_BIT:
return (($condition_value & $field_value) !== (int)$condition_value);
default:
throw new HeraldInvalidConditionException(
pht("Unknown condition '%s'.", $condition_type));
}
}
public function willSaveCondition(HeraldCondition $condition) {
$condition_type = $condition->getFieldCondition();
$condition_value = $condition->getValue();
switch ($condition_type) {
case self::CONDITION_REGEXP:
$ok = @preg_match($condition_value, '');
if ($ok === false) {
throw new HeraldInvalidConditionException(
pht(
'The regular expression "%s" is not valid. Regular expressions '.
'must have enclosing characters (e.g. "@/path/to/file@", not '.
'"/path/to/file") and be syntactically correct.',
$condition_value));
}
break;
case self::CONDITION_REGEXP_PAIR:
$json = null;
try {
$json = phutil_json_decode($condition_value);
} catch (PhutilJSONParserException $ex) {
throw new HeraldInvalidConditionException(
pht(
'The regular expression pair "%s" is not valid JSON. Enter a '.
'valid JSON array with two elements.',
$condition_value));
}
if (count($json) != 2) {
throw new HeraldInvalidConditionException(
pht(
'The regular expression pair "%s" must have exactly two '.
'elements.',
$condition_value));
}
$key_regexp = array_shift($json);
$val_regexp = array_shift($json);
$key_ok = @preg_match($key_regexp, '');
if ($key_ok === false) {
throw new HeraldInvalidConditionException(
pht(
'The first regexp in the regexp pair, "%s", is not a valid '.
'regexp.',
$key_regexp));
}
$val_ok = @preg_match($val_regexp, '');
if ($val_ok === false) {
throw new HeraldInvalidConditionException(
pht(
'The second regexp in the regexp pair, "%s", is not a valid '.
'regexp.',
$val_regexp));
}
break;
case self::CONDITION_CONTAINS:
case self::CONDITION_NOT_CONTAINS:
case self::CONDITION_IS:
case self::CONDITION_IS_NOT:
case self::CONDITION_IS_ANY:
case self::CONDITION_IS_NOT_ANY:
case self::CONDITION_INCLUDE_ALL:
case self::CONDITION_INCLUDE_ANY:
case self::CONDITION_INCLUDE_NONE:
case self::CONDITION_IS_ME:
case self::CONDITION_IS_NOT_ME:
case self::CONDITION_RULE:
case self::CONDITION_NOT_RULE:
case self::CONDITION_EXISTS:
case self::CONDITION_NOT_EXISTS:
case self::CONDITION_UNCONDITIONALLY:
case self::CONDITION_NEVER:
case self::CONDITION_HAS_BIT:
case self::CONDITION_NOT_BIT:
case self::CONDITION_IS_TRUE:
case self::CONDITION_IS_FALSE:
// No explicit validation for these types, although there probably
// should be in some cases.
break;
default:
throw new HeraldInvalidConditionException(
pht(
'Unknown condition "%s"!',
$condition_type));
}
}
/* -( Actions )------------------------------------------------------------ */
public function getCustomActionsForRuleType($rule_type) {
$results = array();
foreach ($this->getCustomActions() as $custom_action) {
if ($custom_action->appliesToRuleType($rule_type)) {
$results[] = $custom_action;
}
}
return $results;
}
public function getActions($rule_type) {
$custom_actions = $this->getCustomActionsForRuleType($rule_type);
$custom_actions = mpull($custom_actions, 'getActionKey');
$actions = $custom_actions;
$object = $this->newObject();
if (($object instanceof PhabricatorProjectInterface)) {
if ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) {
$actions[] = self::ACTION_ADD_PROJECTS;
$actions[] = self::ACTION_REMOVE_PROJECTS;
}
}
return $actions;
}
public function getActionNameMap($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
$standard = array(
self::ACTION_NOTHING => pht('Do nothing'),
self::ACTION_ADD_CC => pht('Add emails to CC'),
self::ACTION_REMOVE_CC => pht('Remove emails from CC'),
self::ACTION_EMAIL => pht('Send an email to'),
self::ACTION_AUDIT => pht('Trigger an Audit by'),
self::ACTION_FLAG => pht('Mark with flag'),
self::ACTION_ASSIGN_TASK => pht('Assign task to'),
self::ACTION_ADD_PROJECTS => pht('Add projects'),
self::ACTION_REMOVE_PROJECTS => pht('Remove projects'),
self::ACTION_ADD_REVIEWERS => pht('Add reviewers'),
self::ACTION_ADD_BLOCKING_REVIEWERS => pht('Add blocking reviewers'),
self::ACTION_APPLY_BUILD_PLANS => pht('Run build plans'),
self::ACTION_REQUIRE_SIGNATURE => pht('Require legal signatures'),
self::ACTION_BLOCK => pht('Block change with message'),
);
break;
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
$standard = array(
self::ACTION_NOTHING => pht('Do nothing'),
self::ACTION_ADD_CC => pht('Add me to CC'),
self::ACTION_REMOVE_CC => pht('Remove me from CC'),
self::ACTION_EMAIL => pht('Send me an email'),
self::ACTION_AUDIT => pht('Trigger an Audit by me'),
self::ACTION_FLAG => pht('Mark with flag'),
self::ACTION_ASSIGN_TASK => pht('Assign task to me'),
self::ACTION_ADD_REVIEWERS => pht('Add me as a reviewer'),
self::ACTION_ADD_BLOCKING_REVIEWERS =>
pht('Add me as a blocking reviewer'),
);
break;
default:
throw new Exception(pht("Unknown rule type '%s'!", $rule_type));
}
$custom_actions = $this->getCustomActionsForRuleType($rule_type);
$standard += mpull($custom_actions, 'getActionName', 'getActionKey');
return $standard;
}
public function willSaveAction(
HeraldRule $rule,
HeraldAction $action) {
$target = $action->getTarget();
if (is_array($target)) {
$target = array_keys($target);
}
$author_phid = $rule->getAuthorPHID();
$rule_type = $rule->getRuleType();
if ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL) {
switch ($action->getAction()) {
case self::ACTION_EMAIL:
case self::ACTION_ADD_CC:
case self::ACTION_REMOVE_CC:
case self::ACTION_AUDIT:
case self::ACTION_ASSIGN_TASK:
case self::ACTION_ADD_REVIEWERS:
case self::ACTION_ADD_BLOCKING_REVIEWERS:
// For personal rules, force these actions to target the rule owner.
$target = array($author_phid);
break;
case self::ACTION_FLAG:
// Make sure flag color is valid; set to blue if not.
$color_map = PhabricatorFlagColor::getColorNameMap();
if (empty($color_map[$target])) {
$target = PhabricatorFlagColor::COLOR_BLUE;
}
break;
case self::ACTION_BLOCK:
case self::ACTION_NOTHING:
break;
default:
throw new HeraldInvalidActionException(
pht(
'Unrecognized action type "%s"!',
$action->getAction()));
}
}
$action->setTarget($target);
}
/* -( Values )------------------------------------------------------------- */
public function getValueTypeForFieldAndCondition($field, $condition) {
if ($this->isHeraldCustomKey($field)) {
$value_type = $this->getCustomFieldValueTypeForFieldAndCondition(
$field,
$condition);
if ($value_type !== null) {
return $value_type;
}
}
switch ($condition) {
case self::CONDITION_CONTAINS:
case self::CONDITION_NOT_CONTAINS:
case self::CONDITION_REGEXP:
case self::CONDITION_REGEXP_PAIR:
return self::VALUE_TEXT;
case self::CONDITION_IS:
case self::CONDITION_IS_NOT:
switch ($field) {
case self::FIELD_CONTENT_SOURCE:
return self::VALUE_CONTENT_SOURCE;
default:
return self::VALUE_TEXT;
}
break;
case self::CONDITION_IS_ANY:
case self::CONDITION_IS_NOT_ANY:
switch ($field) {
case self::FIELD_REPOSITORY:
return self::VALUE_REPOSITORY;
case self::FIELD_TASK_PRIORITY:
return self::VALUE_TASK_PRIORITY;
case self::FIELD_TASK_STATUS:
return self::VALUE_TASK_STATUS;
default:
return self::VALUE_USER;
}
break;
case self::CONDITION_INCLUDE_ALL:
case self::CONDITION_INCLUDE_ANY:
case self::CONDITION_INCLUDE_NONE:
switch ($field) {
case self::FIELD_REPOSITORY:
return self::VALUE_REPOSITORY;
case self::FIELD_CC:
return self::VALUE_EMAIL;
case self::FIELD_TAGS:
return self::VALUE_TAG;
case self::FIELD_AFFECTED_PACKAGE:
return self::VALUE_OWNERS_PACKAGE;
case self::FIELD_AUTHOR_PROJECTS:
case self::FIELD_PUSHER_PROJECTS:
case self::FIELD_PROJECTS:
case self::FIELD_REPOSITORY_PROJECTS:
return self::VALUE_PROJECT;
case self::FIELD_REVIEWERS:
return self::VALUE_USER_OR_PROJECT;
case self::FIELD_APPLICATION_EMAIL:
return self::VALUE_APPLICATION_EMAIL;
default:
return self::VALUE_USER;
}
break;
case self::CONDITION_IS_ME:
case self::CONDITION_IS_NOT_ME:
case self::CONDITION_EXISTS:
case self::CONDITION_NOT_EXISTS:
case self::CONDITION_UNCONDITIONALLY:
case self::CONDITION_NEVER:
case self::CONDITION_IS_TRUE:
case self::CONDITION_IS_FALSE:
return self::VALUE_NONE;
case self::CONDITION_RULE:
case self::CONDITION_NOT_RULE:
return self::VALUE_RULE;
default:
throw new Exception(pht("Unknown condition '%s'.", $condition));
}
}
public function getValueTypeForAction($action, $rule_type) {
$is_personal = ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL);
if ($is_personal) {
switch ($action) {
case self::ACTION_ADD_CC:
case self::ACTION_REMOVE_CC:
case self::ACTION_EMAIL:
case self::ACTION_NOTHING:
case self::ACTION_AUDIT:
case self::ACTION_ASSIGN_TASK:
case self::ACTION_ADD_REVIEWERS:
case self::ACTION_ADD_BLOCKING_REVIEWERS:
return self::VALUE_NONE;
case self::ACTION_FLAG:
return self::VALUE_FLAG_COLOR;
case self::ACTION_ADD_PROJECTS:
case self::ACTION_REMOVE_PROJECTS:
return self::VALUE_PROJECT;
}
} else {
switch ($action) {
case self::ACTION_ADD_CC:
case self::ACTION_REMOVE_CC:
case self::ACTION_EMAIL:
return self::VALUE_EMAIL;
case self::ACTION_NOTHING:
return self::VALUE_NONE;
case self::ACTION_ADD_PROJECTS:
case self::ACTION_REMOVE_PROJECTS:
return self::VALUE_PROJECT;
case self::ACTION_FLAG:
return self::VALUE_FLAG_COLOR;
case self::ACTION_ASSIGN_TASK:
return self::VALUE_USER;
case self::ACTION_AUDIT:
case self::ACTION_ADD_REVIEWERS:
case self::ACTION_ADD_BLOCKING_REVIEWERS:
return self::VALUE_USER_OR_PROJECT;
case self::ACTION_APPLY_BUILD_PLANS:
return self::VALUE_BUILD_PLAN;
case self::ACTION_REQUIRE_SIGNATURE:
return self::VALUE_LEGAL_DOCUMENTS;
case self::ACTION_BLOCK:
return self::VALUE_TEXT;
}
}
$custom_action = idx($this->getCustomActions(), $action);
if ($custom_action !== null) {
return $custom_action->getActionType();
}
throw new Exception(pht("Unknown or invalid action '%s'.", $action));
}
/* -( Repetition )--------------------------------------------------------- */
public function getRepetitionOptions() {
return array(
HeraldRepetitionPolicyConfig::EVERY,
);
}
public static function getAllAdapters() {
static $adapters;
if (!$adapters) {
$adapters = id(new PhutilSymbolLoader())
->setAncestorClass(__CLASS__)
->loadObjects();
$adapters = msort($adapters, 'getAdapterSortKey');
}
return $adapters;
}
public static function getAdapterForContentType($content_type) {
$adapters = self::getAllAdapters();
foreach ($adapters as $adapter) {
if ($adapter->getAdapterContentType() == $content_type) {
return $adapter;
}
}
throw new Exception(
pht(
'No adapter exists for Herald content type "%s".',
$content_type));
}
public static function getEnabledAdapterMap(PhabricatorUser $viewer) {
$map = array();
$adapters = self::getAllAdapters();
foreach ($adapters as $adapter) {
if (!$adapter->isAvailableToUser($viewer)) {
continue;
}
$type = $adapter->getAdapterContentType();
$name = $adapter->getAdapterContentName();
$map[$type] = $name;
}
return $map;
}
public function renderRuleAsText(
HeraldRule $rule,
PhabricatorHandleList $handles) {
require_celerity_resource('herald-css');
$icon = id(new PHUIIconView())
->setIconFont('fa-chevron-circle-right lightgreytext')
->addClass('herald-list-icon');
if ($rule->getMustMatchAll()) {
$match_text = pht('When all of these conditions are met:');
} else {
$match_text = pht('When any of these conditions are met:');
}
$match_title = phutil_tag(
'p',
array(
'class' => 'herald-list-description',
),
$match_text);
$match_list = array();
foreach ($rule->getConditions() as $condition) {
$match_list[] = phutil_tag(
'div',
array(
'class' => 'herald-list-item',
),
array(
$icon,
$this->renderConditionAsText($condition, $handles),
));
}
$integer_code_for_every = HeraldRepetitionPolicyConfig::toInt(
HeraldRepetitionPolicyConfig::EVERY);
if ($rule->getRepetitionPolicy() == $integer_code_for_every) {
$action_text =
pht('Take these actions every time this rule matches:');
} else {
$action_text =
pht('Take these actions the first time this rule matches:');
}
$action_title = phutil_tag(
'p',
array(
'class' => 'herald-list-description',
),
$action_text);
$action_list = array();
foreach ($rule->getActions() as $action) {
$action_list[] = phutil_tag(
'div',
array(
'class' => 'herald-list-item',
),
array(
$icon,
$this->renderActionAsText($action, $handles),
));
}
return array(
$match_title,
$match_list,
$action_title,
$action_list,
);
}
private function renderConditionAsText(
HeraldCondition $condition,
PhabricatorHandleList $handles) {
$field_type = $condition->getFieldName();
$default = $this->isHeraldCustomKey($field_type)
? pht('(Unknown Custom Field "%s")', $field_type)
: pht('(Unknown Field "%s")', $field_type);
$field_name = idx($this->getFieldNameMap(), $field_type, $default);
$condition_type = $condition->getFieldCondition();
$condition_name = idx($this->getConditionNameMap(), $condition_type);
$value = $this->renderConditionValueAsText($condition, $handles);
return hsprintf(' %s %s %s', $field_name, $condition_name, $value);
}
private function renderActionAsText(
HeraldAction $action,
PhabricatorHandleList $handles) {
$rule_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
$action_type = $action->getAction();
$default = $this->isHeraldCustomKey($action_type)
? pht('(Unknown Custom Action "%s") equals', $action_type)
: pht('(Unknown Action "%s") equals', $action_type);
$action_name = idx(
$this->getActionNameMap($rule_global),
$action_type,
$default);
$target = $this->renderActionTargetAsText($action, $handles);
return hsprintf(' %s %s', $action_name, $target);
}
private function renderConditionValueAsText(
HeraldCondition $condition,
PhabricatorHandleList $handles) {
$value = $condition->getValue();
if (!is_array($value)) {
$value = array($value);
}
switch ($condition->getFieldName()) {
case self::FIELD_TASK_PRIORITY:
$priority_map = ManiphestTaskPriority::getTaskPriorityMap();
foreach ($value as $index => $val) {
$name = idx($priority_map, $val);
if ($name) {
$value[$index] = $name;
}
}
break;
case self::FIELD_TASK_STATUS:
$status_map = ManiphestTaskStatus::getTaskStatusMap();
foreach ($value as $index => $val) {
$name = idx($status_map, $val);
if ($name) {
$value[$index] = $name;
}
}
break;
case HeraldPreCommitRefAdapter::FIELD_REF_CHANGE:
$change_map =
PhabricatorRepositoryPushLog::getHeraldChangeFlagConditionOptions();
foreach ($value as $index => $val) {
$name = idx($change_map, $val);
if ($name) {
$value[$index] = $name;
}
}
break;
default:
foreach ($value as $index => $val) {
$handle = $handles->getHandleIfExists($val);
if ($handle) {
$value[$index] = $handle->renderLink();
}
}
break;
}
$value = phutil_implode_html(', ', $value);
return $value;
}
private function renderActionTargetAsText(
HeraldAction $action,
PhabricatorHandleList $handles) {
$target = $action->getTarget();
if (!is_array($target)) {
$target = array($target);
}
foreach ($target as $index => $val) {
switch ($action->getAction()) {
case self::ACTION_FLAG:
$target[$index] = PhabricatorFlagColor::getColorName($val);
break;
default:
$handle = $handles->getHandleIfExists($val);
if ($handle) {
$target[$index] = $handle->renderLink();
}
break;
}
}
$target = phutil_implode_html(', ', $target);
return $target;
}
/**
* Given a @{class:HeraldRule}, this function extracts all the phids that
* we'll want to load as handles later.
*
* This function performs a somewhat hacky approach to figuring out what
* is and is not a phid - try to get the phid type and if the type is
* *not* unknown assume its a valid phid.
*
* Don't try this at home. Use more strongly typed data at home.
*
* Think of the children.
*/
public static function getHandlePHIDs(HeraldRule $rule) {
$phids = array($rule->getAuthorPHID());
foreach ($rule->getConditions() as $condition) {
$value = $condition->getValue();
if (!is_array($value)) {
$value = array($value);
}
foreach ($value as $val) {
if (phid_get_type($val) !=
PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) {
$phids[] = $val;
}
}
}
foreach ($rule->getActions() as $action) {
$target = $action->getTarget();
if (!is_array($target)) {
$target = array($target);
}
foreach ($target as $val) {
if (phid_get_type($val) !=
PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) {
$phids[] = $val;
}
}
}
if ($rule->isObjectRule()) {
$phids[] = $rule->getTriggerObjectPHID();
}
return $phids;
}
/* -( Custom Field Integration )------------------------------------------- */
/**
* Returns the prefix used to namespace Herald fields which are based on
* custom fields.
*
* @return string Key prefix.
* @task customfield
*/
private function getCustomKeyPrefix() {
return 'herald.custom/';
}
/**
* Determine if a field key is based on a custom field or a regular internal
* field.
*
* @param string Field key.
* @return bool True if the field key is based on a custom field.
* @task customfield
*/
private function isHeraldCustomKey($key) {
$prefix = $this->getCustomKeyPrefix();
return (strncmp($key, $prefix, strlen($prefix)) == 0);
}
/**
* Convert a custom field key into a Herald field key.
*
* @param string Custom field key.
* @return string Herald field key.
* @task customfield
*/
private function getHeraldKeyFromCustomKey($key) {
return $this->getCustomKeyPrefix().$key;
}
/**
* Get custom fields for this adapter, if appliable. This will either return
* a field list or `null` if the adapted object does not implement custom
* fields or the adapter does not support them.
*
* @return PhabricatorCustomFieldList|null List of fields, or `null`.
* @task customfield
*/
private function getCustomFields() {
if ($this->customFields === false) {
$this->customFields = null;
$template_object = $this->newObject();
if ($template_object instanceof PhabricatorCustomFieldInterface) {
$object = $this->getObject();
if (!$object) {
$object = $template_object;
}
$fields = PhabricatorCustomField::getObjectFields(
$object,
PhabricatorCustomField::ROLE_HERALD);
$fields->setViewer(PhabricatorUser::getOmnipotentUser());
$fields->readFieldsFromStorage($object);
$this->customFields = $fields;
}
}
return $this->customFields;
}
/**
* Get a custom field by Herald field key, or `null` if it does not exist
* or custom fields are not supported.
*
* @param string Herald field key.
* @return PhabricatorCustomField|null Matching field, if it exists.
* @task customfield
*/
private function getCustomField($herald_field_key) {
$fields = $this->getCustomFields();
if (!$fields) {
return null;
}
foreach ($fields->getFields() as $custom_field) {
$key = $custom_field->getFieldKey();
if ($this->getHeraldKeyFromCustomKey($key) == $herald_field_key) {
return $custom_field;
}
}
return null;
}
/**
* Get the field map for custom fields.
*
* @return map<string, string> Map of Herald field keys to field names.
* @task customfield
*/
private function getCustomFieldNameMap() {
$fields = $this->getCustomFields();
if (!$fields) {
return array();
}
$map = array();
foreach ($fields->getFields() as $field) {
$key = $field->getFieldKey();
$name = $field->getHeraldFieldName();
$map[$this->getHeraldKeyFromCustomKey($key)] = $name;
}
return $map;
}
/**
* Get the value for a custom field.
*
* @param string Herald field key.
* @return wild Custom field value.
* @task customfield
*/
private function getCustomFieldValue($field_key) {
$field = $this->getCustomField($field_key);
if (!$field) {
return null;
}
return $field->getHeraldFieldValue();
}
/**
* Get the Herald conditions for a custom field.
*
* @param string Herald field key.
* @return list<const> List of Herald conditions.
* @task customfield
*/
private function getCustomFieldConditions($field_key) {
$field = $this->getCustomField($field_key);
if (!$field) {
return array(
self::CONDITION_NEVER,
);
}
return $field->getHeraldFieldConditions();
}
/**
* Get the Herald value type for a custom field and condition.
*
* @param string Herald field key.
* @param const Herald condition constant.
* @return const|null Herald value type constant, or null to use the default.
* @task customfield
*/
private function getCustomFieldValueTypeForFieldAndCondition(
$field_key,
$condition) {
$field = $this->getCustomField($field_key);
if (!$field) {
return self::VALUE_NONE;
}
return $field->getHeraldFieldValueType($condition);
}
/* -( Applying Effects )--------------------------------------------------- */
/**
* @task apply
*/
protected function applyStandardEffect(HeraldEffect $effect) {
$action = $effect->getAction();
$rule_type = $effect->getRule()->getRuleType();
$supported = $this->getActions($rule_type);
$supported = array_fuse($supported);
if (empty($supported[$action])) {
return new HeraldApplyTranscript(
$effect,
false,
pht(
'Adapter "%s" does not support action "%s" for rule type "%s".',
get_class($this),
$action,
$rule_type));
}
switch ($action) {
case self::ACTION_ADD_PROJECTS:
case self::ACTION_REMOVE_PROJECTS:
return $this->applyProjectsEffect($effect);
case self::ACTION_FLAG:
return $this->applyFlagEffect($effect);
case self::ACTION_EMAIL:
return $this->applyEmailEffect($effect);
+ case self::ACTION_NOTHING:
+ return $this->applyNothingEffect($effect);
default:
break;
}
$result = $this->handleCustomHeraldEffect($effect);
if (!$result) {
return new HeraldApplyTranscript(
$effect,
false,
pht(
'No custom action exists to handle rule action "%s".',
$action));
}
return $result;
}
+ private function applyNothingEffect(HeraldEffect $effect) {
+ return new HeraldApplyTranscript(
+ $effect,
+ true,
+ pht('Did nothing.'));
+ }
/**
* @task apply
*/
private function applyProjectsEffect(HeraldEffect $effect) {
if ($effect->getAction() == self::ACTION_ADD_PROJECTS) {
$kind = '+';
} else {
$kind = '-';
}
$project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$project_phids = $effect->getTarget();
$xaction = $this->newTransaction()
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $project_type)
->setNewValue(
array(
$kind => array_fuse($project_phids),
));
$this->queueTransaction($xaction);
return new HeraldApplyTranscript(
$effect,
true,
pht('Added projects.'));
}
/**
* @task apply
*/
private function applyFlagEffect(HeraldEffect $effect) {
$phid = $this->getPHID();
$color = $effect->getTarget();
$rule = $effect->getRule();
$user = $rule->getAuthor();
$flag = PhabricatorFlagQuery::loadUserFlag($user, $phid);
if ($flag) {
return new HeraldApplyTranscript(
$effect,
false,
pht('Object already flagged.'));
}
$handle = id(new PhabricatorHandleQuery())
->setViewer($user)
->withPHIDs(array($phid))
->executeOne();
$flag = new PhabricatorFlag();
$flag->setOwnerPHID($user->getPHID());
$flag->setType($handle->getType());
$flag->setObjectPHID($handle->getPHID());
// TOOD: Should really be transcript PHID, but it doesn't exist yet.
$flag->setReasonPHID($user->getPHID());
$flag->setColor($color);
$flag->setNote(
pht('Flagged by Herald Rule "%s".', $rule->getName()));
$flag->save();
return new HeraldApplyTranscript(
$effect,
true,
pht('Added flag.'));
}
/**
* @task apply
*/
private function applyEmailEffect(HeraldEffect $effect) {
foreach ($effect->getTarget() as $phid) {
$this->emailPHIDs[$phid] = $phid;
// If this is a personal rule, we'll force delivery of a real email. This
// effect is stronger than notification preferences, so you get an actual
// email even if your preferences are set to "Notify" or "Ignore".
$rule = $effect->getRule();
if ($rule->isPersonalRule()) {
$this->forcedEmailPHIDs[$phid] = $phid;
}
}
return new HeraldApplyTranscript(
$effect,
true,
pht('Added mailable to mail targets.'));
}
}
diff --git a/src/applications/herald/adapter/HeraldCommitAdapter.php b/src/applications/herald/adapter/HeraldCommitAdapter.php
index e26da09ab4..f10b7f6ee0 100644
--- a/src/applications/herald/adapter/HeraldCommitAdapter.php
+++ b/src/applications/herald/adapter/HeraldCommitAdapter.php
@@ -1,541 +1,535 @@
<?php
final class HeraldCommitAdapter extends HeraldAdapter {
const FIELD_NEED_AUDIT_FOR_PACKAGE = 'need-audit-for-package';
const FIELD_REPOSITORY_AUTOCLOSE_BRANCH = 'repository-autoclose-branch';
protected $diff;
protected $revision;
protected $repository;
protected $commit;
protected $commitData;
private $commitDiff;
protected $addCCPHIDs = array();
protected $auditMap = array();
protected $buildPlans = array();
protected $affectedPaths;
protected $affectedRevision;
protected $affectedPackages;
protected $auditNeededPackages;
public function getAdapterApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
protected function newObject() {
return new PhabricatorRepositoryCommit();
}
public function getObject() {
return $this->commit;
}
public function getAdapterContentType() {
return 'commit';
}
public function getAdapterContentName() {
return pht('Commits');
}
public function getAdapterContentDescription() {
return pht(
"React to new commits appearing in tracked repositories.\n".
"Commit rules can send email, flag commits, trigger audits, ".
"and run build plans.");
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
return true;
default:
return false;
}
}
public function canTriggerOnObject($object) {
if ($object instanceof PhabricatorRepository) {
return true;
}
if ($object instanceof PhabricatorProject) {
return true;
}
return false;
}
public function getTriggerObjectPHIDs() {
return array_merge(
array(
$this->repository->getPHID(),
$this->getPHID(),
),
$this->repository->getProjectPHIDs());
}
public function explainValidTriggerObjects() {
return pht('This rule can trigger for **repositories** and **projects**.');
}
public function getFieldNameMap() {
return array(
self::FIELD_NEED_AUDIT_FOR_PACKAGE =>
pht('Affected packages that need audit'),
self::FIELD_REPOSITORY_AUTOCLOSE_BRANCH
=> pht('Commit is on closing branch'),
) + parent::getFieldNameMap();
}
public function getFields() {
return array_merge(
array(
self::FIELD_BODY,
self::FIELD_AUTHOR,
self::FIELD_COMMITTER,
self::FIELD_REVIEWER,
self::FIELD_REPOSITORY,
self::FIELD_REPOSITORY_PROJECTS,
self::FIELD_DIFF_FILE,
self::FIELD_DIFF_CONTENT,
self::FIELD_DIFF_ADDED_CONTENT,
self::FIELD_DIFF_REMOVED_CONTENT,
self::FIELD_DIFF_ENORMOUS,
self::FIELD_AFFECTED_PACKAGE,
self::FIELD_AFFECTED_PACKAGE_OWNER,
self::FIELD_NEED_AUDIT_FOR_PACKAGE,
self::FIELD_DIFFERENTIAL_REVISION,
self::FIELD_DIFFERENTIAL_ACCEPTED,
self::FIELD_DIFFERENTIAL_REVIEWERS,
self::FIELD_DIFFERENTIAL_CCS,
self::FIELD_BRANCHES,
self::FIELD_REPOSITORY_AUTOCLOSE_BRANCH,
),
parent::getFields());
}
public function getConditionsForField($field) {
switch ($field) {
case self::FIELD_NEED_AUDIT_FOR_PACKAGE:
return array(
self::CONDITION_INCLUDE_ANY,
self::CONDITION_INCLUDE_NONE,
);
case self::FIELD_REPOSITORY_AUTOCLOSE_BRANCH:
return array(
self::CONDITION_UNCONDITIONALLY,
);
}
return parent::getConditionsForField($field);
}
public function getActions($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_EMAIL,
self::ACTION_AUDIT,
self::ACTION_APPLY_BUILD_PLANS,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_EMAIL,
self::ACTION_FLAG,
self::ACTION_AUDIT,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
}
}
public function getValueTypeForFieldAndCondition($field, $condition) {
switch ($field) {
case self::FIELD_DIFFERENTIAL_CCS:
return self::VALUE_EMAIL;
case self::FIELD_NEED_AUDIT_FOR_PACKAGE:
return self::VALUE_OWNERS_PACKAGE;
}
return parent::getValueTypeForFieldAndCondition($field, $condition);
}
public static function newLegacyAdapter(
PhabricatorRepository $repository,
PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $commit_data) {
$object = new HeraldCommitAdapter();
$commit->attachRepository($repository);
$object->repository = $repository;
$object->commit = $commit;
$object->commitData = $commit_data;
return $object;
}
public function setCommit(PhabricatorRepositoryCommit $commit) {
$viewer = PhabricatorUser::getOmnipotentUser();
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withIDs(array($commit->getRepositoryID()))
->needProjectPHIDs(true)
->executeOne();
if (!$repository) {
throw new Exception(pht('Unable to load repository!'));
}
$data = id(new PhabricatorRepositoryCommitData())->loadOneWhere(
'commitID = %d',
$commit->getID());
if (!$data) {
throw new Exception(pht('Unable to load commit data!'));
}
$this->commit = clone $commit;
$this->commit->attachRepository($repository);
$this->commit->attachCommitData($data);
$this->repository = $repository;
$this->commitData = $data;
return $this;
}
public function getPHID() {
return $this->commit->getPHID();
}
public function getAddCCMap() {
return $this->addCCPHIDs;
}
public function getAuditMap() {
return $this->auditMap;
}
public function getBuildPlans() {
return $this->buildPlans;
}
public function getHeraldName() {
return
'r'.
$this->repository->getCallsign().
$this->commit->getCommitIdentifier();
}
public function loadAffectedPaths() {
if ($this->affectedPaths === null) {
$result = PhabricatorOwnerPathQuery::loadAffectedPaths(
$this->repository,
$this->commit,
PhabricatorUser::getOmnipotentUser());
$this->affectedPaths = $result;
}
return $this->affectedPaths;
}
public function loadAffectedPackages() {
if ($this->affectedPackages === null) {
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
$this->repository,
$this->loadAffectedPaths());
$this->affectedPackages = $packages;
}
return $this->affectedPackages;
}
public function loadAuditNeededPackage() {
if ($this->auditNeededPackages === null) {
$status_arr = array(
PhabricatorAuditStatusConstants::AUDIT_REQUIRED,
PhabricatorAuditStatusConstants::CONCERNED,
);
$requests = id(new PhabricatorRepositoryAuditRequest())
->loadAllWhere(
'commitPHID = %s AND auditStatus IN (%Ls)',
$this->commit->getPHID(),
$status_arr);
$packages = mpull($requests, 'getAuditorPHID');
$this->auditNeededPackages = $packages;
}
return $this->auditNeededPackages;
}
public function loadDifferentialRevision() {
if ($this->affectedRevision === null) {
$this->affectedRevision = false;
$data = $this->commitData;
$revision_id = $data->getCommitDetail('differential.revisionID');
if ($revision_id) {
// NOTE: The Herald rule owner might not actually have access to
// the revision, and can control which revision a commit is
// associated with by putting text in the commit message. However,
// the rules they can write against revisions don't actually expose
// anything interesting, so it seems reasonable to load unconditionally
// here.
$revision = id(new DifferentialRevisionQuery())
->withIDs(array($revision_id))
->setViewer(PhabricatorUser::getOmnipotentUser())
->needRelationships(true)
->needReviewerStatus(true)
->executeOne();
if ($revision) {
$this->affectedRevision = $revision;
}
}
}
return $this->affectedRevision;
}
public static function getEnormousByteLimit() {
return 1024 * 1024 * 1024; // 1GB
}
public static function getEnormousTimeLimit() {
return 60 * 15; // 15 Minutes
}
private function loadCommitDiff() {
$drequest = DiffusionRequest::newFromDictionary(
array(
'user' => PhabricatorUser::getOmnipotentUser(),
'repository' => $this->repository,
'commit' => $this->commit->getCommitIdentifier(),
));
$byte_limit = self::getEnormousByteLimit();
$raw = DiffusionQuery::callConduitWithDiffusionRequest(
PhabricatorUser::getOmnipotentUser(),
$drequest,
'diffusion.rawdiffquery',
array(
'commit' => $this->commit->getCommitIdentifier(),
'timeout' => self::getEnormousTimeLimit(),
'byteLimit' => $byte_limit,
'linesOfContext' => 0,
));
if (strlen($raw) >= $byte_limit) {
throw new Exception(
pht(
'The raw text of this change is enormous (larger than %d bytes). '.
'Herald can not process it.',
$byte_limit));
}
$parser = new ArcanistDiffParser();
$changes = $parser->parseDiff($raw);
$diff = DifferentialDiff::newEphemeralFromRawChanges(
$changes);
return $diff;
}
private function getDiffContent($type) {
if ($this->commitDiff === null) {
try {
$this->commitDiff = $this->loadCommitDiff();
} catch (Exception $ex) {
$this->commitDiff = $ex;
phlog($ex);
}
}
if ($this->commitDiff instanceof Exception) {
$ex = $this->commitDiff;
$ex_class = get_class($ex);
$ex_message = pht('Failed to load changes: %s', $ex->getMessage());
return array(
'<'.$ex_class.'>' => $ex_message,
);
}
$changes = $this->commitDiff->getChangesets();
$result = array();
foreach ($changes as $change) {
$lines = array();
foreach ($change->getHunks() as $hunk) {
switch ($type) {
case '-':
$lines[] = $hunk->makeOldFile();
break;
case '+':
$lines[] = $hunk->makeNewFile();
break;
case '*':
$lines[] = $hunk->makeChanges();
break;
default:
throw new Exception(pht("Unknown content selection '%s'!", $type));
}
}
$result[$change->getFilename()] = implode("\n", $lines);
}
return $result;
}
public function getHeraldField($field) {
$data = $this->commitData;
switch ($field) {
case self::FIELD_BODY:
return $data->getCommitMessage();
case self::FIELD_AUTHOR:
return $data->getCommitDetail('authorPHID');
case self::FIELD_COMMITTER:
return $data->getCommitDetail('committerPHID');
case self::FIELD_REVIEWER:
return $data->getCommitDetail('reviewerPHID');
case self::FIELD_DIFF_FILE:
return $this->loadAffectedPaths();
case self::FIELD_REPOSITORY:
return $this->repository->getPHID();
case self::FIELD_REPOSITORY_PROJECTS:
return $this->repository->getProjectPHIDs();
case self::FIELD_DIFF_CONTENT:
return $this->getDiffContent('*');
case self::FIELD_DIFF_ADDED_CONTENT:
return $this->getDiffContent('+');
case self::FIELD_DIFF_REMOVED_CONTENT:
return $this->getDiffContent('-');
case self::FIELD_DIFF_ENORMOUS:
$this->getDiffContent('*');
return ($this->commitDiff instanceof Exception);
case self::FIELD_AFFECTED_PACKAGE:
$packages = $this->loadAffectedPackages();
return mpull($packages, 'getPHID');
case self::FIELD_AFFECTED_PACKAGE_OWNER:
$packages = $this->loadAffectedPackages();
$owners = PhabricatorOwnersOwner::loadAllForPackages($packages);
return mpull($owners, 'getUserPHID');
case self::FIELD_NEED_AUDIT_FOR_PACKAGE:
return $this->loadAuditNeededPackage();
case self::FIELD_DIFFERENTIAL_REVISION:
$revision = $this->loadDifferentialRevision();
if (!$revision) {
return null;
}
return $revision->getID();
case self::FIELD_DIFFERENTIAL_ACCEPTED:
$revision = $this->loadDifferentialRevision();
if (!$revision) {
return null;
}
$status = $data->getCommitDetail(
'precommitRevisionStatus',
$revision->getStatus());
switch ($status) {
case ArcanistDifferentialRevisionStatus::ACCEPTED:
case ArcanistDifferentialRevisionStatus::CLOSED:
return $revision->getPHID();
}
return null;
case self::FIELD_DIFFERENTIAL_REVIEWERS:
$revision = $this->loadDifferentialRevision();
if (!$revision) {
return array();
}
return $revision->getReviewers();
case self::FIELD_DIFFERENTIAL_CCS:
$revision = $this->loadDifferentialRevision();
if (!$revision) {
return array();
}
return $revision->getCCPHIDs();
case self::FIELD_BRANCHES:
$params = array(
'callsign' => $this->repository->getCallsign(),
'contains' => $this->commit->getCommitIdentifier(),
);
$result = id(new ConduitCall('diffusion.branchquery', $params))
->setUser(PhabricatorUser::getOmnipotentUser())
->execute();
$refs = DiffusionRepositoryRef::loadAllFromDictionaries($result);
return mpull($refs, 'getShortName');
case self::FIELD_REPOSITORY_AUTOCLOSE_BRANCH:
return $this->repository->shouldAutocloseCommit($this->commit);
}
return parent::getHeraldField($field);
}
public function applyHeraldEffects(array $effects) {
assert_instances_of($effects, 'HeraldEffect');
$result = array();
foreach ($effects as $effect) {
$action = $effect->getAction();
switch ($action) {
- case self::ACTION_NOTHING:
- $result[] = new HeraldApplyTranscript(
- $effect,
- true,
- pht('Great success at doing nothing.'));
- break;
case self::ACTION_ADD_CC:
foreach ($effect->getTarget() as $phid) {
if (empty($this->addCCPHIDs[$phid])) {
$this->addCCPHIDs[$phid] = array();
}
$this->addCCPHIDs[$phid][] = $effect->getRule()->getID();
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added address to CC.'));
break;
case self::ACTION_AUDIT:
foreach ($effect->getTarget() as $phid) {
if (empty($this->auditMap[$phid])) {
$this->auditMap[$phid] = array();
}
$this->auditMap[$phid][] = $effect->getRule()->getID();
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Triggered an audit.'));
break;
case self::ACTION_APPLY_BUILD_PLANS:
foreach ($effect->getTarget() as $phid) {
$this->buildPlans[] = $phid;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Applied build plans.'));
break;
default:
$result[] = $this->applyStandardEffect($effect);
break;
}
}
return $result;
}
}
diff --git a/src/applications/herald/adapter/HeraldDifferentialDiffAdapter.php b/src/applications/herald/adapter/HeraldDifferentialDiffAdapter.php
index 2a7a576e3e..c4c6587167 100644
--- a/src/applications/herald/adapter/HeraldDifferentialDiffAdapter.php
+++ b/src/applications/herald/adapter/HeraldDifferentialDiffAdapter.php
@@ -1,167 +1,159 @@
<?php
final class HeraldDifferentialDiffAdapter extends HeraldDifferentialAdapter {
public function getAdapterApplicationClass() {
return 'PhabricatorDifferentialApplication';
}
protected function loadChangesets() {
return $this->loadChangesetsWithHunks();
}
protected function loadChangesetsWithHunks() {
return $this->getDiff()->getChangesets();
}
public function getObject() {
return $this->getDiff();
}
public function getAdapterContentType() {
return 'differential.diff';
}
public function getAdapterContentName() {
return pht('Differential Diffs');
}
public function getAdapterContentDescription() {
return pht(
"React to new diffs being uploaded, before writes occur.\n".
"These rules can reject diffs before they are written to permanent ".
"storage, to prevent users from accidentally uploading private keys or ".
"other sensitive information.");
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
return true;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
default:
return false;
}
}
public function getFields() {
return array_merge(
array(
self::FIELD_AUTHOR,
self::FIELD_AUTHOR_PROJECTS,
self::FIELD_REPOSITORY,
self::FIELD_REPOSITORY_PROJECTS,
self::FIELD_DIFF_FILE,
self::FIELD_DIFF_CONTENT,
self::FIELD_DIFF_ADDED_CONTENT,
self::FIELD_DIFF_REMOVED_CONTENT,
),
parent::getFields());
}
public function getRepetitionOptions() {
return array(
HeraldRepetitionPolicyConfig::FIRST,
);
}
public function getPHID() {
return $this->getObject()->getPHID();
}
public function getHeraldName() {
return pht('New Diff');
}
public function getActionNameMap($rule_type) {
return array(
self::ACTION_BLOCK => pht('Block diff with message'),
- );
+ ) + parent::getActionNameMap($rule_type);
}
public function getHeraldField($field) {
switch ($field) {
case self::FIELD_AUTHOR:
return $this->getObject()->getAuthorPHID();
break;
case self::FIELD_AUTHOR_PROJECTS:
$author_phid = $this->getHeraldField(self::FIELD_AUTHOR);
if (!$author_phid) {
return array();
}
$projects = id(new PhabricatorProjectQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withMemberPHIDs(array($author_phid))
->execute();
return mpull($projects, 'getPHID');
case self::FIELD_DIFF_FILE:
return $this->loadAffectedPaths();
case self::FIELD_REPOSITORY:
$repository = $this->loadRepository();
if (!$repository) {
return null;
}
return $repository->getPHID();
case self::FIELD_REPOSITORY_PROJECTS:
$repository = $this->loadRepository();
if (!$repository) {
return array();
}
return $repository->getProjectPHIDs();
case self::FIELD_DIFF_CONTENT:
return $this->loadContentDictionary();
case self::FIELD_DIFF_ADDED_CONTENT:
return $this->loadAddedContentDictionary();
case self::FIELD_DIFF_REMOVED_CONTENT:
return $this->loadRemovedContentDictionary();
}
return parent::getHeraldField($field);
}
public function getActions($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
return array_merge(
array(
self::ACTION_BLOCK,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
}
}
public function applyHeraldEffects(array $effects) {
assert_instances_of($effects, 'HeraldEffect');
$result = array();
foreach ($effects as $effect) {
$action = $effect->getAction();
switch ($action) {
- case self::ACTION_NOTHING:
- $result[] = new HeraldApplyTranscript(
- $effect,
- true,
- pht('Did nothing.'));
- break;
case self::ACTION_BLOCK:
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Blocked diff.'));
break;
default:
- $result[] = new HeraldApplyTranscript(
- $effect,
- false,
- pht('No rules to handle action "%s"!', $action));
+ $result[] = $this->applyStandardEffect($effect);
+ break;
}
}
return $result;
}
}
diff --git a/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php b/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php
index 76fffac1b4..0ccd53d8cb 100644
--- a/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php
+++ b/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php
@@ -1,392 +1,386 @@
<?php
final class HeraldDifferentialRevisionAdapter
extends HeraldDifferentialAdapter {
protected $revision;
protected $explicitReviewers;
protected $forbiddenCCs;
protected $newCCs = array();
protected $remCCs = array();
protected $addReviewerPHIDs = array();
protected $blockingReviewerPHIDs = array();
protected $buildPlans = array();
protected $requiredSignatureDocumentPHIDs = array();
protected $affectedPackages;
protected $changesets;
private $haveHunks;
public function getAdapterApplicationClass() {
return 'PhabricatorDifferentialApplication';
}
protected function newObject() {
return new DifferentialRevision();
}
public function getObject() {
return $this->revision;
}
public function getDiff() {
return $this->diff;
}
public function getAdapterContentType() {
return 'differential';
}
public function getAdapterContentName() {
return pht('Differential Revisions');
}
public function getAdapterContentDescription() {
return pht(
"React to revisions being created or updated.\n".
"Revision rules can send email, flag revisions, add reviewers, ".
"and run build plans.");
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return true;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
default:
return false;
}
}
public function getFields() {
return array_merge(
array(
self::FIELD_TITLE,
self::FIELD_BODY,
self::FIELD_AUTHOR,
self::FIELD_AUTHOR_PROJECTS,
self::FIELD_REVIEWERS,
self::FIELD_CC,
self::FIELD_REPOSITORY,
self::FIELD_REPOSITORY_PROJECTS,
self::FIELD_DIFF_FILE,
self::FIELD_DIFF_CONTENT,
self::FIELD_DIFF_ADDED_CONTENT,
self::FIELD_DIFF_REMOVED_CONTENT,
self::FIELD_AFFECTED_PACKAGE,
self::FIELD_AFFECTED_PACKAGE_OWNER,
self::FIELD_IS_NEW_OBJECT,
),
parent::getFields());
}
public function getRepetitionOptions() {
return array(
HeraldRepetitionPolicyConfig::EVERY,
HeraldRepetitionPolicyConfig::FIRST,
);
}
public static function newLegacyAdapter(
DifferentialRevision $revision,
DifferentialDiff $diff) {
$object = new HeraldDifferentialRevisionAdapter();
// Reload the revision to pick up relationship information.
$revision = id(new DifferentialRevisionQuery())
->withIDs(array($revision->getID()))
->setViewer(PhabricatorUser::getOmnipotentUser())
->needRelationships(true)
->needReviewerStatus(true)
->executeOne();
$object->revision = $revision;
$object->diff = $diff;
return $object;
}
public function setExplicitReviewers($explicit_reviewers) {
$this->explicitReviewers = $explicit_reviewers;
return $this;
}
public function setForbiddenCCs($forbidden_ccs) {
$this->forbiddenCCs = $forbidden_ccs;
return $this;
}
public function getCCsAddedByHerald() {
return array_diff_key($this->newCCs, $this->remCCs);
}
public function getCCsRemovedByHerald() {
return $this->remCCs;
}
public function getReviewersAddedByHerald() {
return $this->addReviewerPHIDs;
}
public function getBlockingReviewersAddedByHerald() {
return $this->blockingReviewerPHIDs;
}
public function getRequiredSignatureDocumentPHIDs() {
return $this->requiredSignatureDocumentPHIDs;
}
public function getBuildPlans() {
return $this->buildPlans;
}
public function getPHID() {
return $this->revision->getPHID();
}
public function getHeraldName() {
return $this->revision->getTitle();
}
protected function loadChangesets() {
if ($this->changesets === null) {
$this->changesets = $this->diff->loadChangesets();
}
return $this->changesets;
}
protected function loadChangesetsWithHunks() {
$changesets = $this->loadChangesets();
if ($changesets && !$this->haveHunks) {
$this->haveHunks = true;
id(new DifferentialHunkQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withChangesets($changesets)
->needAttachToChangesets(true)
->execute();
}
return $changesets;
}
public function loadAffectedPackages() {
if ($this->affectedPackages === null) {
$this->affectedPackages = array();
$repository = $this->loadRepository();
if ($repository) {
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
$repository,
$this->loadAffectedPaths());
$this->affectedPackages = $packages;
}
}
return $this->affectedPackages;
}
public function getHeraldField($field) {
switch ($field) {
case self::FIELD_TITLE:
return $this->revision->getTitle();
break;
case self::FIELD_BODY:
return $this->revision->getSummary()."\n".
$this->revision->getTestPlan();
break;
case self::FIELD_AUTHOR:
return $this->revision->getAuthorPHID();
break;
case self::FIELD_AUTHOR_PROJECTS:
$author_phid = $this->revision->getAuthorPHID();
if (!$author_phid) {
return array();
}
$projects = id(new PhabricatorProjectQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withMemberPHIDs(array($author_phid))
->execute();
return mpull($projects, 'getPHID');
case self::FIELD_DIFF_FILE:
return $this->loadAffectedPaths();
case self::FIELD_REVIEWERS:
if (isset($this->explicitReviewers)) {
return array_keys($this->explicitReviewers);
} else {
return $this->revision->getReviewers();
}
case self::FIELD_REPOSITORY:
$repository = $this->loadRepository();
if (!$repository) {
return null;
}
return $repository->getPHID();
case self::FIELD_REPOSITORY_PROJECTS:
$repository = $this->loadRepository();
if (!$repository) {
return array();
}
return $repository->getProjectPHIDs();
case self::FIELD_DIFF_CONTENT:
return $this->loadContentDictionary();
case self::FIELD_DIFF_ADDED_CONTENT:
return $this->loadAddedContentDictionary();
case self::FIELD_DIFF_REMOVED_CONTENT:
return $this->loadRemovedContentDictionary();
case self::FIELD_AFFECTED_PACKAGE:
$packages = $this->loadAffectedPackages();
return mpull($packages, 'getPHID');
case self::FIELD_AFFECTED_PACKAGE_OWNER:
$packages = $this->loadAffectedPackages();
return PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(
mpull($packages, 'getID'));
}
return parent::getHeraldField($field);
}
public function getActions($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_REMOVE_CC,
self::ACTION_EMAIL,
self::ACTION_ADD_REVIEWERS,
self::ACTION_ADD_BLOCKING_REVIEWERS,
self::ACTION_APPLY_BUILD_PLANS,
self::ACTION_REQUIRE_SIGNATURE,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_REMOVE_CC,
self::ACTION_EMAIL,
self::ACTION_FLAG,
self::ACTION_ADD_REVIEWERS,
self::ACTION_ADD_BLOCKING_REVIEWERS,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
}
}
public function applyHeraldEffects(array $effects) {
assert_instances_of($effects, 'HeraldEffect');
$result = array();
$forbidden_ccs = array_fill_keys(
nonempty($this->forbiddenCCs, array()),
true);
foreach ($effects as $effect) {
$action = $effect->getAction();
switch ($action) {
- case self::ACTION_NOTHING:
- $result[] = new HeraldApplyTranscript(
- $effect,
- true,
- pht('OK, did nothing.'));
- break;
case self::ACTION_ADD_CC:
$base_target = $effect->getTarget();
$forbidden = array();
foreach ($base_target as $key => $fbid) {
if (isset($forbidden_ccs[$fbid])) {
$forbidden[] = $fbid;
unset($base_target[$key]);
} else {
$this->newCCs[$fbid] = true;
}
}
if ($forbidden) {
$failed = clone $effect;
$failed->setTarget($forbidden);
if ($base_target) {
$effect->setTarget($base_target);
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht(
'Added these addresses to CC list. '.
'Others could not be added.'));
}
$result[] = new HeraldApplyTranscript(
$failed,
false,
pht('CC forbidden, these addresses have unsubscribed.'));
} else {
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added addresses to CC list.'));
}
break;
case self::ACTION_REMOVE_CC:
foreach ($effect->getTarget() as $fbid) {
$this->remCCs[$fbid] = true;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Removed addresses from CC list.'));
break;
case self::ACTION_ADD_REVIEWERS:
foreach ($effect->getTarget() as $phid) {
$this->addReviewerPHIDs[$phid] = true;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added reviewers.'));
break;
case self::ACTION_ADD_BLOCKING_REVIEWERS:
// This adds reviewers normally, it just also marks them blocking.
foreach ($effect->getTarget() as $phid) {
$this->addReviewerPHIDs[$phid] = true;
$this->blockingReviewerPHIDs[$phid] = true;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added blocking reviewers.'));
break;
case self::ACTION_APPLY_BUILD_PLANS:
foreach ($effect->getTarget() as $phid) {
$this->buildPlans[] = $phid;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Applied build plans.'));
break;
case self::ACTION_REQUIRE_SIGNATURE:
foreach ($effect->getTarget() as $phid) {
$this->requiredSignatureDocumentPHIDs[] = $phid;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Required signatures.'));
break;
default:
$result[] = $this->applyStandardEffect($effect);
break;
}
}
return $result;
}
}
diff --git a/src/applications/herald/adapter/HeraldManiphestTaskAdapter.php b/src/applications/herald/adapter/HeraldManiphestTaskAdapter.php
index 4f7510199c..300f4eef1c 100644
--- a/src/applications/herald/adapter/HeraldManiphestTaskAdapter.php
+++ b/src/applications/herald/adapter/HeraldManiphestTaskAdapter.php
@@ -1,183 +1,177 @@
<?php
final class HeraldManiphestTaskAdapter extends HeraldAdapter {
private $task;
private $ccPHIDs = array();
private $assignPHID;
protected function newObject() {
return new ManiphestTask();
}
public function getAdapterApplicationClass() {
return 'PhabricatorManiphestApplication';
}
public function getAdapterContentDescription() {
return pht('React to tasks being created or updated.');
}
public function getRepetitionOptions() {
return array(
HeraldRepetitionPolicyConfig::EVERY,
HeraldRepetitionPolicyConfig::FIRST,
);
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return true;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
default:
return false;
}
}
public function setTask(ManiphestTask $task) {
$this->task = $task;
return $this;
}
public function getTask() {
return $this->task;
}
public function getObject() {
return $this->task;
}
private function setCcPHIDs(array $cc_phids) {
$this->ccPHIDs = $cc_phids;
return $this;
}
public function getCcPHIDs() {
return $this->ccPHIDs;
}
public function setAssignPHID($assign_phid) {
$this->assignPHID = $assign_phid;
return $this;
}
public function getAssignPHID() {
return $this->assignPHID;
}
public function getAdapterContentName() {
return pht('Maniphest Tasks');
}
public function getFields() {
return array_merge(
array(
self::FIELD_TITLE,
self::FIELD_BODY,
self::FIELD_AUTHOR,
self::FIELD_ASSIGNEE,
self::FIELD_CC,
self::FIELD_CONTENT_SOURCE,
self::FIELD_PROJECTS,
self::FIELD_TASK_PRIORITY,
self::FIELD_TASK_STATUS,
self::FIELD_IS_NEW_OBJECT,
self::FIELD_APPLICATION_EMAIL,
),
parent::getFields());
}
public function getActions($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_EMAIL,
self::ACTION_ASSIGN_TASK,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_EMAIL,
self::ACTION_FLAG,
self::ACTION_ASSIGN_TASK,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
}
}
public function getPHID() {
return $this->getTask()->getPHID();
}
public function getHeraldName() {
return 'T'.$this->getTask()->getID();
}
public function getHeraldField($field) {
switch ($field) {
case self::FIELD_TITLE:
return $this->getTask()->getTitle();
case self::FIELD_BODY:
return $this->getTask()->getDescription();
case self::FIELD_AUTHOR:
return $this->getTask()->getAuthorPHID();
case self::FIELD_ASSIGNEE:
return $this->getTask()->getOwnerPHID();
case self::FIELD_PROJECTS:
return PhabricatorEdgeQuery::loadDestinationPHIDs(
$this->getTask()->getPHID(),
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
case self::FIELD_TASK_PRIORITY:
return $this->getTask()->getPriority();
case self::FIELD_TASK_STATUS:
return $this->getTask()->getStatus();
}
return parent::getHeraldField($field);
}
public function applyHeraldEffects(array $effects) {
assert_instances_of($effects, 'HeraldEffect');
$result = array();
foreach ($effects as $effect) {
$action = $effect->getAction();
switch ($action) {
- case self::ACTION_NOTHING:
- $result[] = new HeraldApplyTranscript(
- $effect,
- true,
- pht('Great success at doing nothing.'));
- break;
case self::ACTION_ADD_CC:
foreach ($effect->getTarget() as $phid) {
$this->ccPHIDs[] = $phid;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added addresses to cc list.'));
break;
case self::ACTION_ASSIGN_TASK:
$target_array = $effect->getTarget();
$assign_phid = reset($target_array);
$this->setAssignPHID($assign_phid);
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Assigned task.'));
break;
default:
$result[] = $this->applyStandardEffect($effect);
break;
}
}
return $result;
}
}
diff --git a/src/applications/herald/adapter/HeraldPholioMockAdapter.php b/src/applications/herald/adapter/HeraldPholioMockAdapter.php
index 1b156c1751..a96deb8f5b 100644
--- a/src/applications/herald/adapter/HeraldPholioMockAdapter.php
+++ b/src/applications/herald/adapter/HeraldPholioMockAdapter.php
@@ -1,143 +1,137 @@
<?php
final class HeraldPholioMockAdapter extends HeraldAdapter {
private $mock;
private $ccPHIDs = array();
public function getAdapterApplicationClass() {
return 'PhabricatorPholioApplication';
}
public function getAdapterContentDescription() {
return pht('React to mocks being created or updated.');
}
protected function newObject() {
return new PholioMock();
}
public function getObject() {
return $this->mock;
}
public function setMock(PholioMock $mock) {
$this->mock = $mock;
return $this;
}
public function getMock() {
return $this->mock;
}
private function setCcPHIDs(array $cc_phids) {
$this->ccPHIDs = $cc_phids;
return $this;
}
public function getCcPHIDs() {
return $this->ccPHIDs;
}
public function getAdapterContentName() {
return pht('Pholio Mocks');
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return true;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
default:
return false;
}
}
public function getFields() {
return array_merge(
array(
self::FIELD_TITLE,
self::FIELD_BODY,
self::FIELD_AUTHOR,
self::FIELD_CC,
self::FIELD_PROJECTS,
self::FIELD_IS_NEW_OBJECT,
),
parent::getFields());
}
public function getActions($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_FLAG,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
}
}
public function getPHID() {
return $this->getMock()->getPHID();
}
public function getHeraldName() {
return 'M'.$this->getMock()->getID();
}
public function getHeraldField($field) {
switch ($field) {
case self::FIELD_TITLE:
return $this->getMock()->getName();
case self::FIELD_BODY:
return $this->getMock()->getDescription();
case self::FIELD_AUTHOR:
return $this->getMock()->getAuthorPHID();
case self::FIELD_PROJECTS:
return PhabricatorEdgeQuery::loadDestinationPHIDs(
$this->getMock()->getPHID(),
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
}
return parent::getHeraldField($field);
}
public function applyHeraldEffects(array $effects) {
assert_instances_of($effects, 'HeraldEffect');
$result = array();
foreach ($effects as $effect) {
$action = $effect->getAction();
switch ($action) {
- case self::ACTION_NOTHING:
- $result[] = new HeraldApplyTranscript(
- $effect,
- true,
- pht('Great success at doing nothing.'));
- break;
case self::ACTION_ADD_CC:
foreach ($effect->getTarget() as $phid) {
$this->ccPHIDs[] = $phid;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added address to cc list.'));
break;
default:
$result[] = $this->applyStandardEffect($effect);
break;
}
}
return $result;
}
}
diff --git a/src/applications/phriction/herald/PhrictionDocumentHeraldAdapter.php b/src/applications/phriction/herald/PhrictionDocumentHeraldAdapter.php
index 3e4fcaaed6..dd2f12f63b 100644
--- a/src/applications/phriction/herald/PhrictionDocumentHeraldAdapter.php
+++ b/src/applications/phriction/herald/PhrictionDocumentHeraldAdapter.php
@@ -1,144 +1,138 @@
<?php
final class PhrictionDocumentHeraldAdapter extends HeraldAdapter {
private $document;
private $ccPHIDs = array();
public function getAdapterApplicationClass() {
return 'PhabricatorPhrictionApplication';
}
public function getAdapterContentDescription() {
return pht('React to wiki documents being created or updated.');
}
protected function newObject() {
return new PhrictionDocument();
}
public function getObject() {
return $this->document;
}
public function setDocument(PhrictionDocument $document) {
$this->document = $document;
return $this;
}
public function getDocument() {
return $this->document;
}
private function setCcPHIDs(array $cc_phids) {
$this->ccPHIDs = $cc_phids;
return $this;
}
public function getCcPHIDs() {
return $this->ccPHIDs;
}
public function getAdapterContentName() {
return pht('Phriction Documents');
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return true;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
default:
return false;
}
}
public function getFields() {
return array_merge(
array(
self::FIELD_TITLE,
self::FIELD_BODY,
self::FIELD_AUTHOR,
self::FIELD_IS_NEW_OBJECT,
self::FIELD_CC,
self::FIELD_PATH,
),
parent::getFields());
}
public function getActions($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_EMAIL,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_EMAIL,
self::ACTION_FLAG,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
}
}
public function getPHID() {
return $this->getDocument()->getPHID();
}
public function getHeraldName() {
return pht('Wiki Document %d', $this->getDocument()->getID());
}
public function getHeraldField($field) {
switch ($field) {
case self::FIELD_TITLE:
return $this->getDocument()->getContent()->getTitle();
case self::FIELD_BODY:
return $this->getDocument()->getContent()->getContent();
case self::FIELD_AUTHOR:
return $this->getDocument()->getContent()->getAuthorPHID();
case self::FIELD_PATH:
return $this->getDocument()->getContent()->getSlug();
}
return parent::getHeraldField($field);
}
public function applyHeraldEffects(array $effects) {
assert_instances_of($effects, 'HeraldEffect');
$result = array();
foreach ($effects as $effect) {
$action = $effect->getAction();
switch ($action) {
- case self::ACTION_NOTHING:
- $result[] = new HeraldApplyTranscript(
- $effect,
- true,
- pht('Great success at doing nothing.'));
- break;
case self::ACTION_ADD_CC:
foreach ($effect->getTarget() as $phid) {
$this->ccPHIDs[] = $phid;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added address to cc list.'));
break;
default:
$result[] = $this->applyStandardEffect($effect);
break;
}
}
return $result;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Nov 30, 11:22 PM (9 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
429961
Default Alt Text
(186 KB)

Event Timeline