Page MenuHomestyx hydra

No OneTemporary

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
index dfcf236fe8..71384aae9f 100644
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -1,2411 +1,2419 @@
<?php
/**
* This file is automatically generated. Use 'bin/celerity map' to rebuild it.
*
* @generated
*/
return array(
'names' => array(
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => '3dc188c0',
'core.pkg.js' => '9ac8af68',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '67e02996',
'diffusion.pkg.css' => '42c75c37',
'diffusion.pkg.js' => 'a98c0bf7',
'maniphest.pkg.css' => '35995d6d',
'maniphest.pkg.js' => 'c9308721',
'rsrc/audio/basic/alert.mp3' => '17889334',
'rsrc/audio/basic/bing.mp3' => 'a817a0c3',
'rsrc/audio/basic/pock.mp3' => '0fa843d0',
'rsrc/audio/basic/tap.mp3' => '02d16994',
'rsrc/audio/basic/ting.mp3' => 'a6b6540e',
'rsrc/css/aphront/aphront-bars.css' => '4a327b4a',
'rsrc/css/aphront/dark-console.css' => '7f06cda2',
'rsrc/css/aphront/dialog-view.css' => 'b70c70df',
'rsrc/css/aphront/list-filter-view.css' => 'feb64255',
'rsrc/css/aphront/multi-column.css' => 'fbc00ba3',
'rsrc/css/aphront/notification.css' => '30240bd2',
'rsrc/css/aphront/panel-view.css' => '46923d46',
'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf',
'rsrc/css/aphront/table-view.css' => '5f13a9e4',
'rsrc/css/aphront/tokenizer.css' => 'b52d0668',
'rsrc/css/aphront/tooltip.css' => 'e3f2412f',
'rsrc/css/aphront/typeahead-browse.css' => 'b7ed02d2',
'rsrc/css/aphront/typeahead.css' => '8779483d',
'rsrc/css/application/almanac/almanac.css' => '2e050f4f',
'rsrc/css/application/auth/auth.css' => 'add92fd8',
'rsrc/css/application/base/main-menu-view.css' => '17b71bbc',
'rsrc/css/application/base/notification-menu.css' => '4df1ee30',
'rsrc/css/application/base/phui-theme.css' => '35883b37',
'rsrc/css/application/base/standard-page-view.css' => '8a295cb9',
'rsrc/css/application/chatlog/chatlog.css' => 'abdc76ee',
'rsrc/css/application/conduit/conduit-api.css' => 'ce2cfc41',
'rsrc/css/application/config/config-options.css' => '16c920ae',
'rsrc/css/application/config/config-template.css' => '20babf50',
'rsrc/css/application/config/setup-issue.css' => '5eed85b2',
'rsrc/css/application/config/unhandled-exception.css' => '9ecfc00d',
'rsrc/css/application/conpherence/color.css' => 'b17746b0',
'rsrc/css/application/conpherence/durable-column.css' => '2d57072b',
'rsrc/css/application/conpherence/header-pane.css' => 'c9a3db8e',
'rsrc/css/application/conpherence/menu.css' => '67f4680d',
'rsrc/css/application/conpherence/message-pane.css' => 'd244db1e',
'rsrc/css/application/conpherence/notification.css' => '6a3d4e58',
'rsrc/css/application/conpherence/participant-pane.css' => '69e0058a',
'rsrc/css/application/conpherence/transaction.css' => '3a3f5e7e',
'rsrc/css/application/contentsource/content-source-view.css' => 'cdf0d579',
'rsrc/css/application/countdown/timer.css' => 'bff8012f',
'rsrc/css/application/daemon/bulk-job.css' => '73af99f5',
'rsrc/css/application/dashboard/dashboard.css' => '5a205b9d',
'rsrc/css/application/diff/inline-comment-summary.css' => '81eb368d',
'rsrc/css/application/differential/add-comment.css' => '7e5900d9',
'rsrc/css/application/differential/changeset-view.css' => 'bde53589',
'rsrc/css/application/differential/core.css' => '7300a73e',
'rsrc/css/application/differential/phui-inline-comment.css' => '48acce5b',
'rsrc/css/application/differential/revision-comment.css' => '7dbc8d1d',
'rsrc/css/application/differential/revision-history.css' => '8aa3eac5',
'rsrc/css/application/differential/revision-list.css' => '93d2df7d',
'rsrc/css/application/differential/table-of-contents.css' => '0e3364c7',
'rsrc/css/application/diffusion/diffusion-icons.css' => '23b31a1b',
'rsrc/css/application/diffusion/diffusion-readme.css' => 'b68a76e4',
'rsrc/css/application/diffusion/diffusion-repository.css' => 'b89e8c6c',
'rsrc/css/application/diffusion/diffusion.css' => 'b54c77b0',
'rsrc/css/application/feed/feed.css' => 'd8b6e3f8',
'rsrc/css/application/files/global-drag-and-drop.css' => '1d2713a4',
'rsrc/css/application/flag/flag.css' => '2b77be8d',
'rsrc/css/application/harbormaster/harbormaster.css' => '8dfe16b2',
'rsrc/css/application/herald/herald-test.css' => 'e004176f',
'rsrc/css/application/herald/herald.css' => '648d39e2',
'rsrc/css/application/maniphest/report.css' => '3d53188b',
'rsrc/css/application/maniphest/task-edit.css' => '272daa84',
'rsrc/css/application/maniphest/task-summary.css' => '61d1667e',
'rsrc/css/application/objectselector/object-selector.css' => 'ee77366f',
'rsrc/css/application/owners/owners-path-editor.css' => 'fa7c13ef',
'rsrc/css/application/paste/paste.css' => 'b37bcd38',
'rsrc/css/application/people/people-picture-menu-item.css' => 'fe8e07cf',
'rsrc/css/application/people/people-profile.css' => '2ea2daa1',
'rsrc/css/application/phame/phame.css' => 'bb442327',
'rsrc/css/application/pholio/pholio-edit.css' => '4df55b3b',
'rsrc/css/application/pholio/pholio-inline-comments.css' => '722b48c2',
'rsrc/css/application/pholio/pholio.css' => '88ef5ef1',
'rsrc/css/application/phortune/phortune-credit-card-form.css' => '3b9868a8',
'rsrc/css/application/phortune/phortune-invoice.css' => '4436b241',
'rsrc/css/application/phortune/phortune.css' => '12e8251a',
'rsrc/css/application/phrequent/phrequent.css' => 'bd79cc67',
'rsrc/css/application/phriction/phriction-document-css.css' => '03380da0',
'rsrc/css/application/policy/policy-edit.css' => '8794e2ed',
'rsrc/css/application/policy/policy-transaction-detail.css' => 'c02b8384',
'rsrc/css/application/policy/policy.css' => 'ceb56a08',
'rsrc/css/application/ponder/ponder-view.css' => '05a09d0a',
'rsrc/css/application/project/project-card-view.css' => '4e7371cd',
'rsrc/css/application/project/project-triggers.css' => 'cd9c8bb9',
'rsrc/css/application/project/project-view.css' => '567858b3',
'rsrc/css/application/releeph/releeph-core.css' => 'f81ff2db',
'rsrc/css/application/releeph/releeph-preview-branch.css' => '22db5c07',
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '0ac1ea31',
'rsrc/css/application/releeph/releeph-request-typeahead.css' => 'bce37359',
'rsrc/css/application/search/application-search-view.css' => '0f7c06d8',
'rsrc/css/application/search/search-results.css' => '9ea70ace',
'rsrc/css/application/slowvote/slowvote.css' => '1694baed',
'rsrc/css/application/tokens/tokens.css' => 'ce5a50bd',
'rsrc/css/application/uiexample/example.css' => 'b4795059',
'rsrc/css/core/core.css' => '1b29ed61',
'rsrc/css/core/remarkup.css' => '9e627d41',
'rsrc/css/core/syntax.css' => '4234f572',
'rsrc/css/core/z-index.css' => '99c0f5eb',
'rsrc/css/diviner/diviner-shared.css' => '4bd263b0',
'rsrc/css/font/font-awesome.css' => '3883938a',
'rsrc/css/font/font-lato.css' => '23631304',
'rsrc/css/font/phui-font-icon-base.css' => 'd7994e06',
'rsrc/css/layout/phabricator-filetree-view.css' => '56cdd875',
'rsrc/css/layout/phabricator-source-code-view.css' => '03d7ac28',
'rsrc/css/phui/button/phui-button-bar.css' => 'a4aa75c4',
'rsrc/css/phui/button/phui-button-simple.css' => '1ff278aa',
'rsrc/css/phui/button/phui-button.css' => 'ea704902',
'rsrc/css/phui/calendar/phui-calendar-day.css' => '9597d706',
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'ccd7e4e2',
'rsrc/css/phui/calendar/phui-calendar-month.css' => 'cb758c42',
'rsrc/css/phui/calendar/phui-calendar.css' => 'f11073aa',
'rsrc/css/phui/object-item/phui-oi-big-ui.css' => 'fa74cc35',
'rsrc/css/phui/object-item/phui-oi-color.css' => 'b517bfa0',
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'da15d3dc',
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'd7723ecc',
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46',
'rsrc/css/phui/phui-action-list.css' => 'e820263c',
'rsrc/css/phui/phui-action-panel.css' => '6c386cbf',
'rsrc/css/phui/phui-badge.css' => '666e25ad',
'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d',
'rsrc/css/phui/phui-big-info-view.css' => '362ad37b',
'rsrc/css/phui/phui-box.css' => '5ed3b8cb',
'rsrc/css/phui/phui-bulk-editor.css' => '374d5e30',
'rsrc/css/phui/phui-chart.css' => '7853a69b',
'rsrc/css/phui/phui-cms.css' => '8c05c41e',
'rsrc/css/phui/phui-comment-form.css' => '68a2d99a',
'rsrc/css/phui/phui-comment-panel.css' => 'ec4e31c0',
'rsrc/css/phui/phui-crumbs-view.css' => '614f43cf',
'rsrc/css/phui/phui-curtain-view.css' => '68c5efb6',
'rsrc/css/phui/phui-document-pro.css' => 'b9613a10',
'rsrc/css/phui/phui-document-summary.css' => 'b068eed1',
'rsrc/css/phui/phui-document.css' => '52b748a5',
'rsrc/css/phui/phui-feed-story.css' => 'a0c05029',
'rsrc/css/phui/phui-fontkit.css' => '9b714a5e',
'rsrc/css/phui/phui-form-view.css' => '01b796c0',
'rsrc/css/phui/phui-form.css' => '159e2d9c',
'rsrc/css/phui/phui-head-thing.css' => 'd7f293df',
'rsrc/css/phui/phui-header-view.css' => '285c9139',
'rsrc/css/phui/phui-hovercard.css' => '6ca90fa0',
'rsrc/css/phui/phui-icon-set-selector.css' => '7aa5f3ec',
'rsrc/css/phui/phui-icon.css' => '4cbc684a',
'rsrc/css/phui/phui-image-mask.css' => '62c7f4d2',
'rsrc/css/phui/phui-info-view.css' => 'a10a909b',
'rsrc/css/phui/phui-invisible-character-view.css' => 'c694c4a4',
'rsrc/css/phui/phui-left-right.css' => '68513c34',
'rsrc/css/phui/phui-lightbox.css' => '4ebf22da',
'rsrc/css/phui/phui-list.css' => 'b05144dd',
'rsrc/css/phui/phui-object-box.css' => 'f434b6be',
'rsrc/css/phui/phui-pager.css' => 'd022c7ad',
'rsrc/css/phui/phui-pinboard-view.css' => '1f08f5d8',
'rsrc/css/phui/phui-property-list-view.css' => 'cad62236',
'rsrc/css/phui/phui-remarkup-preview.css' => '91767007',
'rsrc/css/phui/phui-segment-bar-view.css' => '5166b370',
'rsrc/css/phui/phui-spacing.css' => 'b05cadc3',
'rsrc/css/phui/phui-status.css' => 'e5ff8be0',
'rsrc/css/phui/phui-tag-view.css' => '8519160a',
'rsrc/css/phui/phui-timeline-view.css' => '1e348e4b',
'rsrc/css/phui/phui-two-column-view.css' => '01e6991e',
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'e86de308',
'rsrc/css/phui/workboards/phui-workboard.css' => '74fc9d98',
'rsrc/css/phui/workboards/phui-workcard.css' => '9e9eb0df',
'rsrc/css/phui/workboards/phui-workpanel.css' => '3ae89b20',
'rsrc/css/sprite-login.css' => '18b368a6',
'rsrc/css/sprite-tokens.css' => 'f1896dc5',
'rsrc/css/syntax/syntax-default.css' => '055fc231',
'rsrc/externals/d3/d3.min.js' => 'd67475f5',
'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '23f8c698',
'rsrc/externals/font/fontawesome/fontawesome-webfont.ttf' => '70983df0',
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => 'cd02f93b',
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff2' => '351fd46a',
'rsrc/externals/font/lato/lato-bold.eot' => '7367aa5e',
'rsrc/externals/font/lato/lato-bold.svg' => '681aa4f5',
'rsrc/externals/font/lato/lato-bold.ttf' => '66d3c296',
'rsrc/externals/font/lato/lato-bold.woff' => '89d9fba7',
'rsrc/externals/font/lato/lato-bold.woff2' => '389fcdb1',
'rsrc/externals/font/lato/lato-bolditalic.eot' => '03eeb4da',
'rsrc/externals/font/lato/lato-bolditalic.svg' => 'f56fa11c',
'rsrc/externals/font/lato/lato-bolditalic.ttf' => '9c3aec21',
'rsrc/externals/font/lato/lato-bolditalic.woff' => 'bfbd0616',
'rsrc/externals/font/lato/lato-bolditalic.woff2' => 'bc7d1274',
'rsrc/externals/font/lato/lato-italic.eot' => '7db5b247',
'rsrc/externals/font/lato/lato-italic.svg' => 'b1ae496f',
'rsrc/externals/font/lato/lato-italic.ttf' => '43eed813',
'rsrc/externals/font/lato/lato-italic.woff' => 'c28975e1',
'rsrc/externals/font/lato/lato-italic.woff2' => 'fffc0d8c',
'rsrc/externals/font/lato/lato-regular.eot' => '06e0c291',
'rsrc/externals/font/lato/lato-regular.svg' => '3ad95f53',
'rsrc/externals/font/lato/lato-regular.ttf' => 'e2e9c398',
'rsrc/externals/font/lato/lato-regular.woff' => '0b13d332',
'rsrc/externals/font/lato/lato-regular.woff2' => '8f846797',
'rsrc/externals/javelin/core/Event.js' => 'c03f2fb4',
'rsrc/externals/javelin/core/Stratcom.js' => '0889b835',
'rsrc/externals/javelin/core/__tests__/event-stop-and-kill.js' => '048472d2',
'rsrc/externals/javelin/core/__tests__/install.js' => '14a7e671',
'rsrc/externals/javelin/core/__tests__/stratcom.js' => 'a28464bb',
'rsrc/externals/javelin/core/__tests__/util.js' => 'e29a4354',
'rsrc/externals/javelin/core/init.js' => '98e6504a',
'rsrc/externals/javelin/core/init_node.js' => '16961339',
'rsrc/externals/javelin/core/install.js' => '5902260c',
'rsrc/externals/javelin/core/util.js' => 'edb4d8c9',
'rsrc/externals/javelin/docs/Base.js' => '5a401d7d',
'rsrc/externals/javelin/docs/onload.js' => 'ee58fb62',
'rsrc/externals/javelin/ext/fx/Color.js' => '78f811c9',
'rsrc/externals/javelin/ext/fx/FX.js' => '34450586',
'rsrc/externals/javelin/ext/reactor/core/DynVal.js' => '202a2e85',
'rsrc/externals/javelin/ext/reactor/core/Reactor.js' => '1c850a26',
'rsrc/externals/javelin/ext/reactor/core/ReactorNode.js' => '72960bc1',
'rsrc/externals/javelin/ext/reactor/core/ReactorNodeCalmer.js' => '225bbb98',
'rsrc/externals/javelin/ext/reactor/dom/RDOM.js' => '6cfa0008',
'rsrc/externals/javelin/ext/view/HTMLView.js' => 'f8c4e135',
'rsrc/externals/javelin/ext/view/View.js' => '289bf236',
'rsrc/externals/javelin/ext/view/ViewInterpreter.js' => '876506b6',
'rsrc/externals/javelin/ext/view/ViewPlaceholder.js' => 'a9942052',
'rsrc/externals/javelin/ext/view/ViewRenderer.js' => '9aae2b66',
'rsrc/externals/javelin/ext/view/ViewVisitor.js' => '308f9fe4',
'rsrc/externals/javelin/ext/view/__tests__/HTMLView.js' => '6e50a13f',
'rsrc/externals/javelin/ext/view/__tests__/View.js' => 'd284be5d',
'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => 'a9f35511',
'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '3a1b81f6',
'rsrc/externals/javelin/lib/Cookie.js' => '05d290ef',
'rsrc/externals/javelin/lib/DOM.js' => '94681e22',
'rsrc/externals/javelin/lib/History.js' => '030b4f7a',
'rsrc/externals/javelin/lib/JSON.js' => '541f81c3',
'rsrc/externals/javelin/lib/Leader.js' => '0d2490ce',
'rsrc/externals/javelin/lib/Mask.js' => '7c4d8998',
'rsrc/externals/javelin/lib/Quicksand.js' => 'd3799cb4',
'rsrc/externals/javelin/lib/Request.js' => '91863989',
'rsrc/externals/javelin/lib/Resource.js' => '740956e1',
'rsrc/externals/javelin/lib/Routable.js' => '6a18c42e',
'rsrc/externals/javelin/lib/Router.js' => '32755edb',
'rsrc/externals/javelin/lib/Scrollbar.js' => 'a43ae2ae',
'rsrc/externals/javelin/lib/Sound.js' => 'd4cc2d2a',
'rsrc/externals/javelin/lib/URI.js' => '2e255291',
'rsrc/externals/javelin/lib/Vector.js' => 'e9c80beb',
'rsrc/externals/javelin/lib/WebSocket.js' => 'fdc13e4e',
'rsrc/externals/javelin/lib/Workflow.js' => '958e9045',
'rsrc/externals/javelin/lib/__tests__/Cookie.js' => 'ca686f71',
'rsrc/externals/javelin/lib/__tests__/DOM.js' => '4566e249',
'rsrc/externals/javelin/lib/__tests__/JSON.js' => '710377ae',
'rsrc/externals/javelin/lib/__tests__/URI.js' => '6fff0c2b',
'rsrc/externals/javelin/lib/__tests__/behavior.js' => '8426ebeb',
'rsrc/externals/javelin/lib/behavior.js' => '1b6acc2a',
'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => '89a1ae3a',
'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => 'a4356cde',
'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => 'a241536a',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '22ee68a5',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '23387297',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '5a79f6c3',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '8badee71',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '80bff3af',
'rsrc/favicons/favicon-16x16.png' => '4c51a03a',
'rsrc/favicons/mask-icon.svg' => 'db699fe1',
'rsrc/image/BFCFDA.png' => '74b5c88b',
'rsrc/image/actions/edit.png' => 'fd987dff',
'rsrc/image/avatar.png' => '0d17c6c4',
'rsrc/image/checker_dark.png' => '7fc8fa7b',
'rsrc/image/checker_light.png' => '3157a202',
'rsrc/image/checker_lighter.png' => 'c45928c1',
'rsrc/image/chevron-in.png' => '1aa2f88f',
'rsrc/image/chevron-out.png' => 'c815e272',
'rsrc/image/controls/checkbox-checked.png' => '1770d7a0',
'rsrc/image/controls/checkbox-unchecked.png' => 'e1deba0a',
'rsrc/image/d5d8e1.png' => '6764616e',
'rsrc/image/darkload.gif' => '5bd41a89',
'rsrc/image/divot.png' => '0fbe2453',
'rsrc/image/examples/hero.png' => '5d8c4b21',
'rsrc/image/grippy_texture.png' => 'a7d222b5',
'rsrc/image/icon/fatcow/arrow_branch.png' => '98149d9f',
'rsrc/image/icon/fatcow/arrow_merge.png' => 'e142f4f8',
'rsrc/image/icon/fatcow/calendar_edit.png' => '5ff44a08',
'rsrc/image/icon/fatcow/document_black.png' => 'd3515fa5',
'rsrc/image/icon/fatcow/flag_blue.png' => '54db2e5c',
'rsrc/image/icon/fatcow/flag_finish.png' => '2953a51b',
'rsrc/image/icon/fatcow/flag_ghost.png' => '7d9ada92',
'rsrc/image/icon/fatcow/flag_green.png' => '010f7161',
'rsrc/image/icon/fatcow/flag_orange.png' => '6c384ca5',
'rsrc/image/icon/fatcow/flag_pink.png' => '11ac6b12',
'rsrc/image/icon/fatcow/flag_purple.png' => 'c4f423a4',
'rsrc/image/icon/fatcow/flag_red.png' => '9e6d8817',
'rsrc/image/icon/fatcow/flag_yellow.png' => '906733f4',
'rsrc/image/icon/fatcow/key_question.png' => 'c10c26db',
'rsrc/image/icon/fatcow/link.png' => '8edbf327',
'rsrc/image/icon/fatcow/page_white_edit.png' => '17ef5625',
'rsrc/image/icon/fatcow/page_white_put.png' => '82430c91',
'rsrc/image/icon/fatcow/source/conduit.png' => '5b55130c',
'rsrc/image/icon/fatcow/source/email.png' => '8a32b77f',
'rsrc/image/icon/fatcow/source/fax.png' => '8bc2a49b',
'rsrc/image/icon/fatcow/source/mobile.png' => '0a918412',
'rsrc/image/icon/fatcow/source/tablet.png' => 'fc50b050',
'rsrc/image/icon/fatcow/source/web.png' => '70433af3',
'rsrc/image/icon/subscribe.png' => '07ef454e',
'rsrc/image/icon/tango/attachment.png' => 'bac9032d',
'rsrc/image/icon/tango/edit.png' => 'e6296206',
'rsrc/image/icon/tango/go-down.png' => '0b903712',
'rsrc/image/icon/tango/log.png' => '86b6a6f4',
'rsrc/image/icon/tango/upload.png' => '3fe6b92d',
'rsrc/image/icon/unsubscribe.png' => 'db04378a',
'rsrc/image/lightblue-header.png' => 'e6d483c6',
'rsrc/image/logo/light-eye.png' => '72337472',
'rsrc/image/main_texture.png' => '894d03c4',
'rsrc/image/menu_texture.png' => '896c9ade',
'rsrc/image/people/harding.png' => '95b2db63',
'rsrc/image/people/jefferson.png' => 'e883a3a2',
'rsrc/image/people/lincoln.png' => 'be2c07c5',
'rsrc/image/people/mckinley.png' => '6af510a0',
'rsrc/image/people/taft.png' => 'b15ab07e',
'rsrc/image/people/user0.png' => '4bc64b40',
'rsrc/image/people/user1.png' => '8063f445',
'rsrc/image/people/user2.png' => 'd28246c0',
'rsrc/image/people/user3.png' => 'fb1ac12d',
'rsrc/image/people/user4.png' => 'fe4fac8f',
'rsrc/image/people/user5.png' => '3d07065c',
'rsrc/image/people/user6.png' => 'e4bd47c8',
'rsrc/image/people/user7.png' => '71d8fe8b',
'rsrc/image/people/user8.png' => '85f86bf7',
'rsrc/image/people/user9.png' => '523db8aa',
'rsrc/image/people/washington.png' => '86159e68',
'rsrc/image/phrequent_active.png' => 'de66dc50',
'rsrc/image/phrequent_inactive.png' => '79c61baf',
'rsrc/image/resize.png' => '9cc83373',
'rsrc/image/sprite-login-X2.png' => '604545f6',
'rsrc/image/sprite-login.png' => '7a001a9a',
'rsrc/image/sprite-tokens-X2.png' => '21621dd9',
'rsrc/image/sprite-tokens.png' => 'bede2580',
'rsrc/image/texture/card-gradient.png' => 'e6892cb4',
'rsrc/image/texture/dark-menu-hover.png' => '390a4fa1',
'rsrc/image/texture/dark-menu.png' => '542f699c',
'rsrc/image/texture/grip.png' => 'bc80753a',
'rsrc/image/texture/panel-header-gradient.png' => '65004dbf',
'rsrc/image/texture/phlnx-bg.png' => '6c9cd31d',
'rsrc/image/texture/pholio-background.gif' => '84910bfc',
'rsrc/image/texture/table_header.png' => '7652d1ad',
'rsrc/image/texture/table_header_hover.png' => '12ea5236',
'rsrc/image/texture/table_header_tall.png' => '5cc420c4',
'rsrc/js/application/aphlict/Aphlict.js' => '022516b4',
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'e9a2940f',
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '4e61fa88',
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'c3703a16',
'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => '070679fe',
'rsrc/js/application/calendar/behavior-day-view.js' => '727a5a61',
'rsrc/js/application/calendar/behavior-event-all-day.js' => '0b1bc990',
'rsrc/js/application/calendar/behavior-month-view.js' => '158c64e0',
'rsrc/js/application/config/behavior-reorder-fields.js' => '2539f834',
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => 'aec8e38c',
'rsrc/js/application/conpherence/behavior-conpherence-search.js' => '91befbcc',
'rsrc/js/application/conpherence/behavior-durable-column.js' => 'fa6f30b2',
'rsrc/js/application/conpherence/behavior-menu.js' => '8c2ed2bf',
'rsrc/js/application/conpherence/behavior-participant-pane.js' => '43ba89a2',
'rsrc/js/application/conpherence/behavior-pontificate.js' => '4ae58b5a',
'rsrc/js/application/conpherence/behavior-quicksand-blacklist.js' => '5a6f6a06',
'rsrc/js/application/conpherence/behavior-toggle-widget.js' => '8f959ad0',
'rsrc/js/application/countdown/timer.js' => '6a162524',
'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => '3829a3cf',
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '9c01e364',
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be',
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8',
'rsrc/js/application/diff/DiffChangeset.js' => 'd0a85a85',
'rsrc/js/application/diff/DiffChangesetList.js' => '04023d82',
'rsrc/js/application/diff/DiffInline.js' => 'a4a14a94',
'rsrc/js/application/diff/behavior-preview-link.js' => 'f51e9c17',
'rsrc/js/application/differential/behavior-diff-radios.js' => '925fe8cd',
'rsrc/js/application/differential/behavior-populate.js' => 'dfa1d313',
'rsrc/js/application/diffusion/DiffusionLocateFileSource.js' => '94243d89',
'rsrc/js/application/diffusion/behavior-audit-preview.js' => 'b7b73831',
'rsrc/js/application/diffusion/behavior-commit-branches.js' => '4b671572',
'rsrc/js/application/diffusion/behavior-commit-graph.js' => 'ef836bf2',
'rsrc/js/application/diffusion/behavior-locate-file.js' => '87428eb2',
'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'c715c123',
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '6a85bc5a',
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '47a0728b',
'rsrc/js/application/fact/Chart.js' => 'fcb0c07d',
'rsrc/js/application/files/behavior-document-engine.js' => '243d6c22',
'rsrc/js/application/files/behavior-icon-composer.js' => '38a6cedb',
'rsrc/js/application/files/behavior-launch-icon-composer.js' => 'a17b84f1',
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => 'b347a301',
'rsrc/js/application/herald/HeraldRuleEditor.js' => '27daef73',
'rsrc/js/application/herald/PathTypeahead.js' => 'ad486db3',
'rsrc/js/application/herald/herald-rule-editor.js' => '0922e81d',
'rsrc/js/application/maniphest/behavior-batch-selector.js' => '139ef688',
+ 'rsrc/js/application/maniphest/behavior-line-chart-legacy.js' => 'faf3ab6b',
'rsrc/js/application/maniphest/behavior-line-chart.js' => 'ad258e28',
'rsrc/js/application/maniphest/behavior-list-edit.js' => 'c687e867',
'rsrc/js/application/owners/OwnersPathEditor.js' => '2a8b62d9',
'rsrc/js/application/owners/owners-path-editor.js' => 'ff688a7a',
'rsrc/js/application/passphrase/passphrase-credential-control.js' => '48fe33d0',
'rsrc/js/application/pholio/behavior-pholio-mock-edit.js' => '3eed1f2b',
'rsrc/js/application/pholio/behavior-pholio-mock-view.js' => '5aa1544e',
'rsrc/js/application/phortune/behavior-stripe-payment-form.js' => '02cb4398',
'rsrc/js/application/phortune/behavior-test-payment-form.js' => '4a7fb02b',
'rsrc/js/application/phortune/phortune-credit-card-form.js' => 'd12d214f',
'rsrc/js/application/policy/behavior-policy-control.js' => '0eaa33a9',
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '9347f172',
'rsrc/js/application/projects/WorkboardBoard.js' => 'c02a5497',
'rsrc/js/application/projects/WorkboardCard.js' => '0392a5d8',
'rsrc/js/application/projects/WorkboardCardTemplate.js' => '2a61f8d4',
'rsrc/js/application/projects/WorkboardColumn.js' => 'c3d24e63',
'rsrc/js/application/projects/WorkboardController.js' => '42c7a5a7',
'rsrc/js/application/projects/WorkboardDropEffect.js' => '8e0aa661',
'rsrc/js/application/projects/WorkboardHeader.js' => '111bfd2d',
'rsrc/js/application/projects/WorkboardHeaderTemplate.js' => 'ebe83a6b',
'rsrc/js/application/projects/WorkboardOrderTemplate.js' => '03e8891f',
'rsrc/js/application/projects/behavior-project-boards.js' => 'aad45445',
'rsrc/js/application/projects/behavior-project-create.js' => '34c53422',
'rsrc/js/application/projects/behavior-reorder-columns.js' => '8ac32fd9',
'rsrc/js/application/releeph/releeph-preview-branch.js' => '75184d68',
'rsrc/js/application/releeph/releeph-request-state-change.js' => '9f081f05',
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'aa3a100c',
'rsrc/js/application/repository/repository-crossreference.js' => 'c15122b4',
'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e5bdb730',
'rsrc/js/application/search/behavior-reorder-queries.js' => 'b86f297f',
'rsrc/js/application/transactions/behavior-comment-actions.js' => '4dffaeb2',
'rsrc/js/application/transactions/behavior-reorder-configs.js' => '4842f137',
'rsrc/js/application/transactions/behavior-reorder-fields.js' => '0ad8d31f',
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '600f440c',
'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => '2bdadf1a',
'rsrc/js/application/transactions/behavior-transaction-list.js' => '9cec214e',
'rsrc/js/application/trigger/TriggerRule.js' => '41b7b4f6',
'rsrc/js/application/trigger/TriggerRuleControl.js' => '5faf27b9',
'rsrc/js/application/trigger/TriggerRuleEditor.js' => 'b49fd60c',
'rsrc/js/application/trigger/TriggerRuleType.js' => '4feea7d3',
'rsrc/js/application/trigger/trigger-rule-editor.js' => '398fdf13',
'rsrc/js/application/typeahead/behavior-typeahead-browse.js' => '70245195',
'rsrc/js/application/typeahead/behavior-typeahead-search.js' => '7b139193',
'rsrc/js/application/uiexample/gesture-example.js' => '242dedd0',
'rsrc/js/application/uiexample/notification-example.js' => '29819b75',
'rsrc/js/core/Busy.js' => '5202e831',
'rsrc/js/core/DragAndDropFileUpload.js' => '4370900d',
'rsrc/js/core/DraggableList.js' => 'c9ad6f70',
'rsrc/js/core/Favicon.js' => '7930776a',
'rsrc/js/core/FileUpload.js' => 'ab85e184',
'rsrc/js/core/Hovercard.js' => '074f0783',
'rsrc/js/core/KeyboardShortcut.js' => 'c9749dcd',
'rsrc/js/core/KeyboardShortcutManager.js' => '37b8a04a',
'rsrc/js/core/MultirowRowManager.js' => '5b54c823',
'rsrc/js/core/Notification.js' => 'a9b91e3f',
'rsrc/js/core/Prefab.js' => '5793d835',
'rsrc/js/core/ShapedRequest.js' => 'abf88db8',
'rsrc/js/core/TextAreaUtils.js' => 'f340a484',
'rsrc/js/core/Title.js' => '43bc9360',
'rsrc/js/core/ToolTip.js' => '83754533',
'rsrc/js/core/behavior-active-nav.js' => '7353f43d',
'rsrc/js/core/behavior-audio-source.js' => '3dc5ad43',
'rsrc/js/core/behavior-autofocus.js' => '65bb0011',
'rsrc/js/core/behavior-badge-view.js' => '92cdd7b6',
'rsrc/js/core/behavior-bulk-editor.js' => 'aa6d2308',
'rsrc/js/core/behavior-choose-control.js' => '04f8a1e3',
'rsrc/js/core/behavior-copy.js' => 'cf32921f',
'rsrc/js/core/behavior-detect-timezone.js' => '78bc5d94',
'rsrc/js/core/behavior-device.js' => '0cf79f45',
'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '7ad020a5',
'rsrc/js/core/behavior-fancy-datepicker.js' => '956f3eeb',
'rsrc/js/core/behavior-file-tree.js' => 'ee82cedb',
'rsrc/js/core/behavior-form.js' => '55d7b788',
'rsrc/js/core/behavior-gesture.js' => 'b58d1a2a',
'rsrc/js/core/behavior-global-drag-and-drop.js' => '1cab0e9a',
'rsrc/js/core/behavior-high-security-warning.js' => 'dae2d55b',
'rsrc/js/core/behavior-history-install.js' => '6a1583a8',
'rsrc/js/core/behavior-hovercard.js' => '6c379000',
'rsrc/js/core/behavior-keyboard-pager.js' => '1325b731',
'rsrc/js/core/behavior-keyboard-shortcuts.js' => '2cc87f49',
'rsrc/js/core/behavior-lightbox-attachments.js' => 'c7e748bf',
'rsrc/js/core/behavior-line-linker.js' => 'e15c8b1f',
'rsrc/js/core/behavior-linked-container.js' => '74446546',
'rsrc/js/core/behavior-more.js' => '506aa3f4',
'rsrc/js/core/behavior-object-selector.js' => 'a4af0b4a',
'rsrc/js/core/behavior-oncopy.js' => 'ff7b3f22',
'rsrc/js/core/behavior-phabricator-nav.js' => 'f166c949',
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '2f80333f',
'rsrc/js/core/behavior-read-only-warning.js' => 'b9109f8f',
'rsrc/js/core/behavior-redirect.js' => '407ee861',
'rsrc/js/core/behavior-refresh-csrf.js' => '46116c01',
'rsrc/js/core/behavior-remarkup-load-image.js' => '202bfa3f',
'rsrc/js/core/behavior-remarkup-preview.js' => 'd8a86cfb',
'rsrc/js/core/behavior-reorder-applications.js' => 'aa371860',
'rsrc/js/core/behavior-reveal-content.js' => 'b105a3a6',
'rsrc/js/core/behavior-scrollbar.js' => '92388bae',
'rsrc/js/core/behavior-search-typeahead.js' => '1cb7d027',
'rsrc/js/core/behavior-select-content.js' => 'e8240b50',
'rsrc/js/core/behavior-select-on-click.js' => '66365ee2',
'rsrc/js/core/behavior-setup-check-https.js' => '01384686',
'rsrc/js/core/behavior-time-typeahead.js' => '5803b9e7',
'rsrc/js/core/behavior-toggle-class.js' => '32db8374',
'rsrc/js/core/behavior-tokenizer.js' => '3b4899b0',
'rsrc/js/core/behavior-tooltip.js' => '73ecc1f8',
'rsrc/js/core/behavior-user-menu.js' => '60cd9241',
'rsrc/js/core/behavior-watch-anchor.js' => '0e6d261f',
'rsrc/js/core/behavior-workflow.js' => '9623adc1',
'rsrc/js/core/darkconsole/DarkLog.js' => '3b869402',
'rsrc/js/core/darkconsole/DarkMessage.js' => '26cd4b73',
'rsrc/js/core/darkconsole/behavior-dark-console.js' => 'f39d968b',
'rsrc/js/core/phtize.js' => '2f1db1ed',
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '5cf0501a',
'rsrc/js/phui/behavior-phui-file-upload.js' => 'e150bd50',
'rsrc/js/phui/behavior-phui-selectable-list.js' => 'b26a41e4',
'rsrc/js/phui/behavior-phui-submenu.js' => 'b5e9bff9',
'rsrc/js/phui/behavior-phui-tab-group.js' => '242aa08b',
'rsrc/js/phui/behavior-phui-timer-control.js' => 'f84bcbf4',
'rsrc/js/phuix/PHUIXActionListView.js' => 'c68f183f',
'rsrc/js/phuix/PHUIXActionView.js' => 'aaa08f3b',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '2fbe234d',
'rsrc/js/phuix/PHUIXButtonView.js' => '55a24e84',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '7acfd98b',
'rsrc/js/phuix/PHUIXExample.js' => 'c2c500a7',
'rsrc/js/phuix/PHUIXFormControl.js' => '38c1f3fb',
'rsrc/js/phuix/PHUIXIconView.js' => 'a5257c4e',
),
'symbols' => array(
'almanac-css' => '2e050f4f',
'aphront-bars' => '4a327b4a',
'aphront-dark-console-css' => '7f06cda2',
'aphront-dialog-view-css' => 'b70c70df',
'aphront-list-filter-view-css' => 'feb64255',
'aphront-multi-column-view-css' => 'fbc00ba3',
'aphront-panel-view-css' => '46923d46',
'aphront-table-view-css' => '5f13a9e4',
'aphront-tokenizer-control-css' => 'b52d0668',
'aphront-tooltip-css' => 'e3f2412f',
'aphront-typeahead-control-css' => '8779483d',
'application-search-view-css' => '0f7c06d8',
'auth-css' => 'add92fd8',
'bulk-job-css' => '73af99f5',
'conduit-api-css' => 'ce2cfc41',
'config-options-css' => '16c920ae',
'conpherence-color-css' => 'b17746b0',
'conpherence-durable-column-view' => '2d57072b',
'conpherence-header-pane-css' => 'c9a3db8e',
'conpherence-menu-css' => '67f4680d',
'conpherence-message-pane-css' => 'd244db1e',
'conpherence-notification-css' => '6a3d4e58',
'conpherence-participant-pane-css' => '69e0058a',
'conpherence-thread-manager' => 'aec8e38c',
'conpherence-transaction-css' => '3a3f5e7e',
'd3' => 'd67475f5',
'differential-changeset-view-css' => 'bde53589',
'differential-core-view-css' => '7300a73e',
'differential-revision-add-comment-css' => '7e5900d9',
'differential-revision-comment-css' => '7dbc8d1d',
'differential-revision-history-css' => '8aa3eac5',
'differential-revision-list-css' => '93d2df7d',
'differential-table-of-contents-css' => '0e3364c7',
'diffusion-css' => 'b54c77b0',
'diffusion-icons-css' => '23b31a1b',
'diffusion-readme-css' => 'b68a76e4',
'diffusion-repository-css' => 'b89e8c6c',
'diviner-shared-css' => '4bd263b0',
'font-fontawesome' => '3883938a',
'font-lato' => '23631304',
'global-drag-and-drop-css' => '1d2713a4',
'harbormaster-css' => '8dfe16b2',
'herald-css' => '648d39e2',
'herald-rule-editor' => '27daef73',
'herald-test-css' => 'e004176f',
'inline-comment-summary-css' => '81eb368d',
'javelin-aphlict' => '022516b4',
'javelin-behavior' => '1b6acc2a',
'javelin-behavior-aphlict-dropdown' => 'e9a2940f',
'javelin-behavior-aphlict-listen' => '4e61fa88',
'javelin-behavior-aphlict-status' => 'c3703a16',
'javelin-behavior-aphront-basic-tokenizer' => '3b4899b0',
'javelin-behavior-aphront-drag-and-drop-textarea' => '7ad020a5',
'javelin-behavior-aphront-form-disable-on-submit' => '55d7b788',
'javelin-behavior-aphront-more' => '506aa3f4',
'javelin-behavior-audio-source' => '3dc5ad43',
'javelin-behavior-audit-preview' => 'b7b73831',
'javelin-behavior-badge-view' => '92cdd7b6',
'javelin-behavior-bulk-editor' => 'aa6d2308',
'javelin-behavior-bulk-job-reload' => '3829a3cf',
'javelin-behavior-calendar-month-view' => '158c64e0',
'javelin-behavior-choose-control' => '04f8a1e3',
'javelin-behavior-comment-actions' => '4dffaeb2',
'javelin-behavior-config-reorder-fields' => '2539f834',
'javelin-behavior-conpherence-menu' => '8c2ed2bf',
'javelin-behavior-conpherence-participant-pane' => '43ba89a2',
'javelin-behavior-conpherence-pontificate' => '4ae58b5a',
'javelin-behavior-conpherence-search' => '91befbcc',
'javelin-behavior-countdown-timer' => '6a162524',
'javelin-behavior-dark-console' => 'f39d968b',
'javelin-behavior-dashboard-async-panel' => '9c01e364',
'javelin-behavior-dashboard-move-panels' => 'a2ab19be',
'javelin-behavior-dashboard-query-panel-select' => '1e413dc9',
'javelin-behavior-dashboard-tab-panel' => '0116d3e8',
'javelin-behavior-day-view' => '727a5a61',
'javelin-behavior-desktop-notifications-control' => '070679fe',
'javelin-behavior-detect-timezone' => '78bc5d94',
'javelin-behavior-device' => '0cf79f45',
'javelin-behavior-diff-preview-link' => 'f51e9c17',
'javelin-behavior-differential-diff-radios' => '925fe8cd',
'javelin-behavior-differential-populate' => 'dfa1d313',
'javelin-behavior-diffusion-commit-branches' => '4b671572',
'javelin-behavior-diffusion-commit-graph' => 'ef836bf2',
'javelin-behavior-diffusion-locate-file' => '87428eb2',
'javelin-behavior-diffusion-pull-lastmodified' => 'c715c123',
'javelin-behavior-document-engine' => '243d6c22',
'javelin-behavior-doorkeeper-tag' => '6a85bc5a',
'javelin-behavior-drydock-live-operation-status' => '47a0728b',
'javelin-behavior-durable-column' => 'fa6f30b2',
'javelin-behavior-editengine-reorder-configs' => '4842f137',
'javelin-behavior-editengine-reorder-fields' => '0ad8d31f',
'javelin-behavior-event-all-day' => '0b1bc990',
'javelin-behavior-fancy-datepicker' => '956f3eeb',
'javelin-behavior-global-drag-and-drop' => '1cab0e9a',
'javelin-behavior-harbormaster-log' => 'b347a301',
'javelin-behavior-herald-rule-editor' => '0922e81d',
'javelin-behavior-high-security-warning' => 'dae2d55b',
'javelin-behavior-history-install' => '6a1583a8',
'javelin-behavior-icon-composer' => '38a6cedb',
'javelin-behavior-launch-icon-composer' => 'a17b84f1',
'javelin-behavior-lightbox-attachments' => 'c7e748bf',
'javelin-behavior-line-chart' => 'ad258e28',
+ 'javelin-behavior-line-chart-legacy' => 'faf3ab6b',
'javelin-behavior-linked-container' => '74446546',
'javelin-behavior-maniphest-batch-selector' => '139ef688',
'javelin-behavior-maniphest-list-editor' => 'c687e867',
'javelin-behavior-owners-path-editor' => 'ff688a7a',
'javelin-behavior-passphrase-credential-control' => '48fe33d0',
'javelin-behavior-phabricator-active-nav' => '7353f43d',
'javelin-behavior-phabricator-autofocus' => '65bb0011',
'javelin-behavior-phabricator-clipboard-copy' => 'cf32921f',
'javelin-behavior-phabricator-file-tree' => 'ee82cedb',
'javelin-behavior-phabricator-gesture' => 'b58d1a2a',
'javelin-behavior-phabricator-gesture-example' => '242dedd0',
'javelin-behavior-phabricator-keyboard-pager' => '1325b731',
'javelin-behavior-phabricator-keyboard-shortcuts' => '2cc87f49',
'javelin-behavior-phabricator-line-linker' => 'e15c8b1f',
'javelin-behavior-phabricator-nav' => 'f166c949',
'javelin-behavior-phabricator-notification-example' => '29819b75',
'javelin-behavior-phabricator-object-selector' => 'a4af0b4a',
'javelin-behavior-phabricator-oncopy' => 'ff7b3f22',
'javelin-behavior-phabricator-remarkup-assist' => '2f80333f',
'javelin-behavior-phabricator-reveal-content' => 'b105a3a6',
'javelin-behavior-phabricator-search-typeahead' => '1cb7d027',
'javelin-behavior-phabricator-show-older-transactions' => '600f440c',
'javelin-behavior-phabricator-tooltips' => '73ecc1f8',
'javelin-behavior-phabricator-transaction-comment-form' => '2bdadf1a',
'javelin-behavior-phabricator-transaction-list' => '9cec214e',
'javelin-behavior-phabricator-watch-anchor' => '0e6d261f',
'javelin-behavior-pholio-mock-edit' => '3eed1f2b',
'javelin-behavior-pholio-mock-view' => '5aa1544e',
'javelin-behavior-phui-dropdown-menu' => '5cf0501a',
'javelin-behavior-phui-file-upload' => 'e150bd50',
'javelin-behavior-phui-hovercards' => '6c379000',
'javelin-behavior-phui-selectable-list' => 'b26a41e4',
'javelin-behavior-phui-submenu' => 'b5e9bff9',
'javelin-behavior-phui-tab-group' => '242aa08b',
'javelin-behavior-phui-timer-control' => 'f84bcbf4',
'javelin-behavior-phuix-example' => 'c2c500a7',
'javelin-behavior-policy-control' => '0eaa33a9',
'javelin-behavior-policy-rule-editor' => '9347f172',
'javelin-behavior-project-boards' => 'aad45445',
'javelin-behavior-project-create' => '34c53422',
'javelin-behavior-quicksand-blacklist' => '5a6f6a06',
'javelin-behavior-read-only-warning' => 'b9109f8f',
'javelin-behavior-redirect' => '407ee861',
'javelin-behavior-refresh-csrf' => '46116c01',
'javelin-behavior-releeph-preview-branch' => '75184d68',
'javelin-behavior-releeph-request-state-change' => '9f081f05',
'javelin-behavior-releeph-request-typeahead' => 'aa3a100c',
'javelin-behavior-remarkup-load-image' => '202bfa3f',
'javelin-behavior-remarkup-preview' => 'd8a86cfb',
'javelin-behavior-reorder-applications' => 'aa371860',
'javelin-behavior-reorder-columns' => '8ac32fd9',
'javelin-behavior-reorder-profile-menu-items' => 'e5bdb730',
'javelin-behavior-repository-crossreference' => 'c15122b4',
'javelin-behavior-scrollbar' => '92388bae',
'javelin-behavior-search-reorder-queries' => 'b86f297f',
'javelin-behavior-select-content' => 'e8240b50',
'javelin-behavior-select-on-click' => '66365ee2',
'javelin-behavior-setup-check-https' => '01384686',
'javelin-behavior-stripe-payment-form' => '02cb4398',
'javelin-behavior-test-payment-form' => '4a7fb02b',
'javelin-behavior-time-typeahead' => '5803b9e7',
'javelin-behavior-toggle-class' => '32db8374',
'javelin-behavior-toggle-widget' => '8f959ad0',
'javelin-behavior-trigger-rule-editor' => '398fdf13',
'javelin-behavior-typeahead-browse' => '70245195',
'javelin-behavior-typeahead-search' => '7b139193',
'javelin-behavior-user-menu' => '60cd9241',
'javelin-behavior-view-placeholder' => 'a9942052',
'javelin-behavior-workflow' => '9623adc1',
'javelin-chart' => 'fcb0c07d',
'javelin-color' => '78f811c9',
'javelin-cookie' => '05d290ef',
'javelin-diffusion-locate-file-source' => '94243d89',
'javelin-dom' => '94681e22',
'javelin-dynval' => '202a2e85',
'javelin-event' => 'c03f2fb4',
'javelin-fx' => '34450586',
'javelin-history' => '030b4f7a',
'javelin-install' => '5902260c',
'javelin-json' => '541f81c3',
'javelin-leader' => '0d2490ce',
'javelin-magical-init' => '98e6504a',
'javelin-mask' => '7c4d8998',
'javelin-quicksand' => 'd3799cb4',
'javelin-reactor' => '1c850a26',
'javelin-reactor-dom' => '6cfa0008',
'javelin-reactor-node-calmer' => '225bbb98',
'javelin-reactornode' => '72960bc1',
'javelin-request' => '91863989',
'javelin-resource' => '740956e1',
'javelin-routable' => '6a18c42e',
'javelin-router' => '32755edb',
'javelin-scrollbar' => 'a43ae2ae',
'javelin-sound' => 'd4cc2d2a',
'javelin-stratcom' => '0889b835',
'javelin-tokenizer' => '89a1ae3a',
'javelin-typeahead' => 'a4356cde',
'javelin-typeahead-composite-source' => '22ee68a5',
'javelin-typeahead-normalizer' => 'a241536a',
'javelin-typeahead-ondemand-source' => '23387297',
'javelin-typeahead-preloaded-source' => '5a79f6c3',
'javelin-typeahead-source' => '8badee71',
'javelin-typeahead-static-source' => '80bff3af',
'javelin-uri' => '2e255291',
'javelin-util' => 'edb4d8c9',
'javelin-vector' => 'e9c80beb',
'javelin-view' => '289bf236',
'javelin-view-html' => 'f8c4e135',
'javelin-view-interpreter' => '876506b6',
'javelin-view-renderer' => '9aae2b66',
'javelin-view-visitor' => '308f9fe4',
'javelin-websocket' => 'fdc13e4e',
'javelin-workboard-board' => 'c02a5497',
'javelin-workboard-card' => '0392a5d8',
'javelin-workboard-card-template' => '2a61f8d4',
'javelin-workboard-column' => 'c3d24e63',
'javelin-workboard-controller' => '42c7a5a7',
'javelin-workboard-drop-effect' => '8e0aa661',
'javelin-workboard-header' => '111bfd2d',
'javelin-workboard-header-template' => 'ebe83a6b',
'javelin-workboard-order-template' => '03e8891f',
'javelin-workflow' => '958e9045',
'maniphest-report-css' => '3d53188b',
'maniphest-task-edit-css' => '272daa84',
'maniphest-task-summary-css' => '61d1667e',
'multirow-row-manager' => '5b54c823',
'owners-path-editor' => '2a8b62d9',
'owners-path-editor-css' => 'fa7c13ef',
'paste-css' => 'b37bcd38',
'path-typeahead' => 'ad486db3',
'people-picture-menu-item-css' => 'fe8e07cf',
'people-profile-css' => '2ea2daa1',
'phabricator-action-list-view-css' => 'e820263c',
'phabricator-busy' => '5202e831',
'phabricator-chatlog-css' => 'abdc76ee',
'phabricator-content-source-view-css' => 'cdf0d579',
'phabricator-core-css' => '1b29ed61',
'phabricator-countdown-css' => 'bff8012f',
'phabricator-darklog' => '3b869402',
'phabricator-darkmessage' => '26cd4b73',
'phabricator-dashboard-css' => '5a205b9d',
'phabricator-diff-changeset' => 'd0a85a85',
'phabricator-diff-changeset-list' => '04023d82',
'phabricator-diff-inline' => 'a4a14a94',
'phabricator-drag-and-drop-file-upload' => '4370900d',
'phabricator-draggable-list' => 'c9ad6f70',
'phabricator-fatal-config-template-css' => '20babf50',
'phabricator-favicon' => '7930776a',
'phabricator-feed-css' => 'd8b6e3f8',
'phabricator-file-upload' => 'ab85e184',
'phabricator-filetree-view-css' => '56cdd875',
'phabricator-flag-css' => '2b77be8d',
'phabricator-keyboard-shortcut' => 'c9749dcd',
'phabricator-keyboard-shortcut-manager' => '37b8a04a',
'phabricator-main-menu-view' => '17b71bbc',
'phabricator-nav-view-css' => 'f8a0c1bf',
'phabricator-notification' => 'a9b91e3f',
'phabricator-notification-css' => '30240bd2',
'phabricator-notification-menu-css' => '4df1ee30',
'phabricator-object-selector-css' => 'ee77366f',
'phabricator-phtize' => '2f1db1ed',
'phabricator-prefab' => '5793d835',
'phabricator-remarkup-css' => '9e627d41',
'phabricator-search-results-css' => '9ea70ace',
'phabricator-shaped-request' => 'abf88db8',
'phabricator-slowvote-css' => '1694baed',
'phabricator-source-code-view-css' => '03d7ac28',
'phabricator-standard-page-view' => '8a295cb9',
'phabricator-textareautils' => 'f340a484',
'phabricator-title' => '43bc9360',
'phabricator-tooltip' => '83754533',
'phabricator-ui-example-css' => 'b4795059',
'phabricator-zindex-css' => '99c0f5eb',
'phame-css' => 'bb442327',
'pholio-css' => '88ef5ef1',
'pholio-edit-css' => '4df55b3b',
'pholio-inline-comments-css' => '722b48c2',
'phortune-credit-card-form' => 'd12d214f',
'phortune-credit-card-form-css' => '3b9868a8',
'phortune-css' => '12e8251a',
'phortune-invoice-css' => '4436b241',
'phrequent-css' => 'bd79cc67',
'phriction-document-css' => '03380da0',
'phui-action-panel-css' => '6c386cbf',
'phui-badge-view-css' => '666e25ad',
'phui-basic-nav-view-css' => '56ebd66d',
'phui-big-info-view-css' => '362ad37b',
'phui-box-css' => '5ed3b8cb',
'phui-bulk-editor-css' => '374d5e30',
'phui-button-bar-css' => 'a4aa75c4',
'phui-button-css' => 'ea704902',
'phui-button-simple-css' => '1ff278aa',
'phui-calendar-css' => 'f11073aa',
'phui-calendar-day-css' => '9597d706',
'phui-calendar-list-css' => 'ccd7e4e2',
'phui-calendar-month-css' => 'cb758c42',
'phui-chart-css' => '7853a69b',
'phui-cms-css' => '8c05c41e',
'phui-comment-form-css' => '68a2d99a',
'phui-comment-panel-css' => 'ec4e31c0',
'phui-crumbs-view-css' => '614f43cf',
'phui-curtain-view-css' => '68c5efb6',
'phui-document-summary-view-css' => 'b068eed1',
'phui-document-view-css' => '52b748a5',
'phui-document-view-pro-css' => 'b9613a10',
'phui-feed-story-css' => 'a0c05029',
'phui-font-icon-base-css' => 'd7994e06',
'phui-fontkit-css' => '9b714a5e',
'phui-form-css' => '159e2d9c',
'phui-form-view-css' => '01b796c0',
'phui-head-thing-view-css' => 'd7f293df',
'phui-header-view-css' => '285c9139',
'phui-hovercard' => '074f0783',
'phui-hovercard-view-css' => '6ca90fa0',
'phui-icon-set-selector-css' => '7aa5f3ec',
'phui-icon-view-css' => '4cbc684a',
'phui-image-mask-css' => '62c7f4d2',
'phui-info-view-css' => 'a10a909b',
'phui-inline-comment-view-css' => '48acce5b',
'phui-invisible-character-view-css' => 'c694c4a4',
'phui-left-right-css' => '68513c34',
'phui-lightbox-css' => '4ebf22da',
'phui-list-view-css' => 'b05144dd',
'phui-object-box-css' => 'f434b6be',
'phui-oi-big-ui-css' => 'fa74cc35',
'phui-oi-color-css' => 'b517bfa0',
'phui-oi-drag-ui-css' => 'da15d3dc',
'phui-oi-flush-ui-css' => '490e2e2e',
'phui-oi-list-view-css' => 'd7723ecc',
'phui-oi-simple-ui-css' => '6a30fa46',
'phui-pager-css' => 'd022c7ad',
'phui-pinboard-view-css' => '1f08f5d8',
'phui-property-list-view-css' => 'cad62236',
'phui-remarkup-preview-css' => '91767007',
'phui-segment-bar-view-css' => '5166b370',
'phui-spacing-css' => 'b05cadc3',
'phui-status-list-view-css' => 'e5ff8be0',
'phui-tag-view-css' => '8519160a',
'phui-theme-css' => '35883b37',
'phui-timeline-view-css' => '1e348e4b',
'phui-two-column-view-css' => '01e6991e',
'phui-workboard-color-css' => 'e86de308',
'phui-workboard-view-css' => '74fc9d98',
'phui-workcard-view-css' => '9e9eb0df',
'phui-workpanel-view-css' => '3ae89b20',
'phuix-action-list-view' => 'c68f183f',
'phuix-action-view' => 'aaa08f3b',
'phuix-autocomplete' => '2fbe234d',
'phuix-button-view' => '55a24e84',
'phuix-dropdown-menu' => '7acfd98b',
'phuix-form-control-view' => '38c1f3fb',
'phuix-icon-view' => 'a5257c4e',
'policy-css' => 'ceb56a08',
'policy-edit-css' => '8794e2ed',
'policy-transaction-detail-css' => 'c02b8384',
'ponder-view-css' => '05a09d0a',
'project-card-view-css' => '4e7371cd',
'project-triggers-css' => 'cd9c8bb9',
'project-view-css' => '567858b3',
'releeph-core' => 'f81ff2db',
'releeph-preview-branch' => '22db5c07',
'releeph-request-differential-create-dialog' => '0ac1ea31',
'releeph-request-typeahead-css' => 'bce37359',
'setup-issue-css' => '5eed85b2',
'sprite-login-css' => '18b368a6',
'sprite-tokens-css' => 'f1896dc5',
'syntax-default-css' => '055fc231',
'syntax-highlighting-css' => '4234f572',
'tokens-css' => 'ce5a50bd',
'trigger-rule' => '41b7b4f6',
'trigger-rule-control' => '5faf27b9',
'trigger-rule-editor' => 'b49fd60c',
'trigger-rule-type' => '4feea7d3',
'typeahead-browse-css' => 'b7ed02d2',
'unhandled-exception-css' => '9ecfc00d',
),
'requires' => array(
'0116d3e8' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'01384686' => array(
'javelin-behavior',
'javelin-uri',
'phabricator-notification',
),
'022516b4' => array(
'javelin-install',
'javelin-util',
'javelin-websocket',
'javelin-leader',
'javelin-json',
),
'02cb4398' => array(
'javelin-behavior',
'javelin-dom',
'phortune-credit-card-form',
),
'030b4f7a' => array(
'javelin-stratcom',
'javelin-install',
'javelin-uri',
'javelin-util',
),
'0392a5d8' => array(
'javelin-install',
),
'03e8891f' => array(
'javelin-install',
),
'04023d82' => array(
'javelin-install',
'phuix-button-view',
),
'04f8a1e3' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-workflow',
),
'05d290ef' => array(
'javelin-install',
'javelin-util',
),
'070679fe' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-uri',
'phabricator-notification',
),
'074f0783' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
'javelin-request',
'javelin-uri',
),
'0889b835' => array(
'javelin-install',
'javelin-event',
'javelin-util',
'javelin-magical-init',
),
'0922e81d' => array(
'herald-rule-editor',
'javelin-behavior',
),
'0ad8d31f' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'0cf79f45' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
'javelin-install',
),
'0d2490ce' => array(
'javelin-install',
),
'0e6d261f' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
),
'0eaa33a9' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phuix-dropdown-menu',
'phuix-action-list-view',
'phuix-action-view',
'javelin-workflow',
'phuix-icon-view',
),
'111bfd2d' => array(
'javelin-install',
),
'1325b731' => array(
'javelin-behavior',
'javelin-uri',
'phabricator-keyboard-shortcut',
),
'139ef688' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
),
'17b71bbc' => array(
'phui-theme-css',
),
'1b6acc2a' => array(
'javelin-magical-init',
'javelin-util',
),
'1c850a26' => array(
'javelin-install',
'javelin-util',
),
'1cab0e9a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-uri',
'javelin-mask',
'phabricator-drag-and-drop-file-upload',
),
'1cb7d027' => array(
'javelin-behavior',
'javelin-typeahead-ondemand-source',
'javelin-typeahead',
'javelin-dom',
'javelin-uri',
'javelin-util',
'javelin-stratcom',
'phabricator-prefab',
'phuix-icon-view',
),
'1e413dc9' => array(
'javelin-behavior',
'javelin-dom',
),
'1ff278aa' => array(
'phui-button-css',
),
'202a2e85' => array(
'javelin-install',
'javelin-reactornode',
'javelin-util',
'javelin-reactor',
),
'202bfa3f' => array(
'javelin-behavior',
'javelin-request',
),
'225bbb98' => array(
'javelin-install',
'javelin-reactor',
'javelin-util',
),
'22ee68a5' => array(
'javelin-install',
'javelin-typeahead-source',
'javelin-util',
),
23387297 => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-typeahead-source',
),
23631304 => array(
'phui-fontkit-css',
),
'242aa08b' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'242dedd0' => array(
'javelin-stratcom',
'javelin-behavior',
'javelin-vector',
'javelin-dom',
),
'243d6c22' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'2539f834' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-json',
'phabricator-draggable-list',
),
'27daef73' => array(
'multirow-row-manager',
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-json',
'phabricator-prefab',
),
'289bf236' => array(
'javelin-install',
'javelin-util',
),
'29819b75' => array(
'phabricator-notification',
'javelin-stratcom',
'javelin-behavior',
),
'2a61f8d4' => array(
'javelin-install',
),
'2a8b62d9' => array(
'multirow-row-manager',
'javelin-install',
'path-typeahead',
'javelin-dom',
'javelin-util',
'phabricator-prefab',
'phuix-form-control-view',
),
'2bdadf1a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-request',
'phabricator-shaped-request',
),
'2cc87f49' => array(
'javelin-behavior',
'javelin-workflow',
'javelin-json',
'javelin-dom',
'phabricator-keyboard-shortcut',
),
'2e255291' => array(
'javelin-install',
'javelin-util',
'javelin-stratcom',
),
'2f1db1ed' => array(
'javelin-util',
),
'2f80333f' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phabricator-phtize',
'phabricator-textareautils',
'javelin-workflow',
'javelin-vector',
'phuix-autocomplete',
'javelin-mask',
),
'2fbe234d' => array(
'javelin-install',
'javelin-dom',
'phuix-icon-view',
'phabricator-prefab',
),
'308f9fe4' => array(
'javelin-install',
'javelin-util',
),
'32755edb' => array(
'javelin-install',
'javelin-util',
),
'32db8374' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
34450586 => array(
'javelin-color',
'javelin-install',
'javelin-util',
),
'34c53422' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
),
'37b8a04a' => array(
'javelin-install',
'javelin-util',
'javelin-stratcom',
'javelin-dom',
'javelin-vector',
),
'3829a3cf' => array(
'javelin-behavior',
'javelin-uri',
),
'38a6cedb' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'38c1f3fb' => array(
'javelin-install',
'javelin-dom',
),
'398fdf13' => array(
'javelin-behavior',
'trigger-rule-editor',
'trigger-rule',
'trigger-rule-type',
),
'3ae89b20' => array(
'phui-workcard-view-css',
),
'3b4899b0' => array(
'javelin-behavior',
'phabricator-prefab',
),
'3dc5ad43' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
),
'3eed1f2b' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-workflow',
'javelin-quicksand',
'phabricator-phtize',
'phabricator-drag-and-drop-file-upload',
'phabricator-draggable-list',
),
'407ee861' => array(
'javelin-behavior',
'javelin-uri',
),
'4234f572' => array(
'syntax-default-css',
),
'42c7a5a7' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'phabricator-drag-and-drop-file-upload',
'javelin-workboard-board',
),
'4370900d' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-dom',
'javelin-uri',
'phabricator-file-upload',
),
'43ba89a2' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-util',
'phabricator-notification',
'conpherence-thread-manager',
),
'43bc9360' => array(
'javelin-install',
),
'46116c01' => array(
'javelin-request',
'javelin-behavior',
'javelin-dom',
'javelin-router',
'javelin-util',
'phabricator-busy',
),
'47a0728b' => array(
'javelin-behavior',
'javelin-dom',
'javelin-request',
),
'4842f137' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'48fe33d0' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-util',
'javelin-uri',
),
'490e2e2e' => array(
'phui-oi-list-view-css',
),
'4a7fb02b' => array(
'javelin-behavior',
'javelin-dom',
'phortune-credit-card-form',
),
'4ae58b5a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-workflow',
'javelin-stratcom',
'conpherence-thread-manager',
),
'4b671572' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-request',
),
'4dffaeb2' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phuix-form-control-view',
'phuix-icon-view',
'javelin-behavior-phabricator-gesture',
),
'4e61fa88' => 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',
),
'4feea7d3' => array(
'trigger-rule-control',
),
'506aa3f4' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'5202e831' => array(
'javelin-install',
'javelin-dom',
'javelin-fx',
),
'541f81c3' => array(
'javelin-install',
),
'55a24e84' => array(
'javelin-install',
'javelin-dom',
),
'55d7b788' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'5793d835' => 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',
),
'5803b9e7' => array(
'javelin-behavior',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
'javelin-typeahead-static-source',
),
'5902260c' => array(
'javelin-util',
'javelin-magical-init',
),
'5a6f6a06' => array(
'javelin-behavior',
'javelin-quicksand',
),
'5a79f6c3' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-typeahead-source',
),
'5aa1544e' => 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',
),
'5b54c823' => array(
'javelin-install',
'javelin-stratcom',
'javelin-dom',
'javelin-util',
),
'5cf0501a' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phuix-dropdown-menu',
),
'5faf27b9' => array(
'phuix-form-control-view',
),
'600f440c' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phabricator-busy',
),
'60cd9241' => array(
'javelin-behavior',
),
'65bb0011' => array(
'javelin-behavior',
'javelin-dom',
),
'66365ee2' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'6a1583a8' => array(
'javelin-behavior',
'javelin-history',
),
'6a162524' => array(
'javelin-behavior',
'javelin-dom',
),
'6a18c42e' => array(
'javelin-install',
),
'6a30fa46' => array(
'phui-oi-list-view-css',
),
'6a85bc5a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-json',
'javelin-workflow',
'javelin-magical-init',
),
'6c379000' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-vector',
'phui-hovercard',
),
'6cfa0008' => array(
'javelin-dom',
'javelin-dynval',
'javelin-reactor',
'javelin-reactornode',
'javelin-install',
'javelin-util',
),
70245195 => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
),
'727a5a61' => array(
'phuix-icon-view',
),
'72960bc1' => array(
'javelin-install',
'javelin-reactor',
'javelin-util',
'javelin-reactor-node-calmer',
),
'7353f43d' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
'javelin-uri',
),
'73ecc1f8' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'phabricator-tooltip',
),
'740956e1' => array(
'javelin-util',
'javelin-uri',
'javelin-install',
),
74446546 => array(
'javelin-behavior',
'javelin-dom',
),
'75184d68' => array(
'javelin-behavior',
'javelin-dom',
'javelin-uri',
'javelin-request',
),
'78bc5d94' => array(
'javelin-behavior',
'javelin-uri',
'phabricator-notification',
),
'78f811c9' => array(
'javelin-install',
),
'7930776a' => array(
'javelin-install',
'javelin-dom',
),
'7acfd98b' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-vector',
'javelin-stratcom',
),
'7ad020a5' => array(
'javelin-behavior',
'javelin-dom',
'phabricator-drag-and-drop-file-upload',
'phabricator-textareautils',
),
'7b139193' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
),
'7c4d8998' => array(
'javelin-install',
'javelin-dom',
),
'80bff3af' => array(
'javelin-install',
'javelin-typeahead-source',
),
83754533 => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-vector',
),
'87428eb2' => array(
'javelin-behavior',
'javelin-diffusion-locate-file-source',
'javelin-dom',
'javelin-typeahead',
'javelin-uri',
),
'876506b6' => array(
'javelin-view',
'javelin-install',
'javelin-dom',
),
'89a1ae3a' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
),
'8ac32fd9' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'8badee71' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-typeahead-normalizer',
),
'8c2ed2bf' => 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',
),
'8e0aa661' => array(
'javelin-install',
'javelin-dom',
),
'8f959ad0' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-workflow',
'javelin-stratcom',
),
91863989 => array(
'javelin-install',
'javelin-stratcom',
'javelin-util',
'javelin-behavior',
'javelin-json',
'javelin-dom',
'javelin-resource',
'javelin-routable',
),
'91befbcc' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-workflow',
'javelin-stratcom',
),
'92388bae' => array(
'javelin-behavior',
'javelin-scrollbar',
),
'925fe8cd' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'92cdd7b6' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'9347f172' => array(
'javelin-behavior',
'multirow-row-manager',
'javelin-dom',
'javelin-util',
'phabricator-prefab',
'javelin-json',
),
'94243d89' => array(
'javelin-install',
'javelin-dom',
'javelin-typeahead-preloaded-source',
'javelin-util',
),
'94681e22' => array(
'javelin-magical-init',
'javelin-install',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
),
'956f3eeb' => array(
'javelin-behavior',
'javelin-util',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
),
'958e9045' => array(
'javelin-stratcom',
'javelin-request',
'javelin-dom',
'javelin-vector',
'javelin-install',
'javelin-util',
'javelin-mask',
'javelin-uri',
'javelin-routable',
),
'9623adc1' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'javelin-router',
),
'9aae2b66' => array(
'javelin-install',
'javelin-util',
),
'9c01e364' => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
),
'9cec214e' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'javelin-uri',
'phabricator-textareautils',
),
'9f081f05' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-util',
'phabricator-keyboard-shortcut',
),
'a17b84f1' => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
),
'a241536a' => array(
'javelin-install',
),
'a2ab19be' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
),
'a4356cde' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
'javelin-util',
),
'a43ae2ae' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-vector',
),
'a4a14a94' => array(
'javelin-dom',
),
'a4aa75c4' => array(
'phui-button-css',
'phui-button-simple-css',
),
'a4af0b4a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-request',
'javelin-util',
),
'a5257c4e' => array(
'javelin-install',
'javelin-dom',
),
'a9942052' => array(
'javelin-behavior',
'javelin-dom',
'javelin-view-renderer',
'javelin-install',
),
'a9b91e3f' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
'phabricator-notification-css',
),
'aa371860' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'aa3a100c' => array(
'javelin-behavior',
'javelin-dom',
'javelin-typeahead',
'javelin-typeahead-ondemand-source',
'javelin-dom',
),
'aa6d2308' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'multirow-row-manager',
'javelin-json',
'phuix-form-control-view',
),
'aaa08f3b' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
),
'aad45445' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-vector',
'javelin-stratcom',
'javelin-workflow',
'javelin-workboard-controller',
'javelin-workboard-drop-effect',
),
'ab85e184' => array(
'javelin-install',
'javelin-dom',
'phabricator-notification',
),
'abf88db8' => array(
'javelin-install',
'javelin-util',
'javelin-request',
'javelin-router',
),
'ad258e28' => array(
'javelin-behavior',
'javelin-dom',
'javelin-chart',
),
'ad486db3' => array(
'javelin-install',
'javelin-typeahead',
'javelin-dom',
'javelin-request',
'javelin-typeahead-ondemand-source',
'javelin-util',
),
'aec8e38c' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
'javelin-aphlict',
'javelin-workflow',
'javelin-router',
'javelin-behavior-device',
'javelin-vector',
),
'b105a3a6' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'b26a41e4' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'b347a301' => array(
'javelin-behavior',
),
'b49fd60c' => array(
'multirow-row-manager',
'trigger-rule',
),
'b517bfa0' => array(
'phui-oi-list-view-css',
),
'b52d0668' => array(
'aphront-typeahead-control-css',
'phui-tag-view-css',
),
'b58d1a2a' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
'javelin-magical-init',
),
'b5e9bff9' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'b7b73831' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-shaped-request',
),
'b86f297f' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'b9109f8f' => array(
'javelin-behavior',
'javelin-uri',
'phabricator-notification',
),
'bde53589' => array(
'phui-inline-comment-view-css',
),
'c02a5497' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
'javelin-workboard-column',
'javelin-workboard-header-template',
'javelin-workboard-card-template',
'javelin-workboard-order-template',
),
'c03f2fb4' => array(
'javelin-install',
),
'c15122b4' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-uri',
),
'c2c500a7' => array(
'javelin-install',
'javelin-dom',
'phuix-button-view',
),
'c3703a16' => array(
'javelin-behavior',
'javelin-aphlict',
'phabricator-phtize',
'javelin-dom',
),
'c3d24e63' => array(
'javelin-install',
'javelin-workboard-card',
'javelin-workboard-header',
),
'c687e867' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
'javelin-fx',
'javelin-util',
),
'c68f183f' => array(
'javelin-install',
'javelin-dom',
),
'c715c123' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-workflow',
'javelin-json',
),
'c7e748bf' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-mask',
'javelin-util',
'phuix-icon-view',
'phabricator-busy',
),
'c9749dcd' => array(
'javelin-install',
'javelin-util',
'phabricator-keyboard-shortcut-manager',
),
'c9ad6f70' => array(
'javelin-install',
'javelin-dom',
'javelin-stratcom',
'javelin-util',
'javelin-vector',
'javelin-magical-init',
),
'cf32921f' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'd0a85a85' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
'javelin-workflow',
'javelin-router',
'javelin-behavior-device',
'javelin-vector',
'phabricator-diff-inline',
),
'd12d214f' => array(
'javelin-install',
'javelin-dom',
'javelin-json',
'javelin-workflow',
'javelin-util',
),
'd3799cb4' => array(
'javelin-install',
),
'd4cc2d2a' => array(
'javelin-install',
),
'd8a86cfb' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'phabricator-shaped-request',
),
'da15d3dc' => array(
'phui-oi-list-view-css',
),
'dae2d55b' => array(
'javelin-behavior',
'javelin-uri',
'phabricator-notification',
),
'dfa1d313' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'phabricator-tooltip',
'phabricator-diff-changeset-list',
'phabricator-diff-changeset',
),
'e150bd50' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phuix-dropdown-menu',
),
'e15c8b1f' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'javelin-history',
),
'e5bdb730' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-workflow',
'javelin-dom',
'phabricator-draggable-list',
),
'e8240b50' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'e9a2940f' => array(
'javelin-behavior',
'javelin-request',
'javelin-stratcom',
'javelin-vector',
'javelin-dom',
'javelin-uri',
'javelin-behavior-device',
'phabricator-title',
'phabricator-favicon',
),
'e9c80beb' => array(
'javelin-install',
'javelin-event',
),
'ebe83a6b' => array(
'javelin-install',
),
'ec4e31c0' => array(
'phui-timeline-view-css',
),
'ee77366f' => array(
'aphront-dialog-view-css',
),
'ee82cedb' => array(
'javelin-behavior',
'phabricator-keyboard-shortcut',
'javelin-stratcom',
),
'ef836bf2' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'f166c949' => array(
'javelin-behavior',
'javelin-behavior-device',
'javelin-stratcom',
'javelin-dom',
'javelin-magical-init',
'javelin-vector',
'javelin-request',
'javelin-util',
),
'f340a484' => array(
'javelin-install',
'javelin-dom',
'javelin-vector',
),
'f39d968b' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-util',
'javelin-dom',
'javelin-request',
'phabricator-keyboard-shortcut',
'phabricator-darklog',
'phabricator-darkmessage',
),
'f51e9c17' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'f84bcbf4' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
),
'f8c4e135' => array(
'javelin-install',
'javelin-dom',
'javelin-view-visitor',
'javelin-util',
),
'fa6f30b2' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-behavior-device',
'javelin-scrollbar',
'javelin-quicksand',
'phabricator-keyboard-shortcut',
'conpherence-thread-manager',
),
'fa74cc35' => array(
'phui-oi-list-view-css',
),
+ 'faf3ab6b' => array(
+ 'javelin-behavior',
+ 'javelin-dom',
+ 'javelin-vector',
+ 'phui-chart-css',
+ ),
'fcb0c07d' => array(
'phui-chart-css',
'd3',
),
'fdc13e4e' => array(
'javelin-install',
),
'ff688a7a' => array(
'owners-path-editor',
'javelin-behavior',
),
'ff7b3f22' => array(
'javelin-behavior',
'javelin-dom',
),
),
'packages' => array(
'conpherence.pkg.css' => array(
'conpherence-durable-column-view',
'conpherence-menu-css',
'conpherence-color-css',
'conpherence-message-pane-css',
'conpherence-notification-css',
'conpherence-transaction-css',
'conpherence-participant-pane-css',
'conpherence-header-pane-css',
),
'conpherence.pkg.js' => array(
'javelin-behavior-conpherence-menu',
'javelin-behavior-conpherence-participant-pane',
'javelin-behavior-conpherence-pontificate',
'javelin-behavior-toggle-widget',
),
'core.pkg.css' => array(
'phabricator-core-css',
'phabricator-zindex-css',
'phui-button-css',
'phui-button-simple-css',
'phui-theme-css',
'phabricator-standard-page-view',
'aphront-dialog-view-css',
'phui-form-view-css',
'aphront-panel-view-css',
'aphront-table-view-css',
'aphront-tokenizer-control-css',
'aphront-typeahead-control-css',
'aphront-list-filter-view-css',
'application-search-view-css',
'phabricator-remarkup-css',
'syntax-highlighting-css',
'syntax-default-css',
'phui-pager-css',
'aphront-tooltip-css',
'phabricator-flag-css',
'phui-info-view-css',
'phabricator-main-menu-view',
'phabricator-notification-css',
'phabricator-notification-menu-css',
'phui-lightbox-css',
'phui-comment-panel-css',
'phui-header-view-css',
'phabricator-nav-view-css',
'phui-basic-nav-view-css',
'phui-crumbs-view-css',
'phui-oi-list-view-css',
'phui-oi-color-css',
'phui-oi-big-ui-css',
'phui-oi-drag-ui-css',
'phui-oi-simple-ui-css',
'phui-oi-flush-ui-css',
'global-drag-and-drop-css',
'phui-spacing-css',
'phui-form-css',
'phui-icon-view-css',
'phabricator-action-list-view-css',
'phui-property-list-view-css',
'phui-tag-view-css',
'phui-list-view-css',
'font-fontawesome',
'font-lato',
'phui-font-icon-base-css',
'phui-fontkit-css',
'phui-box-css',
'phui-object-box-css',
'phui-timeline-view-css',
'phui-two-column-view-css',
'phui-curtain-view-css',
'sprite-login-css',
'sprite-tokens-css',
'tokens-css',
'auth-css',
'phui-status-list-view-css',
'phui-feed-story-css',
'phabricator-feed-css',
'phabricator-dashboard-css',
'aphront-multi-column-view-css',
),
'core.pkg.js' => array(
'javelin-util',
'javelin-install',
'javelin-event',
'javelin-stratcom',
'javelin-behavior',
'javelin-resource',
'javelin-request',
'javelin-vector',
'javelin-dom',
'javelin-json',
'javelin-uri',
'javelin-workflow',
'javelin-mask',
'javelin-typeahead',
'javelin-typeahead-normalizer',
'javelin-typeahead-source',
'javelin-typeahead-preloaded-source',
'javelin-typeahead-ondemand-source',
'javelin-tokenizer',
'javelin-history',
'javelin-router',
'javelin-routable',
'javelin-behavior-aphront-basic-tokenizer',
'javelin-behavior-workflow',
'javelin-behavior-aphront-form-disable-on-submit',
'phabricator-keyboard-shortcut-manager',
'phabricator-keyboard-shortcut',
'javelin-behavior-phabricator-keyboard-shortcuts',
'javelin-behavior-refresh-csrf',
'javelin-behavior-phabricator-watch-anchor',
'javelin-behavior-phabricator-autofocus',
'phuix-dropdown-menu',
'phuix-action-list-view',
'phuix-action-view',
'phuix-icon-view',
'phabricator-phtize',
'javelin-behavior-phabricator-oncopy',
'phabricator-tooltip',
'javelin-behavior-phabricator-tooltips',
'phabricator-prefab',
'javelin-behavior-device',
'javelin-behavior-toggle-class',
'javelin-behavior-lightbox-attachments',
'phabricator-busy',
'javelin-sound',
'javelin-aphlict',
'phabricator-notification',
'javelin-behavior-aphlict-listen',
'javelin-behavior-phabricator-search-typeahead',
'javelin-behavior-aphlict-dropdown',
'javelin-behavior-history-install',
'javelin-behavior-phabricator-gesture',
'javelin-behavior-phabricator-active-nav',
'javelin-behavior-phabricator-nav',
'javelin-behavior-phabricator-remarkup-assist',
'phabricator-textareautils',
'phabricator-file-upload',
'javelin-behavior-global-drag-and-drop',
'javelin-behavior-phabricator-reveal-content',
'phui-hovercard',
'javelin-behavior-phui-hovercards',
'javelin-color',
'javelin-fx',
'phabricator-draggable-list',
'javelin-behavior-phabricator-transaction-list',
'javelin-behavior-phabricator-show-older-transactions',
'javelin-behavior-phui-dropdown-menu',
'javelin-behavior-doorkeeper-tag',
'phabricator-title',
'javelin-leader',
'javelin-websocket',
'javelin-behavior-dashboard-async-panel',
'javelin-behavior-dashboard-tab-panel',
'javelin-quicksand',
'javelin-behavior-quicksand-blacklist',
'javelin-behavior-high-security-warning',
'javelin-behavior-read-only-warning',
'javelin-scrollbar',
'javelin-behavior-scrollbar',
'javelin-behavior-durable-column',
'conpherence-thread-manager',
'javelin-behavior-detect-timezone',
'javelin-behavior-setup-check-https',
'javelin-behavior-aphlict-status',
'javelin-behavior-user-menu',
'phabricator-favicon',
),
'differential.pkg.css' => array(
'differential-core-view-css',
'differential-changeset-view-css',
'differential-revision-history-css',
'differential-revision-list-css',
'differential-table-of-contents-css',
'differential-revision-comment-css',
'differential-revision-add-comment-css',
'phabricator-object-selector-css',
'phabricator-content-source-view-css',
'inline-comment-summary-css',
'phui-inline-comment-view-css',
'phabricator-filetree-view-css',
),
'differential.pkg.js' => array(
'phabricator-drag-and-drop-file-upload',
'phabricator-shaped-request',
'javelin-behavior-differential-populate',
'javelin-behavior-differential-diff-radios',
'javelin-behavior-aphront-drag-and-drop-textarea',
'javelin-behavior-phabricator-object-selector',
'javelin-behavior-repository-crossreference',
'javelin-behavior-aphront-more',
'phabricator-diff-inline',
'phabricator-diff-changeset',
'phabricator-diff-changeset-list',
),
'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-list-editor',
),
),
);
diff --git a/src/applications/maniphest/controller/ManiphestReportController.php b/src/applications/maniphest/controller/ManiphestReportController.php
index 40498e6e40..90210a0ee4 100644
--- a/src/applications/maniphest/controller/ManiphestReportController.php
+++ b/src/applications/maniphest/controller/ManiphestReportController.php
@@ -1,882 +1,882 @@
<?php
final class ManiphestReportController extends ManiphestController {
private $view;
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$this->view = $request->getURIData('view');
if ($request->isFormPost()) {
$uri = $request->getRequestURI();
$project = head($request->getArr('set_project'));
$project = nonempty($project, null);
if ($project !== null) {
$uri->replaceQueryParam('project', $project);
} else {
$uri->removeQueryParam('project');
}
$window = $request->getStr('set_window');
if ($window !== null) {
$uri->replaceQueryParam('window', $window);
} else {
$uri->removeQueryParam('window');
}
return id(new AphrontRedirectResponse())->setURI($uri);
}
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI('/maniphest/report/'));
$nav->addLabel(pht('Open Tasks'));
$nav->addFilter('user', pht('By User'));
$nav->addFilter('project', pht('By Project'));
$nav->addLabel(pht('Burnup'));
$nav->addFilter('burn', pht('Burnup Rate'));
$this->view = $nav->selectFilter($this->view, 'user');
require_celerity_resource('maniphest-report-css');
switch ($this->view) {
case 'burn':
$core = $this->renderBurn();
break;
case 'user':
case 'project':
$core = $this->renderOpenTasks();
break;
default:
return new Aphront404Response();
}
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb(pht('Reports'));
$nav->appendChild($core);
$title = pht('Maniphest Reports');
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->setNavigation($nav);
}
public function renderBurn() {
$request = $this->getRequest();
$viewer = $request->getUser();
$handle = null;
$project_phid = $request->getStr('project');
if ($project_phid) {
$phids = array($project_phid);
$handles = $this->loadViewerHandles($phids);
$handle = $handles[$project_phid];
}
$table = new ManiphestTransaction();
$conn = $table->establishConnection('r');
if ($project_phid) {
$joins = qsprintf(
$conn,
'JOIN %T t ON x.objectPHID = t.phid
JOIN %T p ON p.src = t.phid AND p.type = %d AND p.dst = %s',
id(new ManiphestTask())->getTableName(),
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
$project_phid);
$create_joins = qsprintf(
$conn,
'JOIN %T p ON p.src = t.phid AND p.type = %d AND p.dst = %s',
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
$project_phid);
} else {
$joins = qsprintf($conn, '');
$create_joins = qsprintf($conn, '');
}
$data = queryfx_all(
$conn,
'SELECT x.transactionType, x.oldValue, x.newValue, x.dateCreated
FROM %T x %Q
WHERE transactionType IN (%Ls)
ORDER BY x.dateCreated ASC',
$table->getTableName(),
$joins,
array(
ManiphestTaskStatusTransaction::TRANSACTIONTYPE,
ManiphestTaskMergedIntoTransaction::TRANSACTIONTYPE,
));
// See PHI273. After the move to EditEngine, we no longer create a
// "status" transaction if a task is created directly into the default
// status. This likely impacted API/email tasks after 2016 and all other
// tasks after late 2017. Until Facts can fix this properly, use the
// task creation dates to generate synthetic transactions which look like
// the older transactions that this page expects.
$default_status = ManiphestTaskStatus::getDefaultStatus();
$duplicate_status = ManiphestTaskStatus::getDuplicateStatus();
// Build synthetic transactions which take status from `null` to the
// default value.
$create_rows = queryfx_all(
$conn,
'SELECT t.dateCreated FROM %T t %Q',
id(new ManiphestTask())->getTableName(),
$create_joins);
foreach ($create_rows as $key => $create_row) {
$create_rows[$key] = array(
'transactionType' => 'status',
'oldValue' => null,
'newValue' => $default_status,
'dateCreated' => $create_row['dateCreated'],
);
}
// Remove any actual legacy status transactions which take status from
// `null` to any open status.
foreach ($data as $key => $row) {
if ($row['transactionType'] != 'status') {
continue;
}
$oldv = trim($row['oldValue'], '"');
$newv = trim($row['newValue'], '"');
// If this is a status change, preserve it.
if ($oldv != 'null') {
continue;
}
// If this task was created directly into a closed status, preserve
// the transaction.
if (!ManiphestTaskStatus::isOpenStatus($newv)) {
continue;
}
// If this is a legacy "create" transaction, discard it in favor of the
// synthetic one.
unset($data[$key]);
}
// Merge the synthetic rows into the real transactions.
$data = array_merge($create_rows, $data);
$data = array_values($data);
$data = isort($data, 'dateCreated');
$stats = array();
$day_buckets = array();
$open_tasks = array();
foreach ($data as $key => $row) {
switch ($row['transactionType']) {
case ManiphestTaskStatusTransaction::TRANSACTIONTYPE:
// NOTE: Hack to avoid json_decode().
$oldv = trim($row['oldValue'], '"');
$newv = trim($row['newValue'], '"');
break;
case ManiphestTaskMergedIntoTransaction::TRANSACTIONTYPE:
// NOTE: Merging a task does not generate a "status" transaction.
// We pretend it did. Note that this is not always accurate: it is
// possible to merge a task which was previously closed, but this
// fake transaction always counts a merge as a closure.
$oldv = $default_status;
$newv = $duplicate_status;
break;
}
if ($oldv == 'null') {
$old_is_open = false;
} else {
$old_is_open = ManiphestTaskStatus::isOpenStatus($oldv);
}
$new_is_open = ManiphestTaskStatus::isOpenStatus($newv);
$is_open = ($new_is_open && !$old_is_open);
$is_close = ($old_is_open && !$new_is_open);
$data[$key]['_is_open'] = $is_open;
$data[$key]['_is_close'] = $is_close;
if (!$is_open && !$is_close) {
// This is either some kind of bogus event, or a resolution change
// (e.g., resolved -> invalid). Just skip it.
continue;
}
$day_bucket = phabricator_format_local_time(
$row['dateCreated'],
$viewer,
'Yz');
$day_buckets[$day_bucket] = $row['dateCreated'];
if (empty($stats[$day_bucket])) {
$stats[$day_bucket] = array(
'open' => 0,
'close' => 0,
);
}
$stats[$day_bucket][$is_close ? 'close' : 'open']++;
}
$template = array(
'open' => 0,
'close' => 0,
);
$rows = array();
$rowc = array();
$last_month = null;
$last_month_epoch = null;
$last_week = null;
$last_week_epoch = null;
$week = null;
$month = null;
$last = last_key($stats) - 1;
$period = $template;
foreach ($stats as $bucket => $info) {
$epoch = $day_buckets[$bucket];
$week_bucket = phabricator_format_local_time(
$epoch,
$viewer,
'YW');
if ($week_bucket != $last_week) {
if ($week) {
$rows[] = $this->formatBurnRow(
pht('Week of %s', phabricator_date($last_week_epoch, $viewer)),
$week);
$rowc[] = 'week';
}
$week = $template;
$last_week = $week_bucket;
$last_week_epoch = $epoch;
}
$month_bucket = phabricator_format_local_time(
$epoch,
$viewer,
'Ym');
if ($month_bucket != $last_month) {
if ($month) {
$rows[] = $this->formatBurnRow(
phabricator_format_local_time($last_month_epoch, $viewer, 'F, Y'),
$month);
$rowc[] = 'month';
}
$month = $template;
$last_month = $month_bucket;
$last_month_epoch = $epoch;
}
$rows[] = $this->formatBurnRow(phabricator_date($epoch, $viewer), $info);
$rowc[] = null;
$week['open'] += $info['open'];
$week['close'] += $info['close'];
$month['open'] += $info['open'];
$month['close'] += $info['close'];
$period['open'] += $info['open'];
$period['close'] += $info['close'];
}
if ($week) {
$rows[] = $this->formatBurnRow(
pht('Week To Date'),
$week);
$rowc[] = 'week';
}
if ($month) {
$rows[] = $this->formatBurnRow(
pht('Month To Date'),
$month);
$rowc[] = 'month';
}
$rows[] = $this->formatBurnRow(
pht('All Time'),
$period);
$rowc[] = 'aggregate';
$rows = array_reverse($rows);
$rowc = array_reverse($rowc);
$table = new AphrontTableView($rows);
$table->setRowClasses($rowc);
$table->setHeaders(
array(
pht('Period'),
pht('Opened'),
pht('Closed'),
pht('Change'),
));
$table->setColumnClasses(
array(
'right wide',
'n',
'n',
'n',
));
if ($handle) {
$inst = pht(
'NOTE: This table reflects tasks currently in '.
'the project. If a task was opened in the past but added to '.
'the project recently, it is counted on the day it was '.
'opened, not the day it was categorized. If a task was part '.
'of this project in the past but no longer is, it is not '.
'counted at all.');
$header = pht('Task Burn Rate for Project %s', $handle->renderLink());
$caption = phutil_tag('p', array(), $inst);
} else {
$header = pht('Task Burn Rate for All Tasks');
$caption = null;
}
if ($caption) {
$caption = id(new PHUIInfoView())
->appendChild($caption)
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
}
$panel = new PHUIObjectBoxView();
$panel->setHeaderText($header);
if ($caption) {
$panel->setInfoView($caption);
}
$panel->setTable($table);
$tokens = array();
if ($handle) {
$tokens = array($handle);
}
$filter = $this->renderReportFilters($tokens, $has_window = false);
$id = celerity_generate_unique_node_id();
$chart = phutil_tag(
'div',
array(
'id' => $id,
'style' => 'border: 1px solid #BFCFDA; '.
'background-color: #fff; '.
'margin: 8px 16px; '.
'height: 400px; ',
),
'');
list($burn_x, $burn_y) = $this->buildSeries($data);
require_celerity_resource('d3');
require_celerity_resource('phui-chart-css');
- Javelin::initBehavior('line-chart', array(
+ Javelin::initBehavior('line-chart-legacy', array(
'hardpoint' => $id,
'x' => array(
$burn_x,
),
'y' => array(
$burn_y,
),
'xformat' => 'epoch',
'yformat' => 'int',
));
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Burnup Rate'))
->appendChild($chart);
return array($filter, $box, $panel);
}
private function renderReportFilters(array $tokens, $has_window) {
$request = $this->getRequest();
$viewer = $request->getUser();
$form = id(new AphrontFormView())
->setUser($viewer)
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorProjectDatasource())
->setLabel(pht('Project'))
->setLimit(1)
->setName('set_project')
// TODO: This is silly, but this is Maniphest reports.
->setValue(mpull($tokens, 'getPHID')));
if ($has_window) {
list($window_str, $ignored, $window_error) = $this->getWindow();
$form
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Recently Means'))
->setName('set_window')
->setCaption(
pht('Configure the cutoff for the "Recently Closed" column.'))
->setValue($window_str)
->setError($window_error));
}
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Filter By Project')));
$filter = new AphrontListFilterView();
$filter->appendChild($form);
return $filter;
}
private function buildSeries(array $data) {
$out = array();
$counter = 0;
foreach ($data as $row) {
$t = (int)$row['dateCreated'];
if ($row['_is_close']) {
--$counter;
$out[$t] = $counter;
} else if ($row['_is_open']) {
++$counter;
$out[$t] = $counter;
}
}
return array(array_keys($out), array_values($out));
}
private function formatBurnRow($label, $info) {
$delta = $info['open'] - $info['close'];
$fmt = number_format($delta);
if ($delta > 0) {
$fmt = '+'.$fmt;
$fmt = phutil_tag('span', array('class' => 'red'), $fmt);
} else {
$fmt = phutil_tag('span', array('class' => 'green'), $fmt);
}
return array(
$label,
number_format($info['open']),
number_format($info['close']),
$fmt,
);
}
public function renderOpenTasks() {
$request = $this->getRequest();
$viewer = $request->getUser();
$query = id(new ManiphestTaskQuery())
->setViewer($viewer)
->withStatuses(ManiphestTaskStatus::getOpenStatusConstants());
switch ($this->view) {
case 'project':
$query->needProjectPHIDs(true);
break;
}
$project_phid = $request->getStr('project');
$project_handle = null;
if ($project_phid) {
$phids = array($project_phid);
$handles = $this->loadViewerHandles($phids);
$project_handle = $handles[$project_phid];
$query->withEdgeLogicPHIDs(
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
PhabricatorQueryConstraint::OPERATOR_OR,
$phids);
}
$tasks = $query->execute();
$recently_closed = $this->loadRecentlyClosedTasks();
$date = phabricator_date(time(), $viewer);
switch ($this->view) {
case 'user':
$result = mgroup($tasks, 'getOwnerPHID');
$leftover = idx($result, '', array());
unset($result['']);
$result_closed = mgroup($recently_closed, 'getOwnerPHID');
$leftover_closed = idx($result_closed, '', array());
unset($result_closed['']);
$base_link = '/maniphest/?assigned=';
$leftover_name = phutil_tag('em', array(), pht('(Up For Grabs)'));
$col_header = pht('User');
$header = pht('Open Tasks by User and Priority (%s)', $date);
break;
case 'project':
$result = array();
$leftover = array();
foreach ($tasks as $task) {
$phids = $task->getProjectPHIDs();
if ($phids) {
foreach ($phids as $project_phid) {
$result[$project_phid][] = $task;
}
} else {
$leftover[] = $task;
}
}
$result_closed = array();
$leftover_closed = array();
foreach ($recently_closed as $task) {
$phids = $task->getProjectPHIDs();
if ($phids) {
foreach ($phids as $project_phid) {
$result_closed[$project_phid][] = $task;
}
} else {
$leftover_closed[] = $task;
}
}
$base_link = '/maniphest/?projects=';
$leftover_name = phutil_tag('em', array(), pht('(No Project)'));
$col_header = pht('Project');
$header = pht('Open Tasks by Project and Priority (%s)', $date);
break;
}
$phids = array_keys($result);
$handles = $this->loadViewerHandles($phids);
$handles = msort($handles, 'getName');
$order = $request->getStr('order', 'name');
list($order, $reverse) = AphrontTableView::parseSort($order);
require_celerity_resource('aphront-tooltip-css');
Javelin::initBehavior('phabricator-tooltips', array());
$rows = array();
$pri_total = array();
foreach (array_merge($handles, array(null)) as $handle) {
if ($handle) {
if (($project_handle) &&
($project_handle->getPHID() == $handle->getPHID())) {
// If filtering by, e.g., "bugs", don't show a "bugs" group.
continue;
}
$tasks = idx($result, $handle->getPHID(), array());
$name = phutil_tag(
'a',
array(
'href' => $base_link.$handle->getPHID(),
),
$handle->getName());
$closed = idx($result_closed, $handle->getPHID(), array());
} else {
$tasks = $leftover;
$name = $leftover_name;
$closed = $leftover_closed;
}
$taskv = $tasks;
$tasks = mgroup($tasks, 'getPriority');
$row = array();
$row[] = $name;
$total = 0;
foreach (ManiphestTaskPriority::getTaskPriorityMap() as $pri => $label) {
$n = count(idx($tasks, $pri, array()));
if ($n == 0) {
$row[] = '-';
} else {
$row[] = number_format($n);
}
$total += $n;
}
$row[] = number_format($total);
list($link, $oldest_all) = $this->renderOldest($taskv);
$row[] = $link;
$normal_or_better = array();
foreach ($taskv as $id => $task) {
// TODO: This is sort of a hard-code for the default "normal" status.
// When reports are more powerful, this should be made more general.
if ($task->getPriority() < 50) {
continue;
}
$normal_or_better[$id] = $task;
}
list($link, $oldest_pri) = $this->renderOldest($normal_or_better);
$row[] = $link;
if ($closed) {
$task_ids = implode(',', mpull($closed, 'getID'));
$row[] = phutil_tag(
'a',
array(
'href' => '/maniphest/?ids='.$task_ids,
'target' => '_blank',
),
number_format(count($closed)));
} else {
$row[] = '-';
}
switch ($order) {
case 'total':
$row['sort'] = $total;
break;
case 'oldest-all':
$row['sort'] = $oldest_all;
break;
case 'oldest-pri':
$row['sort'] = $oldest_pri;
break;
case 'closed':
$row['sort'] = count($closed);
break;
case 'name':
default:
$row['sort'] = $handle ? $handle->getName() : '~';
break;
}
$rows[] = $row;
}
$rows = isort($rows, 'sort');
foreach ($rows as $k => $row) {
unset($rows[$k]['sort']);
}
if ($reverse) {
$rows = array_reverse($rows);
}
$cname = array($col_header);
$cclass = array('pri right wide');
$pri_map = ManiphestTaskPriority::getShortNameMap();
foreach ($pri_map as $pri => $label) {
$cname[] = $label;
$cclass[] = 'n';
}
$cname[] = pht('Total');
$cclass[] = 'n';
$cname[] = javelin_tag(
'span',
array(
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => pht('Oldest open task.'),
'size' => 200,
),
),
pht('Oldest (All)'));
$cclass[] = 'n';
$cname[] = javelin_tag(
'span',
array(
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => pht(
'Oldest open task, excluding those with Low or Wishlist priority.'),
'size' => 200,
),
),
pht('Oldest (Pri)'));
$cclass[] = 'n';
list($ignored, $window_epoch) = $this->getWindow();
$edate = phabricator_datetime($window_epoch, $viewer);
$cname[] = javelin_tag(
'span',
array(
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => pht('Closed after %s', $edate),
'size' => 260,
),
),
pht('Recently Closed'));
$cclass[] = 'n';
$table = new AphrontTableView($rows);
$table->setHeaders($cname);
$table->setColumnClasses($cclass);
$table->makeSortable(
$request->getRequestURI(),
'order',
$order,
$reverse,
array(
'name',
null,
null,
null,
null,
null,
null,
'total',
'oldest-all',
'oldest-pri',
'closed',
));
$panel = new PHUIObjectBoxView();
$panel->setHeaderText($header);
$panel->setTable($table);
$tokens = array();
if ($project_handle) {
$tokens = array($project_handle);
}
$filter = $this->renderReportFilters($tokens, $has_window = true);
return array($filter, $panel);
}
/**
* Load all the tasks that have been recently closed.
*/
private function loadRecentlyClosedTasks() {
list($ignored, $window_epoch) = $this->getWindow();
$table = new ManiphestTask();
$xtable = new ManiphestTransaction();
$conn_r = $table->establishConnection('r');
// TODO: Gross. This table is not meant to be queried like this. Build
// real stats tables.
$open_status_list = array();
foreach (ManiphestTaskStatus::getOpenStatusConstants() as $constant) {
$open_status_list[] = json_encode((string)$constant);
}
$rows = queryfx_all(
$conn_r,
'SELECT t.id FROM %T t JOIN %T x ON x.objectPHID = t.phid
WHERE t.status NOT IN (%Ls)
AND x.oldValue IN (null, %Ls)
AND x.newValue NOT IN (%Ls)
AND t.dateModified >= %d
AND x.dateCreated >= %d',
$table->getTableName(),
$xtable->getTableName(),
ManiphestTaskStatus::getOpenStatusConstants(),
$open_status_list,
$open_status_list,
$window_epoch,
$window_epoch);
if (!$rows) {
return array();
}
$ids = ipull($rows, 'id');
$query = id(new ManiphestTaskQuery())
->setViewer($this->getRequest()->getUser())
->withIDs($ids);
switch ($this->view) {
case 'project':
$query->needProjectPHIDs(true);
break;
}
return $query->execute();
}
/**
* Parse the "Recently Means" filter into:
*
* - A string representation, like "12 AM 7 days ago" (default);
* - a locale-aware epoch representation; and
* - a possible error.
*/
private function getWindow() {
$request = $this->getRequest();
$viewer = $request->getUser();
$window_str = $this->getRequest()->getStr('window', '12 AM 7 days ago');
$error = null;
$window_epoch = null;
// Do locale-aware parsing so that the user's timezone is assumed for
// time windows like "3 PM", rather than assuming the server timezone.
$window_epoch = PhabricatorTime::parseLocalTime($window_str, $viewer);
if (!$window_epoch) {
$error = 'Invalid';
$window_epoch = time() - (60 * 60 * 24 * 7);
}
// If the time ends up in the future, convert it to the corresponding time
// and equal distance in the past. This is so users can type "6 days" (which
// means "6 days from now") and get the behavior of "6 days ago", rather
// than no results (because the window epoch is in the future). This might
// be a little confusing because it causes "tomorrow" to mean "yesterday"
// and "2022" (or whatever) to mean "ten years ago", but these inputs are
// nonsense anyway.
if ($window_epoch > time()) {
$window_epoch = time() - ($window_epoch - time());
}
return array($window_str, $window_epoch, $error);
}
private function renderOldest(array $tasks) {
assert_instances_of($tasks, 'ManiphestTask');
$oldest = null;
foreach ($tasks as $id => $task) {
if (($oldest === null) ||
($task->getDateCreated() < $tasks[$oldest]->getDateCreated())) {
$oldest = $id;
}
}
if ($oldest === null) {
return array('-', 0);
}
$oldest = $tasks[$oldest];
$raw_age = (time() - $oldest->getDateCreated());
$age = number_format($raw_age / (24 * 60 * 60)).' d';
$link = javelin_tag(
'a',
array(
'href' => '/T'.$oldest->getID(),
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => 'T'.$oldest->getID().': '.$oldest->getTitle(),
),
'target' => '_blank',
),
$age);
return array($link, $raw_age);
}
}
diff --git a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
index 340099daef..9d351ea856 100644
--- a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
+++ b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
@@ -1,757 +1,757 @@
<?php
/**
* Manages execution of `git pull` and `hg pull` commands for
* @{class:PhabricatorRepository} objects. Used by
* @{class:PhabricatorRepositoryPullLocalDaemon}.
*
* This class also covers initial working copy setup through `git clone`,
* `git init`, `hg clone`, `hg init`, or `svnadmin create`.
*
* @task pull Pulling Working Copies
* @task git Pulling Git Working Copies
* @task hg Pulling Mercurial Working Copies
* @task svn Pulling Subversion Working Copies
* @task internal Internals
*/
final class PhabricatorRepositoryPullEngine
extends PhabricatorRepositoryEngine {
/* -( Pulling Working Copies )--------------------------------------------- */
public function pullRepository() {
$repository = $this->getRepository();
$lock = $this->newRepositoryLock($repository, 'repo.pull', true);
try {
$lock->lock();
} catch (PhutilLockException $ex) {
throw new DiffusionDaemonLockException(
pht(
'Another process is currently updating repository "%s", '.
'skipping pull.',
$repository->getDisplayName()));
}
try {
$result = $this->pullRepositoryWithLock();
} catch (Exception $ex) {
$lock->unlock();
throw $ex;
}
$lock->unlock();
return $result;
}
private function pullRepositoryWithLock() {
$repository = $this->getRepository();
$viewer = PhabricatorUser::getOmnipotentUser();
$is_hg = false;
$is_git = false;
$is_svn = false;
$vcs = $repository->getVersionControlSystem();
switch ($vcs) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
// We never pull a local copy of non-hosted Subversion repositories.
if (!$repository->isHosted()) {
$this->skipPull(
pht(
'Repository "%s" is a non-hosted Subversion repository, which '.
'does not require a local working copy to be pulled.',
$repository->getDisplayName()));
return;
}
$is_svn = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$is_git = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$is_hg = true;
break;
default:
$this->abortPull(pht('Unknown VCS "%s"!', $vcs));
break;
}
$local_path = $repository->getLocalPath();
if ($local_path === null) {
$this->abortPull(
pht(
'No local path is configured for repository "%s".',
$repository->getDisplayName()));
}
try {
$dirname = dirname($local_path);
if (!Filesystem::pathExists($dirname)) {
Filesystem::createDirectory($dirname, 0755, $recursive = true);
}
if (!Filesystem::pathExists($local_path)) {
$this->logPull(
pht(
'Creating a new working copy for repository "%s".',
$repository->getDisplayName()));
if ($is_git) {
$this->executeGitCreate();
} else if ($is_hg) {
$this->executeMercurialCreate();
} else {
$this->executeSubversionCreate();
}
}
id(new DiffusionRepositoryClusterEngine())
->setViewer($viewer)
->setRepository($repository)
->synchronizeWorkingCopyBeforeRead();
if (!$repository->isHosted()) {
$this->logPull(
pht(
'Updating the working copy for repository "%s".',
$repository->getDisplayName()));
if ($is_git) {
$this->executeGitUpdate();
} else if ($is_hg) {
$this->executeMercurialUpdate();
}
}
if ($repository->isHosted()) {
if ($is_git) {
$this->installGitHook();
} else if ($is_svn) {
$this->installSubversionHook();
} else if ($is_hg) {
$this->installMercurialHook();
}
foreach ($repository->getHookDirectories() as $directory) {
$this->installHookDirectory($directory);
}
}
if ($is_git) {
$this->updateGitWorkingCopyConfiguration();
}
} catch (Exception $ex) {
$this->abortPull(
pht(
"Pull of '%s' failed: %s",
$repository->getDisplayName(),
$ex->getMessage()),
$ex);
}
$this->donePull();
return $this;
}
private function skipPull($message) {
$this->log($message);
$this->donePull();
}
private function abortPull($message, Exception $ex = null) {
$code_error = PhabricatorRepositoryStatusMessage::CODE_ERROR;
$this->updateRepositoryInitStatus($code_error, $message);
if ($ex) {
throw $ex;
} else {
throw new Exception($message);
}
}
private function logPull($message) {
$this->log($message);
}
private function donePull() {
$code_okay = PhabricatorRepositoryStatusMessage::CODE_OKAY;
$this->updateRepositoryInitStatus($code_okay);
}
private function updateRepositoryInitStatus($code, $message = null) {
$this->getRepository()->writeStatusMessage(
PhabricatorRepositoryStatusMessage::TYPE_INIT,
$code,
array(
'message' => $message,
));
}
private function installHook($path, array $hook_argv = array()) {
$this->log(pht('Installing commit hook to "%s"...', $path));
$repository = $this->getRepository();
$identifier = $this->getHookContextIdentifier($repository);
$root = dirname(phutil_get_library_root('phabricator'));
$bin = $root.'/bin/commit-hook';
$full_php_path = Filesystem::resolveBinary('php');
$cmd = csprintf(
'exec %s -f %s -- %s %Ls "$@"',
$full_php_path,
$bin,
$identifier,
$hook_argv);
$hook = "#!/bin/sh\nexport TERM=dumb\n{$cmd}\n";
Filesystem::writeFile($path, $hook);
Filesystem::changePermissions($path, 0755);
}
private function installHookDirectory($path) {
$readme = pht(
"To add custom hook scripts to this repository, add them to this ".
"directory.\n\nPhabricator will run any executables in this directory ".
"after running its own checks, as though they were normal hook ".
"scripts.");
Filesystem::createDirectory($path, 0755);
Filesystem::writeFile($path.'/README', $readme);
}
private function getHookContextIdentifier(PhabricatorRepository $repository) {
$identifier = $repository->getPHID();
$instance = PhabricatorEnv::getEnvConfig('cluster.instance');
if (strlen($instance)) {
$identifier = "{$identifier}:{$instance}";
}
return $identifier;
}
/* -( Pulling Git Working Copies )----------------------------------------- */
/**
* @task git
*/
private function executeGitCreate() {
$repository = $this->getRepository();
$path = rtrim($repository->getLocalPath(), '/');
if ($repository->isHosted()) {
$repository->execxRemoteCommand(
'init --bare -- %s',
$path);
} else {
$repository->execxRemoteCommand(
'clone --bare -- %P %s',
$repository->getRemoteURIEnvelope(),
$path);
}
}
/**
* @task git
*/
private function executeGitUpdate() {
$repository = $this->getRepository();
list($err, $stdout) = $repository->execLocalCommand(
'rev-parse --show-toplevel');
$message = null;
$path = $repository->getLocalPath();
if ($err) {
// Try to raise a more tailored error message in the more common case
// of the user creating an empty directory. (We could try to remove it,
// but might not be able to, and it's much simpler to raise a good
// message than try to navigate those waters.)
if (is_dir($path)) {
$files = Filesystem::listDirectory($path, $include_hidden = true);
if (!$files) {
$message = pht(
"Expected to find a git repository at '%s', but there ".
"is an empty directory there. Remove the directory: the daemon ".
"will run '%s' for you.",
$path,
'git clone');
} else {
$message = pht(
"Expected to find a git repository at '%s', but there is ".
"a non-repository directory (with other stuff in it) there. Move ".
"or remove this directory (or reconfigure the repository to use a ".
"different directory), and then either clone a repository ".
"yourself or let the daemon do it.",
$path);
}
} else if (is_file($path)) {
$message = pht(
"Expected to find a git repository at '%s', but there is a ".
"file there instead. Remove it and let the daemon clone a ".
"repository for you.",
$path);
} else {
$message = pht(
"Expected to find a git repository at '%s', but did not.",
$path);
}
} else {
$repo_path = rtrim($stdout, "\n");
if (empty($repo_path)) {
// This can mean one of two things: we're in a bare repository, or
// we're inside a git repository inside another git repository. Since
// the first is dramatically more likely now that we perform bare
// clones and I don't have a great way to test for the latter, assume
// we're OK.
} else if (!Filesystem::pathsAreEquivalent($repo_path, $path)) {
$err = true;
$message = pht(
"Expected to find repo at '%s', but the actual git repository root ".
"for this directory is '%s'. Something is misconfigured. ".
"The repository's 'Local Path' should be set to some place where ".
"the daemon can check out a working copy, ".
"and should not be inside another git repository.",
$path,
$repo_path);
}
}
if ($err && $repository->canDestroyWorkingCopy()) {
phlog(
pht(
"Repository working copy at '%s' failed sanity check; ".
"destroying and re-cloning. %s",
$path,
$message));
Filesystem::remove($path);
$this->executeGitCreate();
} else if ($err) {
throw new Exception($message);
}
// Load the refs we're planning to fetch from the remote repository.
$remote_refs = $this->loadGitRemoteRefs(
$repository,
$repository->getRemoteURIEnvelope());
// Load the refs we're planning to fetch from the local repository, by
// using the local working copy path as the "remote" repository URI.
$local_refs = $this->loadGitRemoteRefs(
$repository,
new PhutilOpaqueEnvelope($path));
if ($remote_refs === $local_refs) {
$this->log(
pht(
'Skipping fetch because local and remote refs are already '.
'identical.'));
return false;
}
$this->logRefDifferences($remote_refs, $local_refs);
$fetch_rules = $this->getGitFetchRules($repository);
$future = $repository->getRemoteCommandFuture(
'fetch --prune -- %P %Ls',
$repository->getRemoteURIEnvelope(),
$fetch_rules);
$future
->setCWD($path)
->resolvex();
}
private function getGitRefRules(PhabricatorRepository $repository) {
$ref_rules = $repository->getFetchRules($repository);
if (!$ref_rules) {
$ref_rules = array(
'refs/*',
);
}
return $ref_rules;
}
private function getGitFetchRules(PhabricatorRepository $repository) {
$ref_rules = $this->getGitRefRules($repository);
// Rewrite each ref rule "X" into "+X:X".
// The "X" means "fetch ref X".
// The "...:X" means "...and copy it into local ref X".
// The "+..." means "...and overwrite the local ref if it already exists".
$fetch_rules = array();
foreach ($ref_rules as $key => $ref_rule) {
$fetch_rules[] = sprintf(
'+%s:%s',
$ref_rule,
$ref_rule);
}
return $fetch_rules;
}
/**
* @task git
*/
private function installGitHook() {
$repository = $this->getRepository();
$root = $repository->getLocalPath();
if ($repository->isWorkingCopyBare()) {
$path = '/hooks/pre-receive';
} else {
$path = '/.git/hooks/pre-receive';
}
$this->installHook($root.$path);
}
private function updateGitWorkingCopyConfiguration() {
$repository = $this->getRepository();
// See T5963. When you "git clone" from a remote with no "master", the
// client warns you that it isn't sure what it should check out as an
// initial state:
// warning: remote HEAD refers to nonexistent ref, unable to checkout
// We can tell the client what it should check out by making "HEAD"
// point somewhere. However:
//
- // (1) If we don't set "receive.denyDelteCurrent" to "ignore" and a user
+ // (1) If we don't set "receive.denyDeleteCurrent" to "ignore" and a user
// tries to delete the default branch, Git raises an error and refuses.
// We want to allow this; we already have sufficient protections around
// dangerous changes and do not need to special case the default branch.
//
// (2) A repository may have a nonexistent default branch configured.
// For now, we just respect configuration. This will raise a warning when
// users clone the repository.
//
// In any case, these changes are both advisory, so ignore any errors we
// may encounter.
// We do this for both hosted and observed repositories. Although it is
// not terribly common to clone from Phabricator's copy of an observed
// repository, it works fine and makes sense occasionally.
if ($repository->isWorkingCopyBare()) {
$repository->execLocalCommand(
'config -- receive.denyDeleteCurrent ignore');
$repository->execLocalCommand(
'symbolic-ref HEAD %s',
'refs/heads/'.$repository->getDefaultBranch());
}
}
private function loadGitRemoteRefs(
PhabricatorRepository $repository,
PhutilOpaqueEnvelope $remote_envelope) {
$ref_rules = $this->getGitRefRules($repository);
// NOTE: "git ls-remote" does not support "--" until circa January 2016.
// See T12416. None of the flags to "ls-remote" appear dangerous, but
// refuse to list any refs beginning with "-" just in case.
foreach ($ref_rules as $ref_rule) {
if (preg_match('/^-/', $ref_rule)) {
throw new Exception(
pht(
'Refusing to list potentially dangerous ref ("%s") beginning '.
'with "-".',
$ref_rule));
}
}
list($stdout) = $repository->execxRemoteCommand(
'ls-remote %P %Ls',
$remote_envelope,
$ref_rules);
// Empty repositories don't have any refs.
if (!strlen(rtrim($stdout))) {
return array();
}
$map = array();
$lines = phutil_split_lines($stdout, false);
foreach ($lines as $line) {
list($hash, $name) = preg_split('/\s+/', $line, 2);
// If the remote has a HEAD, just ignore it.
if ($name == 'HEAD') {
continue;
}
// If the remote ref is itself a remote ref, ignore it.
if (preg_match('(^refs/remotes/)', $name)) {
continue;
}
$map[$name] = $hash;
}
ksort($map);
return $map;
}
private function loadGitLocalRefs(PhabricatorRepository $repository) {
$refs = id(new DiffusionLowLevelGitRefQuery())
->setRepository($repository)
->execute();
$map = array();
foreach ($refs as $ref) {
$fields = $ref->getRawFields();
$map[idx($fields, 'refname')] = $ref->getCommitIdentifier();
}
ksort($map);
return $map;
}
private function logRefDifferences(array $remote, array $local) {
$all = $local + $remote;
$differences = array();
foreach ($all as $key => $ignored) {
$remote_ref = idx($remote, $key, pht('<null>'));
$local_ref = idx($local, $key, pht('<null>'));
if ($remote_ref !== $local_ref) {
$differences[] = pht(
'%s (remote: "%s", local: "%s")',
$key,
$remote_ref,
$local_ref);
}
}
$this->log(
pht(
"Updating repository after detecting ref differences:\n%s",
implode("\n", $differences)));
}
/* -( Pulling Mercurial Working Copies )----------------------------------- */
/**
* @task hg
*/
private function executeMercurialCreate() {
$repository = $this->getRepository();
$path = rtrim($repository->getLocalPath(), '/');
if ($repository->isHosted()) {
$repository->execxRemoteCommand(
'init -- %s',
$path);
} else {
$remote = $repository->getRemoteURIEnvelope();
// NOTE: Mercurial prior to 3.2.4 has an severe command injection
// vulnerability. See: <http://bit.ly/19B58E9>
// On vulnerable versions of Mercurial, we refuse to clone remotes which
// contain characters which may be interpreted by the shell.
$hg_binary = PhutilBinaryAnalyzer::getForBinary('hg');
$is_vulnerable = $hg_binary->isMercurialVulnerableToInjection();
if ($is_vulnerable) {
$cleartext = $remote->openEnvelope();
// The use of "%R" here is an attempt to limit collateral damage
// for normal URIs because it isn't clear how long this vulnerability
// has been around for.
$escaped = csprintf('%R', $cleartext);
if ((string)$escaped !== (string)$cleartext) {
throw new Exception(
pht(
'You have an old version of Mercurial (%s) which has a severe '.
'command injection security vulnerability. The remote URI for '.
'this repository (%s) is potentially unsafe. Upgrade Mercurial '.
'to at least 3.2.4 to clone it.',
$hg_binary->getBinaryVersion(),
$repository->getMonogram()));
}
}
try {
$repository->execxRemoteCommand(
'clone --noupdate -- %P %s',
$remote,
$path);
} catch (Exception $ex) {
$message = $ex->getMessage();
$message = $this->censorMercurialErrorMessage($message);
throw new Exception($message);
}
}
}
/**
* @task hg
*/
private function executeMercurialUpdate() {
$repository = $this->getRepository();
$path = $repository->getLocalPath();
// This is a local command, but needs credentials.
$remote = $repository->getRemoteURIEnvelope();
$future = $repository->getRemoteCommandFuture('pull -- %P', $remote);
$future->setCWD($path);
try {
$future->resolvex();
} catch (CommandException $ex) {
$err = $ex->getError();
$stdout = $ex->getStdout();
// NOTE: Between versions 2.1 and 2.1.1, Mercurial changed the behavior
// of "hg pull" to return 1 in case of a successful pull with no changes.
// This behavior has been reverted, but users who updated between Feb 1,
// 2012 and Mar 1, 2012 will have the erroring version. Do a dumb test
// against stdout to check for this possibility.
// See: https://github.com/phacility/phabricator/issues/101/
// NOTE: Mercurial has translated versions, which translate this error
// string. In a translated version, the string will be something else,
// like "aucun changement trouve". There didn't seem to be an easy way
// to handle this (there are hard ways but this is not a common problem
// and only creates log spam, not application failures). Assume English.
// TODO: Remove this once we're far enough in the future that deployment
// of 2.1 is exceedingly rare?
if ($err == 1 && preg_match('/no changes found/', $stdout)) {
return;
} else {
$message = $ex->getMessage();
$message = $this->censorMercurialErrorMessage($message);
throw new Exception($message);
}
}
}
/**
* Censor response bodies from Mercurial error messages.
*
* When Mercurial attempts to clone an HTTP repository but does not
* receive a response it expects, it emits the response body in the
* command output.
*
* This represents a potential SSRF issue, because an attacker with
* permission to create repositories can create one which points at the
* remote URI for some local service, then read the response from the
* error message. To prevent this, censor response bodies out of error
* messages.
*
* @param string Uncensored Mercurial command output.
* @return string Censored Mercurial command output.
*/
private function censorMercurialErrorMessage($message) {
return preg_replace(
'/^---%<---.*/sm',
pht('<Response body omitted from Mercurial error message.>')."\n",
$message);
}
/**
* @task hg
*/
private function installMercurialHook() {
$repository = $this->getRepository();
$path = $repository->getLocalPath().'/.hg/hgrc';
$identifier = $this->getHookContextIdentifier($repository);
$root = dirname(phutil_get_library_root('phabricator'));
$bin = $root.'/bin/commit-hook';
$data = array();
$data[] = '[hooks]';
// This hook handles normal pushes.
$data[] = csprintf(
'pretxnchangegroup.phabricator = TERM=dumb %s %s %s',
$bin,
$identifier,
'pretxnchangegroup');
// This one handles creating bookmarks.
$data[] = csprintf(
'prepushkey.phabricator = TERM=dumb %s %s %s',
$bin,
$identifier,
'prepushkey');
$data[] = null;
$data = implode("\n", $data);
$this->log('%s', pht('Installing commit hook config to "%s"...', $path));
Filesystem::writeFile($path, $data);
}
/* -( Pulling Subversion Working Copies )---------------------------------- */
/**
* @task svn
*/
private function executeSubversionCreate() {
$repository = $this->getRepository();
$path = rtrim($repository->getLocalPath(), '/');
execx('svnadmin create -- %s', $path);
}
/**
* @task svn
*/
private function installSubversionHook() {
$repository = $this->getRepository();
$root = $repository->getLocalPath();
$path = '/hooks/pre-commit';
$this->installHook($root.$path);
$revprop_path = '/hooks/pre-revprop-change';
$revprop_argv = array(
'--hook-mode',
'svn-revprop',
);
$this->installHook($root.$revprop_path, $revprop_argv);
}
}
diff --git a/webroot/rsrc/js/application/maniphest/behavior-line-chart-legacy.js b/webroot/rsrc/js/application/maniphest/behavior-line-chart-legacy.js
new file mode 100644
index 0000000000..187f39a8d4
--- /dev/null
+++ b/webroot/rsrc/js/application/maniphest/behavior-line-chart-legacy.js
@@ -0,0 +1,126 @@
+/**
+ * @provides javelin-behavior-line-chart-legacy
+ * @requires javelin-behavior
+ * javelin-dom
+ * javelin-vector
+ * phui-chart-css
+ */
+
+JX.behavior('line-chart-legacy', function(config) {
+
+ function fn(n) {
+ return n + '(' + JX.$A(arguments).slice(1).join(', ') + ')';
+ }
+
+ var h = JX.$(config.hardpoint);
+ var d = JX.Vector.getDim(h);
+
+ var padding = {
+ top: 24,
+ left: 48,
+ bottom: 48,
+ right: 32
+ };
+
+ var size = {
+ frameWidth: d.x,
+ frameHeight: d.y,
+ };
+
+ size.width = size.frameWidth - padding.left - padding.right;
+ size.height = size.frameHeight - padding.top - padding.bottom;
+
+ var x = d3.time.scale()
+ .range([0, size.width]);
+
+ var y = d3.scale.linear()
+ .range([size.height, 0]);
+
+ var xAxis = d3.svg.axis()
+ .scale(x)
+ .orient('bottom');
+
+ var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient('left');
+
+ var svg = d3.select('#' + config.hardpoint).append('svg')
+ .attr('width', size.frameWidth)
+ .attr('height', size.frameHeight)
+ .attr('class', 'chart');
+
+ var g = svg.append('g')
+ .attr('transform', fn('translate', padding.left, padding.top));
+
+ g.append('rect')
+ .attr('class', 'inner')
+ .attr('width', size.width)
+ .attr('height', size.height);
+
+ var line = d3.svg.line()
+ .x(function(d) { return x(d.date); })
+ .y(function(d) { return y(d.count); });
+
+ var data = [];
+ for (var ii = 0; ii < config.x[0].length; ii++) {
+ data.push(
+ {
+ date: new Date(config.x[0][ii] * 1000),
+ count: +config.y[0][ii]
+ });
+ }
+
+ x.domain(d3.extent(data, function(d) { return d.date; }));
+
+ var yex = d3.extent(data, function(d) { return d.count; });
+ yex[0] = 0;
+ yex[1] = yex[1] * 1.05;
+ y.domain(yex);
+
+ g.append('path')
+ .datum(data)
+ .attr('class', 'line')
+ .attr('d', line);
+
+ g.append('g')
+ .attr('class', 'x axis')
+ .attr('transform', fn('translate', 0, size.height))
+ .call(xAxis);
+
+ g.append('g')
+ .attr('class', 'y axis')
+ .attr('transform', fn('translate', 0, 0))
+ .call(yAxis);
+
+ var div = d3.select('body')
+ .append('div')
+ .attr('class', 'chart-tooltip')
+ .style('opacity', 0);
+
+ g.selectAll('dot')
+ .data(data)
+ .enter()
+ .append('circle')
+ .attr('class', 'point')
+ .attr('r', 3)
+ .attr('cx', function(d) { return x(d.date); })
+ .attr('cy', function(d) { return y(d.count); })
+ .on('mouseover', function(d) {
+ var d_y = d.date.getFullYear();
+
+ // NOTE: Javascript months are zero-based. See PHI1017.
+ var d_m = d.date.getMonth() + 1;
+
+ var d_d = d.date.getDate();
+
+ div
+ .html(d_y + '-' + d_m + '-' + d_d + ': ' + d.count)
+ .style('opacity', 0.9)
+ .style('left', (d3.event.pageX - 60) + 'px')
+ .style('top', (d3.event.pageY - 38) + 'px');
+ })
+ .on('mouseout', function() {
+ div.style('opacity', 0);
+ });
+
+});

File Metadata

Mime Type
text/x-diff
Expires
Fri, Mar 14, 3:07 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71978
Default Alt Text
(139 KB)

Event Timeline