diff --git a/resources/sql/patches/releeph.sql b/resources/sql/patches/releeph.sql new file mode 100644 index 000000000..a82435795 --- /dev/null +++ b/resources/sql/patches/releeph.sql @@ -0,0 +1,92 @@ +CREATE TABLE {$NAMESPACE}_releeph.`releeph_project` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + `phid` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `name` varchar(255) NOT NULL, + `trunkBranch` varchar(255) NOT NULL, + `repositoryID` int(10) unsigned NOT NULL, + `repositoryPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `arcanistProjectID` int(10) unsigned NOT NULL, + `createdByUserPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `isActive` tinyint(1) NOT NULL DEFAULT '1', + `projectID` int(10) unsigned DEFAULT NULL, + `details` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `projectName` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE {$NAMESPACE}_releeph.`releeph_branch` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + `basename` varchar(64) NOT NULL, + `releephProjectID` int(10) unsigned NOT NULL, + `createdByUserPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `cutPointCommitIdentifier` + varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `cutPointCommitPHID` + varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `isActive` tinyint(1) NOT NULL DEFAULT '1', + `symbolicName` varchar(64) DEFAULT NULL, + `details` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `phid` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `name` varchar(128) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `releephProjectID_2` (`releephProjectID`,`basename`), + UNIQUE KEY `releephProjectID_name` (`releephProjectID`,`name`), + UNIQUE KEY `releephProjectID` (`releephProjectID`,`symbolicName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE {$NAMESPACE}_releeph.`releeph_request` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + `phid` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `branchID` int(10) unsigned NOT NULL, + `summary` longtext CHARACTER SET utf8 COLLATE utf8_bin, + `requestUserPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `requestCommitIdentifier` + varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `requestCommitPHID` + varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `requestCommitOrdinal` int(10) unsigned NOT NULL, + `commitIdentifier` + varchar(40) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `committedByUserPHID` + varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `commitPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `status` tinyint(4) DEFAULT NULL, + `pickStatus` tinyint(4) DEFAULT NULL, + `details` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `userIntents` longtext CHARACTER SET utf8 COLLATE utf8_bin, + `inBranch` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `phid` (`phid`), + UNIQUE KEY `requestIdentifierBranch` (`requestCommitIdentifier`,`branchID`), + KEY `branchID` (`branchID`,`requestCommitOrdinal`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE {$NAMESPACE}_releeph.`releeph_requestevent` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + `releephRequestID` int(10) unsigned NOT NULL, + `actorPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `details` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `type` varchar(32) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE {$NAMESPACE}_releeph.`releeph_event` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + `releephProjectID` int(10) unsigned NOT NULL, + `releephBranchID` int(10) unsigned DEFAULT NULL, + `type` varchar(32) NOT NULL, + `epoch` int(10) unsigned DEFAULT NULL, + `actorPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `details` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 3f64a695a..43b2d86a4 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -1,3937 +1,4066 @@ <?php /** * This file is automatically generated. Use 'celerity_mapper.php' to rebuild * it. * @generated */ celerity_register_resource_map(array( '/rsrc/image/actions/edit.png' => array( 'hash' => 'ae90914d120ac3838ddc633b480343f3', 'uri' => '/res/ae90914d/rsrc/image/actions/edit.png', 'disk' => '/rsrc/image/actions/edit.png', 'type' => 'png', ), '/rsrc/image/avatar.png' => array( 'hash' => '1c5f255071537f05406adee86717ff27', 'uri' => '/res/1c5f2550/rsrc/image/avatar.png', 'disk' => '/rsrc/image/avatar.png', 'type' => 'png', ), '/rsrc/image/checker_dark.png' => array( 'hash' => '640f795343df76ebe5409aae6187e57f', 'uri' => '/res/640f7953/rsrc/image/checker_dark.png', 'disk' => '/rsrc/image/checker_dark.png', 'type' => 'png', ), '/rsrc/image/checker_light.png' => array( 'hash' => '7f8f3ef8beb0f2cc4cc69efb9e1c3308', 'uri' => '/res/7f8f3ef8/rsrc/image/checker_light.png', 'disk' => '/rsrc/image/checker_light.png', 'type' => 'png', ), '/rsrc/image/credit_cards.png' => array( 'hash' => '681448de424ea159b6ea68af04c046ae', 'uri' => '/res/681448de/rsrc/image/credit_cards.png', 'disk' => '/rsrc/image/credit_cards.png', 'type' => 'png', ), '/rsrc/image/darkload.gif' => array( 'hash' => '3a52cb7145d6e70f461fed21273117f2', 'uri' => '/res/3a52cb71/rsrc/image/darkload.gif', 'disk' => '/rsrc/image/darkload.gif', 'type' => 'gif', ), '/rsrc/image/divot.png' => array( 'hash' => '3be267bd11ea375bf68e808893718e0e', 'uri' => '/res/3be267bd/rsrc/image/divot.png', 'disk' => '/rsrc/image/divot.png', 'type' => 'png', ), '/rsrc/image/grippy_texture.png' => array( 'hash' => 'a8945e12ceeaddd5b491a8d81cfa19c1', 'uri' => '/res/a8945e12/rsrc/image/grippy_texture.png', 'disk' => '/rsrc/image/grippy_texture.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/arrow_branch.png' => array( 'hash' => 'f27b67520766e3d971722bcff703f3a8', 'uri' => '/res/f27b6752/rsrc/image/icon/fatcow/arrow_branch.png', 'disk' => '/rsrc/image/icon/fatcow/arrow_branch.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/arrow_merge.png' => array( 'hash' => 'c4bd97f3b1257439e2123ef69d2194d0', 'uri' => '/res/c4bd97f3/rsrc/image/icon/fatcow/arrow_merge.png', 'disk' => '/rsrc/image/icon/fatcow/arrow_merge.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/bullet_black.png' => array( 'hash' => '718f9c560a13766796f1be7dfaadeeab', 'uri' => '/res/718f9c56/rsrc/image/icon/fatcow/bullet_black.png', 'disk' => '/rsrc/image/icon/fatcow/bullet_black.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/bullet_orange.png' => array( 'hash' => 'c3bf91b65baacb27f2af143ab9180119', 'uri' => '/res/c3bf91b6/rsrc/image/icon/fatcow/bullet_orange.png', 'disk' => '/rsrc/image/icon/fatcow/bullet_orange.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/bullet_red.png' => array( 'hash' => '00273e4aa6ea3de630295610d6c9560c', 'uri' => '/res/00273e4a/rsrc/image/icon/fatcow/bullet_red.png', 'disk' => '/rsrc/image/icon/fatcow/bullet_red.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/calendar_edit.png' => array( 'hash' => 'de249c0f4f37bf5b2c69ff39ec5573fb', 'uri' => '/res/de249c0f/rsrc/image/icon/fatcow/calendar_edit.png', 'disk' => '/rsrc/image/icon/fatcow/calendar_edit.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/document_black.png' => array( 'hash' => '44d65a7f05a9c921719deedc160d68f7', 'uri' => '/res/44d65a7f/rsrc/image/icon/fatcow/document_black.png', 'disk' => '/rsrc/image/icon/fatcow/document_black.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_blue.png' => array( 'hash' => '75a080492f900fbe489e4b27e403962b', 'uri' => '/res/75a08049/rsrc/image/icon/fatcow/flag_blue.png', 'disk' => '/rsrc/image/icon/fatcow/flag_blue.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_finish.png' => array( 'hash' => '4af11fc7fab8e4610cbc3c88a02d4f78', 'uri' => '/res/4af11fc7/rsrc/image/icon/fatcow/flag_finish.png', 'disk' => '/rsrc/image/icon/fatcow/flag_finish.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_ghost.png' => array( 'hash' => '14c9f30a37b43f276f27a27a924bf02d', 'uri' => '/res/14c9f30a/rsrc/image/icon/fatcow/flag_ghost.png', 'disk' => '/rsrc/image/icon/fatcow/flag_ghost.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_green.png' => array( 'hash' => 'fed01374cd396cb774872762dcc447e1', 'uri' => '/res/fed01374/rsrc/image/icon/fatcow/flag_green.png', 'disk' => '/rsrc/image/icon/fatcow/flag_green.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_orange.png' => array( 'hash' => '88008cb8bb99761a37e5a743e2455aeb', 'uri' => '/res/88008cb8/rsrc/image/icon/fatcow/flag_orange.png', 'disk' => '/rsrc/image/icon/fatcow/flag_orange.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_pink.png' => array( 'hash' => '2f199f06ffc3dfc81b7561a057e0bc33', 'uri' => '/res/2f199f06/rsrc/image/icon/fatcow/flag_pink.png', 'disk' => '/rsrc/image/icon/fatcow/flag_pink.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_purple.png' => array( 'hash' => '16358629dc86c39550b575586eb5df80', 'uri' => '/res/16358629/rsrc/image/icon/fatcow/flag_purple.png', 'disk' => '/rsrc/image/icon/fatcow/flag_purple.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_red.png' => array( 'hash' => '210c28b4d93c439a499f5814f5e05772', 'uri' => '/res/210c28b4/rsrc/image/icon/fatcow/flag_red.png', 'disk' => '/rsrc/image/icon/fatcow/flag_red.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/flag_yellow.png' => array( 'hash' => 'bdfd73744a80bb80329ae50bc8a5f962', 'uri' => '/res/bdfd7374/rsrc/image/icon/fatcow/flag_yellow.png', 'disk' => '/rsrc/image/icon/fatcow/flag_yellow.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/folder.png' => array( 'hash' => '25e46cf9d210dde2242332296f79938c', 'uri' => '/res/25e46cf9/rsrc/image/icon/fatcow/folder.png', 'disk' => '/rsrc/image/icon/fatcow/folder.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/folder_go.png' => array( 'hash' => 'ba922ff7959309f51a14cb7ed5124d8b', 'uri' => '/res/ba922ff7/rsrc/image/icon/fatcow/folder_go.png', 'disk' => '/rsrc/image/icon/fatcow/folder_go.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/key_question.png' => array( 'hash' => '530a6448a4b91edec091a9292ccfd3d9', 'uri' => '/res/530a6448/rsrc/image/icon/fatcow/key_question.png', 'disk' => '/rsrc/image/icon/fatcow/key_question.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/link.png' => array( 'hash' => 'be1bea49b216548433014f3324902928', 'uri' => '/res/be1bea49/rsrc/image/icon/fatcow/link.png', 'disk' => '/rsrc/image/icon/fatcow/link.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/page_white_edit.png' => array( 'hash' => 'e7b7e7f2d9730bc80bc5c9eac1f3e36d', 'uri' => '/res/e7b7e7f2/rsrc/image/icon/fatcow/page_white_edit.png', 'disk' => '/rsrc/image/icon/fatcow/page_white_edit.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/page_white_link.png' => array( 'hash' => '1cfbad14412bda6c6f132dcc7c8725fd', 'uri' => '/res/1cfbad14/rsrc/image/icon/fatcow/page_white_link.png', 'disk' => '/rsrc/image/icon/fatcow/page_white_link.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/page_white_put.png' => array( 'hash' => 'bb7308aa5ac40137a8262da395a267fd', 'uri' => '/res/bb7308aa/rsrc/image/icon/fatcow/page_white_put.png', 'disk' => '/rsrc/image/icon/fatcow/page_white_put.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/page_white_text.png' => array( 'hash' => 'e47d590b626f617fb7d1d44e96e8fd11', 'uri' => '/res/e47d590b/rsrc/image/icon/fatcow/page_white_text.png', 'disk' => '/rsrc/image/icon/fatcow/page_white_text.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/source/conduit.png' => array( 'hash' => '1cae0656580aa3cd0b54b9d98306b1b9', 'uri' => '/res/1cae0656/rsrc/image/icon/fatcow/source/conduit.png', 'disk' => '/rsrc/image/icon/fatcow/source/conduit.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/source/email.png' => array( 'hash' => '93bdb3e168da1ed68f50c42125729d4e', 'uri' => '/res/93bdb3e1/rsrc/image/icon/fatcow/source/email.png', 'disk' => '/rsrc/image/icon/fatcow/source/email.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/source/fax.png' => array( 'hash' => 'd7dedf229841f2d041b347afd881596f', 'uri' => '/res/d7dedf22/rsrc/image/icon/fatcow/source/fax.png', 'disk' => '/rsrc/image/icon/fatcow/source/fax.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/source/mobile.png' => array( 'hash' => '786e7146d1e7d7318baf76c9d2baad97', 'uri' => '/res/786e7146/rsrc/image/icon/fatcow/source/mobile.png', 'disk' => '/rsrc/image/icon/fatcow/source/mobile.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/source/tablet.png' => array( 'hash' => '374cd40e4965be6b2fbdef4059d0ca05', 'uri' => '/res/374cd40e/rsrc/image/icon/fatcow/source/tablet.png', 'disk' => '/rsrc/image/icon/fatcow/source/tablet.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/source/web.png' => array( 'hash' => 'f4882a8f5619ba505ca033f72a340635', 'uri' => '/res/f4882a8f/rsrc/image/icon/fatcow/source/web.png', 'disk' => '/rsrc/image/icon/fatcow/source/web.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/thumbnails/default160x120.png' => array( 'hash' => '1b52ebd1fe0eee3ed0abfc382991b265', 'uri' => '/res/1b52ebd1/rsrc/image/icon/fatcow/thumbnails/default160x120.png', 'disk' => '/rsrc/image/icon/fatcow/thumbnails/default160x120.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/thumbnails/default60x45.png' => array( 'hash' => '048d851d8d1daad4754e891e734c1899', 'uri' => '/res/048d851d/rsrc/image/icon/fatcow/thumbnails/default60x45.png', 'disk' => '/rsrc/image/icon/fatcow/thumbnails/default60x45.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/thumbnails/image160x120.png' => array( 'hash' => '434acbd8dbbc2da9f09f6205a396eba1', 'uri' => '/res/434acbd8/rsrc/image/icon/fatcow/thumbnails/image160x120.png', 'disk' => '/rsrc/image/icon/fatcow/thumbnails/image160x120.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/thumbnails/image60x45.png' => array( 'hash' => '29f7872dc53588fe0b8f0b330c7ee23a', 'uri' => '/res/29f7872d/rsrc/image/icon/fatcow/thumbnails/image60x45.png', 'disk' => '/rsrc/image/icon/fatcow/thumbnails/image60x45.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png' => array( 'hash' => '39d2e22541658a3472ba41ae2fa548e5', 'uri' => '/res/39d2e225/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png', 'disk' => '/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png' => array( 'hash' => 'b3572e9317cbed5184d12bdfabed2727', 'uri' => '/res/b3572e93/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png', 'disk' => '/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/thumbnails/zip160x120.png' => array( 'hash' => 'e505108688a903b5cfb674707a289bcc', 'uri' => '/res/e5051086/rsrc/image/icon/fatcow/thumbnails/zip160x120.png', 'disk' => '/rsrc/image/icon/fatcow/thumbnails/zip160x120.png', 'type' => 'png', ), '/rsrc/image/icon/fatcow/thumbnails/zip60x45.png' => array( 'hash' => 'f00716f4e8f7a95e70d43504f06be0a6', 'uri' => '/res/f00716f4/rsrc/image/icon/fatcow/thumbnails/zip60x45.png', 'disk' => '/rsrc/image/icon/fatcow/thumbnails/zip60x45.png', 'type' => 'png', ), '/rsrc/image/icon/lightbox/close-2.png' => array( 'hash' => '72ff3ddcc1ed5d19a715ed6242114b53', 'uri' => '/res/72ff3ddc/rsrc/image/icon/lightbox/close-2.png', 'disk' => '/rsrc/image/icon/lightbox/close-2.png', 'type' => 'png', ), '/rsrc/image/icon/lightbox/close-hover-2.png' => array( 'hash' => '6ad4bd4a7820547a1d9041752546ba16', 'uri' => '/res/6ad4bd4a/rsrc/image/icon/lightbox/close-hover-2.png', 'disk' => '/rsrc/image/icon/lightbox/close-hover-2.png', 'type' => 'png', ), '/rsrc/image/icon/lightbox/left-arrow-2.png' => array( 'hash' => 'd84cbb0d42739f87b8f25b2f1d2f1153', 'uri' => '/res/d84cbb0d/rsrc/image/icon/lightbox/left-arrow-2.png', 'disk' => '/rsrc/image/icon/lightbox/left-arrow-2.png', 'type' => 'png', ), '/rsrc/image/icon/lightbox/left-arrow-hover-2.png' => array( 'hash' => 'cdf05f98fff3f390cd8df0c89894a3e1', 'uri' => '/res/cdf05f98/rsrc/image/icon/lightbox/left-arrow-hover-2.png', 'disk' => '/rsrc/image/icon/lightbox/left-arrow-hover-2.png', 'type' => 'png', ), '/rsrc/image/icon/lightbox/right-arrow-2.png' => array( 'hash' => '52021038cb6995c71f62a804bc2d420d', 'uri' => '/res/52021038/rsrc/image/icon/lightbox/right-arrow-2.png', 'disk' => '/rsrc/image/icon/lightbox/right-arrow-2.png', 'type' => 'png', ), '/rsrc/image/icon/lightbox/right-arrow-hover-2.png' => array( 'hash' => '65d5756b7b9cfcdeb2eb197a9aa6bbd2', 'uri' => '/res/65d5756b/rsrc/image/icon/lightbox/right-arrow-hover-2.png', 'disk' => '/rsrc/image/icon/lightbox/right-arrow-hover-2.png', 'type' => 'png', ), '/rsrc/image/icon/subscribe.png' => array( 'hash' => '5f47a4b17de245af39a4e7a097e40623', 'uri' => '/res/5f47a4b1/rsrc/image/icon/subscribe.png', 'disk' => '/rsrc/image/icon/subscribe.png', 'type' => 'png', ), '/rsrc/image/icon/tango/attachment.png' => array( 'hash' => '776fed2de89803fd8a0ba4b9deede230', 'uri' => '/res/776fed2d/rsrc/image/icon/tango/attachment.png', 'disk' => '/rsrc/image/icon/tango/attachment.png', 'type' => 'png', ), '/rsrc/image/icon/tango/edit.png' => array( 'hash' => 'c0028d99dcf4e9559bbf3c88ce2d8a8d', 'uri' => '/res/c0028d99/rsrc/image/icon/tango/edit.png', 'disk' => '/rsrc/image/icon/tango/edit.png', 'type' => 'png', ), '/rsrc/image/icon/tango/go-down.png' => array( 'hash' => '96862812cbb0445573c264dc057b8300', 'uri' => '/res/96862812/rsrc/image/icon/tango/go-down.png', 'disk' => '/rsrc/image/icon/tango/go-down.png', 'type' => 'png', ), '/rsrc/image/icon/tango/log.png' => array( 'hash' => 'a6f72499bef279ff6807a7dbc5148f1e', 'uri' => '/res/a6f72499/rsrc/image/icon/tango/log.png', 'disk' => '/rsrc/image/icon/tango/log.png', 'type' => 'png', ), '/rsrc/image/icon/tango/upload.png' => array( 'hash' => '8c11b63d6d99db3d7159c5d9a94e3062', 'uri' => '/res/8c11b63d/rsrc/image/icon/tango/upload.png', 'disk' => '/rsrc/image/icon/tango/upload.png', 'type' => 'png', ), '/rsrc/image/icon/unsubscribe.png' => array( 'hash' => '29429ad65aa3af50b072b32087057361', 'uri' => '/res/29429ad6/rsrc/image/icon/unsubscribe.png', 'disk' => '/rsrc/image/icon/unsubscribe.png', 'type' => 'png', ), '/rsrc/image/loading.gif' => array( 'hash' => '664297671941142f37d8c89e717ff2ce', 'uri' => '/res/66429767/rsrc/image/loading.gif', 'disk' => '/rsrc/image/loading.gif', 'type' => 'gif', ), '/rsrc/image/main_texture.png' => array( 'hash' => 'e34d8143384721be73ec9b7532a977ab', 'uri' => '/res/e34d8143/rsrc/image/main_texture.png', 'disk' => '/rsrc/image/main_texture.png', 'type' => 'png', ), '/rsrc/image/menu_texture.png' => array( 'hash' => 'ad020b1529b3a3b3480ca9de1d5f1e40', 'uri' => '/res/ad020b15/rsrc/image/menu_texture.png', 'disk' => '/rsrc/image/menu_texture.png', 'type' => 'png', ), '/rsrc/image/search.png' => array( 'hash' => 'ff7da044e6f923b8f569dec11f97e5e5', 'uri' => '/res/ff7da044/rsrc/image/search.png', 'disk' => '/rsrc/image/search.png', 'type' => 'png', ), '/rsrc/image/sprite-apps-X2.png' => array( 'hash' => '361e64ded74eee1094127c7878c2c385', 'uri' => '/res/361e64de/rsrc/image/sprite-apps-X2.png', 'disk' => '/rsrc/image/sprite-apps-X2.png', 'type' => 'png', ), '/rsrc/image/sprite-apps-large-X2.png' => array( 'hash' => '73507e04b4bd4d1e8e7544f7c424fc0f', 'uri' => '/res/73507e04/rsrc/image/sprite-apps-large-X2.png', 'disk' => '/rsrc/image/sprite-apps-large-X2.png', 'type' => 'png', ), '/rsrc/image/sprite-apps-large.png' => array( 'hash' => '6a5aade6134954171f2f1f8507270632', 'uri' => '/res/6a5aade6/rsrc/image/sprite-apps-large.png', 'disk' => '/rsrc/image/sprite-apps-large.png', 'type' => 'png', ), '/rsrc/image/sprite-apps-xlarge.png' => array( 'hash' => '992d2c278b6a22c0fa874d457a252fbd', 'uri' => '/res/992d2c27/rsrc/image/sprite-apps-xlarge.png', 'disk' => '/rsrc/image/sprite-apps-xlarge.png', 'type' => 'png', ), '/rsrc/image/sprite-apps.png' => array( 'hash' => '5e76c53e9f61755e5d3e7befa9d73ae5', 'uri' => '/res/5e76c53e/rsrc/image/sprite-apps.png', 'disk' => '/rsrc/image/sprite-apps.png', 'type' => 'png', ), '/rsrc/image/sprite-conpherence-X2.png' => array( 'hash' => '5e47868b00933a9afb6c844e464e6b23', 'uri' => '/res/5e47868b/rsrc/image/sprite-conpherence-X2.png', 'disk' => '/rsrc/image/sprite-conpherence-X2.png', 'type' => 'png', ), '/rsrc/image/sprite-conpherence.png' => array( 'hash' => 'ca51f1be25213262d68e626e4cab7f0f', 'uri' => '/res/ca51f1be/rsrc/image/sprite-conpherence.png', 'disk' => '/rsrc/image/sprite-conpherence.png', 'type' => 'png', ), '/rsrc/image/sprite-docs-X2.png' => array( 'hash' => '57d3286ce88133f3ec9240e35f6bb897', 'uri' => '/res/57d3286c/rsrc/image/sprite-docs-X2.png', 'disk' => '/rsrc/image/sprite-docs-X2.png', 'type' => 'png', ), '/rsrc/image/sprite-docs.png' => array( 'hash' => 'b2b089072d6eddd831402a77c02b5736', 'uri' => '/res/b2b08907/rsrc/image/sprite-docs.png', 'disk' => '/rsrc/image/sprite-docs.png', 'type' => 'png', ), '/rsrc/image/sprite-gradient.png' => array( 'hash' => '92aebaab67dcc6baf2ea99294368d895', 'uri' => '/res/92aebaab/rsrc/image/sprite-gradient.png', 'disk' => '/rsrc/image/sprite-gradient.png', 'type' => 'png', ), '/rsrc/image/sprite-icon-X2.png' => array( 'hash' => 'c9fae25bc6221922ce26517e654a18e4', 'uri' => '/res/c9fae25b/rsrc/image/sprite-icon-X2.png', 'disk' => '/rsrc/image/sprite-icon-X2.png', 'type' => 'png', ), '/rsrc/image/sprite-icon.png' => array( 'hash' => 'b690ea69bf5f2abe84d0a6e9ef64b03d', 'uri' => '/res/b690ea69/rsrc/image/sprite-icon.png', 'disk' => '/rsrc/image/sprite-icon.png', 'type' => 'png', ), '/rsrc/image/sprite-menu-X2.png' => array( 'hash' => '9f5cae08146fbe3b7e865b60c64121d1', 'uri' => '/res/9f5cae08/rsrc/image/sprite-menu-X2.png', 'disk' => '/rsrc/image/sprite-menu-X2.png', 'type' => 'png', ), '/rsrc/image/sprite-menu.png' => array( 'hash' => 'cc82b64d031dafa2b2a62cc8effa62f6', 'uri' => '/res/cc82b64d/rsrc/image/sprite-menu.png', 'disk' => '/rsrc/image/sprite-menu.png', 'type' => 'png', ), '/rsrc/image/sprite-tokens.png' => array( 'hash' => '67c46fd75c885b76ecbfe46e71a476cc', 'uri' => '/res/67c46fd7/rsrc/image/sprite-tokens.png', 'disk' => '/rsrc/image/sprite-tokens.png', 'type' => 'png', ), '/rsrc/image/texture/dark-menu-hover.png' => array( 'hash' => 'a214a732644be34872e895b338b5d639', 'uri' => '/res/a214a732/rsrc/image/texture/dark-menu-hover.png', 'disk' => '/rsrc/image/texture/dark-menu-hover.png', 'type' => 'png', ), '/rsrc/image/texture/dark-menu.png' => array( 'hash' => '41ee673a762cec48a154b456ad5ac204', 'uri' => '/res/41ee673a/rsrc/image/texture/dark-menu.png', 'disk' => '/rsrc/image/texture/dark-menu.png', 'type' => 'png', ), '/rsrc/image/texture/dust_background.jpg' => array( 'hash' => '1ff330c03712e08ca2eed006ccc6c1e7', 'uri' => '/res/1ff330c0/rsrc/image/texture/dust_background.jpg', 'disk' => '/rsrc/image/texture/dust_background.jpg', 'type' => 'jpg', ), '/rsrc/image/texture/pholio-background.gif' => array( 'hash' => 'cf4561af116edf393dc583e5119fb412', 'uri' => '/res/cf4561af/rsrc/image/texture/pholio-background.gif', 'disk' => '/rsrc/image/texture/pholio-background.gif', 'type' => 'gif', ), '/rsrc/image/texture/table_header.png' => array( 'hash' => '4ed3f56a30d3749e8f62052b9735a316', 'uri' => '/res/4ed3f56a/rsrc/image/texture/table_header.png', 'disk' => '/rsrc/image/texture/table_header.png', 'type' => 'png', ), '/rsrc/image/texture/table_header_hover.png' => array( 'hash' => 'ea1f71a604e9b4859de1e25751540437', 'uri' => '/res/ea1f71a6/rsrc/image/texture/table_header_hover.png', 'disk' => '/rsrc/image/texture/table_header_hover.png', 'type' => 'png', ), '/rsrc/image/texture/table_header_tall.png' => array( 'hash' => 'b05525601f78d759f1c5e47fd9c1a8aa', 'uri' => '/res/b0552560/rsrc/image/texture/table_header_tall.png', 'disk' => '/rsrc/image/texture/table_header_tall.png', 'type' => 'png', ), '/rsrc/swf/aphlict.swf' => array( 'hash' => '4b9a9d83bebaf254f3790e87b45c1f92', 'uri' => '/res/4b9a9d83/rsrc/swf/aphlict.swf', 'disk' => '/rsrc/swf/aphlict.swf', 'type' => 'swf', ), 'aphront-attached-file-view-css' => array( 'uri' => '/res/a6ca5487/rsrc/css/aphront/attached-file-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/attached-file-view.css', ), 'aphront-bars' => array( 'uri' => '/res/d7bd9032/rsrc/css/core/aphront-bars.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/aphront-bars.css', ), 'aphront-calendar-view-css' => array( 'uri' => '/res/73061a31/rsrc/css/aphront/calendar-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/calendar-view.css', ), 'aphront-contextbar-view-css' => array( 'uri' => '/res/ecfd5ba9/rsrc/css/aphront/context-bar.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/context-bar.css', ), 'aphront-dark-console-css' => array( 'uri' => '/res/0d316573/rsrc/css/aphront/dark-console.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/dark-console.css', ), 'aphront-dialog-view-css' => array( 'uri' => '/res/215b3ab1/rsrc/css/aphront/dialog-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/dialog-view.css', ), 'aphront-error-view-css' => array( 'uri' => '/res/5f43a7c5/rsrc/css/aphront/error-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/error-view.css', ), 'aphront-form-view-css' => array( 'uri' => '/res/ed8c70fa/rsrc/css/aphront/form-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/form-view.css', ), 'aphront-list-filter-view-css' => array( 'uri' => '/res/cc6e940e/rsrc/css/aphront/list-filter-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/list-filter-view.css', ), 'aphront-notes' => array( 'uri' => '/res/f8f3dcfa/rsrc/css/core/aphront-notes.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/aphront-notes.css', ), 'aphront-pager-view-css' => array( 'uri' => '/res/43fb79f0/rsrc/css/aphront/pager-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/pager-view.css', ), 'aphront-panel-view-css' => array( 'uri' => '/res/3d1420b3/rsrc/css/aphront/panel-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/panel-view.css', ), 'aphront-request-failure-view-css' => array( 'uri' => '/res/c9a43002/rsrc/css/aphront/request-failure-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/request-failure-view.css', ), 'aphront-table-view-css' => array( 'uri' => '/res/fd33a0f0/rsrc/css/aphront/table-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/table-view.css', ), 'aphront-tokenizer-control-css' => array( 'uri' => '/res/207105f0/rsrc/css/aphront/tokenizer.css', 'type' => 'css', 'requires' => array( 0 => 'aphront-typeahead-control-css', ), 'disk' => '/rsrc/css/aphront/tokenizer.css', ), 'aphront-tooltip-css' => array( 'uri' => '/res/3a7d8e07/rsrc/css/aphront/tooltip.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/tooltip.css', ), 'aphront-two-column-view-css' => array( 'uri' => '/res/7afa129f/rsrc/css/aphront/two-column.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/two-column.css', ), 'aphront-typeahead-control-css' => array( 'uri' => '/res/ef59c20c/rsrc/css/aphront/typeahead.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/typeahead.css', ), 'config-options-css' => array( 'uri' => '/res/e6c21f2f/rsrc/css/application/config/config-options.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/config/config-options.css', ), 'conpherence-header-pane-css' => array( 'uri' => '/res/11c32adc/rsrc/css/application/conpherence/header-pane.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/conpherence/header-pane.css', ), 'conpherence-menu-css' => array( 'uri' => '/res/0dc6b412/rsrc/css/application/conpherence/menu.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/conpherence/menu.css', ), 'conpherence-message-pane-css' => array( 'uri' => '/res/3aa15b9e/rsrc/css/application/conpherence/message-pane.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/conpherence/message-pane.css', ), 'conpherence-update-css' => array( 'uri' => '/res/92094ed7/rsrc/css/application/conpherence/update.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/conpherence/update.css', ), 'conpherence-widget-pane-css' => array( 'uri' => '/res/f728d1fc/rsrc/css/application/conpherence/widget-pane.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/conpherence/widget-pane.css', ), 'differential-changeset-view-css' => array( 'uri' => '/res/ea694162/rsrc/css/application/differential/changeset-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/changeset-view.css', ), 'differential-core-view-css' => array( 'uri' => '/res/85fe5117/rsrc/css/application/differential/core.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/core.css', ), 'differential-inline-comment-editor' => array( 'uri' => '/res/e0ad34ac/rsrc/js/application/differential/DifferentialInlineCommentEditor.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-dom', 1 => 'javelin-util', 2 => 'javelin-stratcom', 3 => 'javelin-install', 4 => 'javelin-request', 5 => 'javelin-workflow', ), 'disk' => '/rsrc/js/application/differential/DifferentialInlineCommentEditor.js', ), 'differential-local-commits-view-css' => array( 'uri' => '/res/224f3703/rsrc/css/application/differential/local-commits-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/local-commits-view.css', ), 'differential-results-table-css' => array( 'uri' => '/res/aab3123c/rsrc/css/application/differential/results-table.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/results-table.css', ), 'differential-revision-add-comment-css' => array( 'uri' => '/res/849748d3/rsrc/css/application/differential/add-comment.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/add-comment.css', ), 'differential-revision-comment-css' => array( 'uri' => '/res/42c222f4/rsrc/css/application/differential/revision-comment.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-comment.css', ), 'differential-revision-comment-list-css' => array( 'uri' => '/res/3b31faa3/rsrc/css/application/differential/revision-comment-list.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-comment-list.css', ), 'differential-revision-history-css' => array( 'uri' => '/res/d41bc64c/rsrc/css/application/differential/revision-history.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-history.css', ), 'differential-revision-list-css' => array( 'uri' => '/res/fe6c4721/rsrc/css/application/differential/revision-list.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-list.css', ), 'differential-table-of-contents-css' => array( 'uri' => '/res/4fde8bfc/rsrc/css/application/differential/table-of-contents.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/table-of-contents.css', ), 'diffusion-commit-view-css' => array( 'uri' => '/res/b445944e/rsrc/css/application/diffusion/commit-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/diffusion/commit-view.css', ), 'diffusion-icons-css' => array( 'uri' => '/res/b93e32c9/rsrc/css/application/diffusion/diffusion-icons.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/diffusion/diffusion-icons.css', ), 'diffusion-source-css' => array( 'uri' => '/res/e76bcd50/rsrc/css/application/diffusion/diffusion-source.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/diffusion/diffusion-source.css', ), 'global-drag-and-drop-css' => array( 'uri' => '/res/4e24cb65/rsrc/css/application/files/global-drag-and-drop.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/files/global-drag-and-drop.css', ), 'herald-css' => array( 'uri' => '/res/2150a55d/rsrc/css/application/herald/herald.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/herald/herald.css', ), 'herald-rule-editor' => array( 'uri' => '/res/f35d7e23/rsrc/js/application/herald/HeraldRuleEditor.js', 'type' => 'js', 'requires' => array( 0 => 'multirow-row-manager', 1 => 'javelin-install', 2 => 'javelin-typeahead', 3 => 'javelin-util', 4 => 'javelin-dom', 5 => 'javelin-tokenizer', 6 => 'javelin-typeahead-preloaded-source', 7 => 'javelin-stratcom', 8 => 'javelin-json', 9 => 'phabricator-prefab', ), 'disk' => '/rsrc/js/application/herald/HeraldRuleEditor.js', ), 'herald-test-css' => array( 'uri' => '/res/c0cd6bdb/rsrc/css/application/herald/herald-test.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/herald/herald-test.css', ), 'inline-comment-summary-css' => array( 'uri' => '/res/338704f7/rsrc/css/application/diff/inline-comment-summary.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/diff/inline-comment-summary.css', ), 'javelin-aphlict' => array( 'uri' => '/res/c0b9e53f/rsrc/js/application/aphlict/Aphlict.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', ), 'disk' => '/rsrc/js/application/aphlict/Aphlict.js', ), 'javelin-behavior' => array( 'uri' => '/res/ef4eda09/rsrc/js/javelin/lib/behavior.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-magical-init', ), 'disk' => '/rsrc/js/javelin/lib/behavior.js', ), 'javelin-behavior-aphlict-dropdown' => array( 'uri' => '/res/2418f448/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-request', 2 => 'javelin-stratcom', 3 => 'javelin-vector', 4 => 'javelin-dom', 5 => 'javelin-uri', ), 'disk' => '/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js', ), 'javelin-behavior-aphlict-listen' => array( 'uri' => '/res/6dde3f43/rsrc/js/application/aphlict/behavior-aphlict-listen.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-aphlict', 2 => 'javelin-stratcom', 3 => 'javelin-request', 4 => 'javelin-uri', 5 => 'javelin-dom', 6 => 'javelin-json', 7 => 'phabricator-notification', ), 'disk' => '/rsrc/js/application/aphlict/behavior-aphlict-listen.js', ), 'javelin-behavior-aphront-basic-tokenizer' => array( 'uri' => '/res/cf049052/rsrc/js/application/core/behavior-tokenizer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'phabricator-prefab', ), 'disk' => '/rsrc/js/application/core/behavior-tokenizer.js', ), 'javelin-behavior-aphront-crop' => array( 'uri' => '/res/cda1eace/rsrc/js/application/core/behavior-crop.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-vector', 3 => 'javelin-magical-init', ), 'disk' => '/rsrc/js/application/core/behavior-crop.js', ), 'javelin-behavior-aphront-drag-and-drop' => array( 'uri' => '/res/8dd5fd78/rsrc/js/application/core/behavior-drag-and-drop.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'phabricator-file-upload', 3 => 'phabricator-drag-and-drop-file-upload', ), 'disk' => '/rsrc/js/application/core/behavior-drag-and-drop.js', ), 'javelin-behavior-aphront-drag-and-drop-textarea' => array( 'uri' => '/res/853e33b9/rsrc/js/application/core/behavior-drag-and-drop-textarea.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'phabricator-drag-and-drop-file-upload', 3 => 'phabricator-paste-file-upload', 4 => 'phabricator-textareautils', ), 'disk' => '/rsrc/js/application/core/behavior-drag-and-drop-textarea.js', ), 'javelin-behavior-aphront-form-disable-on-submit' => array( 'uri' => '/res/b5052cd0/rsrc/js/application/core/behavior-form.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/behavior-form.js', ), 'javelin-behavior-aphront-more' => array( 'uri' => '/res/9ad83c3c/rsrc/js/application/core/behavior-more.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/behavior-more.js', ), 'javelin-behavior-audit-preview' => array( 'uri' => '/res/3048b073/rsrc/js/application/diffusion/behavior-audit-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), 'disk' => '/rsrc/js/application/diffusion/behavior-audit-preview.js', ), 'javelin-behavior-conpherence-drag-and-drop-photo' => array( 'uri' => '/res/9e3eb1cd/rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-workflow', 3 => 'phabricator-drag-and-drop-file-upload', ), 'disk' => '/rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js', ), 'javelin-behavior-conpherence-init' => array( 'uri' => '/res/700bba2e/rsrc/js/application/conpherence/behavior-init.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/conpherence/behavior-init.js', ), 'javelin-behavior-conpherence-menu' => array( 'uri' => '/res/cb1a5cf0/rsrc/js/application/conpherence/behavior-menu.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-request', 3 => 'javelin-stratcom', 4 => 'javelin-uri', 5 => 'javelin-util', 6 => 'javelin-workflow', ), 'disk' => '/rsrc/js/application/conpherence/behavior-menu.js', ), 'javelin-behavior-conpherence-pontificate' => array( 'uri' => '/res/15263692/rsrc/js/application/conpherence/behavior-pontificate.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'javelin-workflow', ), 'disk' => '/rsrc/js/application/conpherence/behavior-pontificate.js', ), 'javelin-behavior-conpherence-widget-pane' => array( 'uri' => '/res/43a0fe1b/rsrc/js/application/conpherence/behavior-widget-pane.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/conpherence/behavior-widget-pane.js', ), 'javelin-behavior-countdown-timer' => array( 'uri' => '/res/7468acb7/rsrc/js/application/countdown/timer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', ), 'disk' => '/rsrc/js/application/countdown/timer.js', ), 'javelin-behavior-dark-console' => array( 'uri' => '/res/89aeb6c0/rsrc/js/application/core/behavior-dark-console.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-request', 5 => 'phabricator-keyboard-shortcut', ), 'disk' => '/rsrc/js/application/core/behavior-dark-console.js', ), 'javelin-behavior-device' => array( 'uri' => '/res/a10b851b/rsrc/js/application/core/behavior-device.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', 3 => 'javelin-vector', 4 => 'javelin-install', ), 'disk' => '/rsrc/js/application/core/behavior-device.js', ), 'javelin-behavior-differential-accept-with-errors' => array( 'uri' => '/res/8fea67b3/rsrc/js/application/differential/behavior-accept-with-errors.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/differential/behavior-accept-with-errors.js', ), 'javelin-behavior-differential-add-reviewers-and-ccs' => array( 'uri' => '/res/27be3f81/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'phabricator-prefab', ), 'disk' => '/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js', ), 'javelin-behavior-differential-comment-jump' => array( 'uri' => '/res/b580229b/rsrc/js/application/differential/behavior-comment-jump.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-util', 2 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/differential/behavior-comment-jump.js', ), 'javelin-behavior-differential-diff-radios' => array( 'uri' => '/res/004cb66f/rsrc/js/application/differential/behavior-diff-radios.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/differential/behavior-diff-radios.js', ), 'javelin-behavior-differential-dropdown-menus' => array( 'uri' => '/res/752f5dfc/rsrc/js/application/differential/behavior-dropdown-menus.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'javelin-stratcom', 4 => 'phabricator-dropdown-menu', 5 => 'phabricator-menu-item', ), 'disk' => '/rsrc/js/application/differential/behavior-dropdown-menus.js', ), 'javelin-behavior-differential-edit-inline-comments' => array( 'uri' => '/res/70c1f3a3/rsrc/js/application/differential/behavior-edit-inline-comments.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', 3 => 'javelin-util', 4 => 'javelin-vector', 5 => 'differential-inline-comment-editor', ), 'disk' => '/rsrc/js/application/differential/behavior-edit-inline-comments.js', ), 'javelin-behavior-differential-feedback-preview' => array( 'uri' => '/res/5fbce8db/rsrc/js/application/differential/behavior-comment-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', 3 => 'javelin-request', 4 => 'javelin-util', 5 => 'phabricator-shaped-request', ), 'disk' => '/rsrc/js/application/differential/behavior-comment-preview.js', ), 'javelin-behavior-differential-keyboard-navigation' => array( 'uri' => '/res/89e93cc9/rsrc/js/application/differential/behavior-keyboard-nav.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', 3 => 'phabricator-keyboard-shortcut', ), 'disk' => '/rsrc/js/application/differential/behavior-keyboard-nav.js', ), 'javelin-behavior-differential-populate' => array( 'uri' => '/res/526c2615/rsrc/js/application/differential/behavior-populate.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-workflow', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-stratcom', 5 => 'javelin-behavior-device', 6 => 'javelin-vector', 7 => 'phabricator-tooltip', ), 'disk' => '/rsrc/js/application/differential/behavior-populate.js', ), 'javelin-behavior-differential-show-all-comments' => array( 'uri' => '/res/eaa12efc/rsrc/js/application/differential/behavior-show-all-comments.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/differential/behavior-show-all-comments.js', ), 'javelin-behavior-differential-show-field-details' => array( 'uri' => '/res/8d57f459/rsrc/js/application/differential/behavior-show-field-details.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/differential/behavior-show-field-details.js', ), 'javelin-behavior-differential-show-more' => array( 'uri' => '/res/b9f93090/rsrc/js/application/differential/behavior-show-more.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-workflow', 3 => 'javelin-util', 4 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/differential/behavior-show-more.js', ), 'javelin-behavior-differential-toggle-files' => array( 'uri' => '/res/ae937207/rsrc/js/application/differential/behavior-toggle-files.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/differential/behavior-toggle-files.js', ), 'javelin-behavior-differential-user-select' => array( 'uri' => '/res/23c51a5d/rsrc/js/application/differential/behavior-user-select.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/differential/behavior-user-select.js', ), 'javelin-behavior-diffusion-commit-branches' => array( 'uri' => '/res/1ede335a/rsrc/js/application/diffusion/behavior-commit-branches.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'javelin-request', ), 'disk' => '/rsrc/js/application/diffusion/behavior-commit-branches.js', ), 'javelin-behavior-diffusion-commit-graph' => array( 'uri' => '/res/62bd2035/rsrc/js/application/diffusion/behavior-commit-graph.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/diffusion/behavior-commit-graph.js', ), 'javelin-behavior-diffusion-jump-to' => array( 'uri' => '/res/7c42e1ba/rsrc/js/application/diffusion/behavior-jump-to.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-util', 2 => 'javelin-vector', 3 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/diffusion/behavior-jump-to.js', ), 'javelin-behavior-diffusion-line-linker' => array( 'uri' => '/res/12866f13/rsrc/js/application/diffusion/behavior-line-linker.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', 3 => 'javelin-history', ), 'disk' => '/rsrc/js/application/diffusion/behavior-line-linker.js', ), 'javelin-behavior-diffusion-pull-lastmodified' => array( 'uri' => '/res/29fe2790/rsrc/js/application/diffusion/behavior-pull-lastmodified.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'javelin-request', ), 'disk' => '/rsrc/js/application/diffusion/behavior-pull-lastmodified.js', ), 'javelin-behavior-error-log' => array( 'uri' => '/res/f46289e9/rsrc/js/application/core/behavior-error-log.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/behavior-error-log.js', ), 'javelin-behavior-fancy-datepicker' => array( 'uri' => '/res/0a1bc610/rsrc/js/application/core/behavior-fancy-datepicker.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-util', 2 => 'javelin-dom', 3 => 'javelin-stratcom', 4 => 'javelin-vector', ), 'disk' => '/rsrc/js/application/core/behavior-fancy-datepicker.js', ), 'javelin-behavior-global-drag-and-drop' => array( 'uri' => '/res/73ae3fd1/rsrc/js/application/core/behavior-global-drag-and-drop.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-uri', 3 => 'javelin-mask', 4 => 'phabricator-drag-and-drop-file-upload', ), 'disk' => '/rsrc/js/application/core/behavior-global-drag-and-drop.js', ), 'javelin-behavior-herald-rule-editor' => array( 'uri' => '/res/77a0c945/rsrc/js/application/herald/herald-rule-editor.js', 'type' => 'js', 'requires' => array( 0 => 'herald-rule-editor', 1 => 'javelin-behavior', ), 'disk' => '/rsrc/js/application/herald/herald-rule-editor.js', ), 'javelin-behavior-history-install' => array( 'uri' => '/res/e146a99b/rsrc/js/application/core/behavior-history-install.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-history', ), 'disk' => '/rsrc/js/application/core/behavior-history-install.js', ), 'javelin-behavior-konami' => array( 'uri' => '/res/2199602f/rsrc/js/application/core/behavior-konami.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/core/behavior-konami.js', ), 'javelin-behavior-lightbox-attachments' => array( 'uri' => '/res/08f5e202/rsrc/js/application/core/behavior-lightbox-attachments.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', 3 => 'javelin-mask', 4 => 'javelin-util', 5 => 'phabricator-busy', ), 'disk' => '/rsrc/js/application/core/behavior-lightbox-attachments.js', ), 'javelin-behavior-line-chart' => array( 'uri' => '/res/1aa5ac88/rsrc/js/application/maniphest/behavior-line-chart.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-vector', ), 'disk' => '/rsrc/js/application/maniphest/behavior-line-chart.js', ), 'javelin-behavior-load-blame' => array( 'uri' => '/res/138e2961/rsrc/js/application/diffusion/behavior-load-blame.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-request', ), 'disk' => '/rsrc/js/application/diffusion/behavior-load-blame.js', ), 'javelin-behavior-maniphest-batch-editor' => array( 'uri' => '/res/d22661be/rsrc/js/application/maniphest/behavior-batch-editor.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'phabricator-prefab', 4 => 'multirow-row-manager', 5 => 'javelin-json', ), 'disk' => '/rsrc/js/application/maniphest/behavior-batch-editor.js', ), 'javelin-behavior-maniphest-batch-selector' => array( 'uri' => '/res/398cf8d7/rsrc/js/application/maniphest/behavior-batch-selector.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/maniphest/behavior-batch-selector.js', ), 'javelin-behavior-maniphest-description-preview' => array( 'uri' => '/res/8acd6f07/rsrc/js/application/maniphest/behavior-task-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), 'disk' => '/rsrc/js/application/maniphest/behavior-task-preview.js', ), 'javelin-behavior-maniphest-subpriority-editor' => array( 'uri' => '/res/5e02f19a/rsrc/js/application/maniphest/behavior-subpriorityeditor.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-magical-init', 2 => 'javelin-dom', 3 => 'javelin-vector', 4 => 'javelin-stratcom', 5 => 'javelin-workflow', ), 'disk' => '/rsrc/js/application/maniphest/behavior-subpriorityeditor.js', ), 'javelin-behavior-maniphest-transaction-controls' => array( 'uri' => '/res/62465554/rsrc/js/application/maniphest/behavior-transaction-controls.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'phabricator-prefab', ), 'disk' => '/rsrc/js/application/maniphest/behavior-transaction-controls.js', ), 'javelin-behavior-maniphest-transaction-expand' => array( 'uri' => '/res/966410de/rsrc/js/application/maniphest/behavior-transaction-expand.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-workflow', 3 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/maniphest/behavior-transaction-expand.js', ), 'javelin-behavior-maniphest-transaction-preview' => array( 'uri' => '/res/855c9f0c/rsrc/js/application/maniphest/behavior-transaction-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'javelin-json', 4 => 'javelin-stratcom', 5 => 'phabricator-shaped-request', ), 'disk' => '/rsrc/js/application/maniphest/behavior-transaction-preview.js', ), 'javelin-behavior-owners-path-editor' => array( 'uri' => '/res/9cf78ffc/rsrc/js/application/owners/owners-path-editor.js', 'type' => 'js', 'requires' => array( 0 => 'owners-path-editor', 1 => 'javelin-behavior', ), 'disk' => '/rsrc/js/application/owners/owners-path-editor.js', ), 'javelin-behavior-phabricator-active-nav' => array( 'uri' => '/res/f879d4dd/rsrc/js/application/core/behavior-active-nav.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-vector', 3 => 'javelin-dom', 4 => 'javelin-uri', ), 'disk' => '/rsrc/js/application/core/behavior-active-nav.js', ), 'javelin-behavior-phabricator-autofocus' => array( 'uri' => '/res/2946bb89/rsrc/js/application/core/behavior-autofocus.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/behavior-autofocus.js', ), 'javelin-behavior-phabricator-file-tree' => array( 'uri' => '/res/e9c96597/rsrc/js/application/core/behavior-file-tree.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'phabricator-keyboard-shortcut', 2 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/core/behavior-file-tree.js', ), 'javelin-behavior-phabricator-gesture' => array( 'uri' => '/res/f186161c/rsrc/js/application/core/behavior-gesture.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-behavior-device', 2 => 'javelin-stratcom', 3 => 'javelin-vector', 4 => 'javelin-dom', 5 => 'javelin-magical-init', ), 'disk' => '/rsrc/js/application/core/behavior-gesture.js', ), 'javelin-behavior-phabricator-gesture-example' => array( 'uri' => '/res/da636e19/rsrc/js/application/uiexample/gesture-example.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-stratcom', 1 => 'javelin-behavior', 2 => 'javelin-vector', 3 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/uiexample/gesture-example.js', ), 'javelin-behavior-phabricator-keyboard-pager' => array( 'uri' => '/res/56d64eff/rsrc/js/application/core/behavior-keyboard-pager.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-uri', 2 => 'phabricator-keyboard-shortcut', ), 'disk' => '/rsrc/js/application/core/behavior-keyboard-pager.js', ), 'javelin-behavior-phabricator-keyboard-shortcuts' => array( 'uri' => '/res/c5eb65cd/rsrc/js/application/core/behavior-keyboard-shortcuts.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-workflow', 2 => 'javelin-json', 3 => 'javelin-dom', 4 => 'phabricator-keyboard-shortcut', ), 'disk' => '/rsrc/js/application/core/behavior-keyboard-shortcuts.js', ), 'javelin-behavior-phabricator-nav' => array( 'uri' => '/res/222b9329/rsrc/js/application/core/behavior-phabricator-nav.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-behavior-device', 2 => 'javelin-stratcom', 3 => 'javelin-dom', 4 => 'javelin-magical-init', 5 => 'javelin-vector', ), 'disk' => '/rsrc/js/application/core/behavior-phabricator-nav.js', ), 'javelin-behavior-phabricator-notification-example' => array( 'uri' => '/res/a6d51998/rsrc/js/application/uiexample/notification-example.js', 'type' => 'js', 'requires' => array( 0 => 'phabricator-notification', 1 => 'javelin-stratcom', 2 => 'javelin-behavior', 3 => 'javelin-uri', ), 'disk' => '/rsrc/js/application/uiexample/notification-example.js', ), 'javelin-behavior-phabricator-object-selector' => array( 'uri' => '/res/0c4b0d82/rsrc/js/application/core/behavior-object-selector.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-request', 3 => 'javelin-util', ), 'disk' => '/rsrc/js/application/core/behavior-object-selector.js', ), 'javelin-behavior-phabricator-oncopy' => array( 'uri' => '/res/f490b8d1/rsrc/js/application/core/behavior-oncopy.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/behavior-oncopy.js', ), 'javelin-behavior-phabricator-remarkup-assist' => array( 'uri' => '/res/07406487/rsrc/js/application/core/behavior-phabricator-remarkup-assist.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', 3 => 'phabricator-textareautils', ), 'disk' => '/rsrc/js/application/core/behavior-phabricator-remarkup-assist.js', ), 'javelin-behavior-phabricator-reveal-content' => array( 'uri' => '/res/a4fae14a/rsrc/js/application/core/behavior-reveal-content.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/behavior-reveal-content.js', ), 'javelin-behavior-phabricator-search-typeahead' => array( 'uri' => '/res/046ab274/rsrc/js/application/core/behavior-search-typeahead.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-typeahead-ondemand-source', 2 => 'javelin-typeahead', 3 => 'javelin-dom', 4 => 'javelin-uri', 5 => 'javelin-util', 6 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/application/core/behavior-search-typeahead.js', ), 'javelin-behavior-phabricator-tooltips' => array( 'uri' => '/res/e0b344c6/rsrc/js/application/core/behavior-tooltip.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-behavior-device', 2 => 'javelin-stratcom', 3 => 'phabricator-tooltip', ), 'disk' => '/rsrc/js/application/core/behavior-tooltip.js', ), 'javelin-behavior-phabricator-transaction-comment-form' => array( 'uri' => '/res/acc3ada1/rsrc/js/application/transactions/behavior-transaction-comment-form.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), 'disk' => '/rsrc/js/application/transactions/behavior-transaction-comment-form.js', ), 'javelin-behavior-phabricator-transaction-list' => array( 'uri' => '/res/f1fbb474/rsrc/js/application/transactions/behavior-transaction-list.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-workflow', 3 => 'javelin-dom', 4 => 'javelin-fx', ), 'disk' => '/rsrc/js/application/transactions/behavior-transaction-list.js', ), 'javelin-behavior-phabricator-watch-anchor' => array( 'uri' => '/res/b20b1cc2/rsrc/js/application/core/behavior-watch-anchor.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', 3 => 'javelin-vector', ), 'disk' => '/rsrc/js/application/core/behavior-watch-anchor.js', ), 'javelin-behavior-phame-post-preview' => array( 'uri' => '/res/ac4c503a/rsrc/js/application/phame/phame-post-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), 'disk' => '/rsrc/js/application/phame/phame-post-preview.js', ), 'javelin-behavior-pholio-mock-view' => array( - 'uri' => '/res/eefc43b3/rsrc/js/application/pholio/behavior-pholio-mock-view.js', + 'uri' => '/res/ecf5f969/rsrc/js/application/pholio/behavior-pholio-mock-view.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-util', 2 => 'javelin-stratcom', 3 => 'javelin-dom', 4 => 'javelin-vector', 5 => 'javelin-magical-init', 6 => 'javelin-request', 7 => 'javelin-history', 8 => 'javelin-workflow', 9 => 'javelin-mask', 10 => 'javelin-behavior-device', 11 => 'phabricator-keyboard-shortcut', ), 'disk' => '/rsrc/js/application/pholio/behavior-pholio-mock-view.js', ), 'javelin-behavior-phriction-document-preview' => array( 'uri' => '/res/f1665ecd/rsrc/js/application/phriction/phriction-document-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), 'disk' => '/rsrc/js/application/phriction/phriction-document-preview.js', ), 'javelin-behavior-ponder-feedback-preview' => array( 'uri' => '/res/2e802dd9/rsrc/js/application/ponder/behavior-comment-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), 'disk' => '/rsrc/js/application/ponder/behavior-comment-preview.js', ), 'javelin-behavior-ponder-votebox' => array( 'uri' => '/res/9d091af3/rsrc/js/application/ponder/behavior-votebox.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-util', 3 => 'javelin-stratcom', 4 => 'javelin-request', ), 'disk' => '/rsrc/js/application/ponder/behavior-votebox.js', ), 'javelin-behavior-project-create' => array( 'uri' => '/res/e91f3f8f/rsrc/js/application/projects/behavior-project-create.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', 3 => 'javelin-workflow', ), 'disk' => '/rsrc/js/application/projects/behavior-project-create.js', ), 'javelin-behavior-refresh-csrf' => array( 'uri' => '/res/6fd76d0f/rsrc/js/application/core/behavior-refresh-csrf.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-request', 1 => 'javelin-behavior', 2 => 'javelin-dom', 3 => 'phabricator-busy', ), 'disk' => '/rsrc/js/application/core/behavior-refresh-csrf.js', ), + 'javelin-behavior-releeph-preview-branch' => + array( + 'uri' => '/res/a77ebc86/rsrc/js/application/releeph/releeph-preview-branch.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-stratcom', + 3 => 'javelin-uri', + 4 => 'javelin-util', + ), + 'disk' => '/rsrc/js/application/releeph/releeph-preview-branch.js', + ), + 'javelin-behavior-releeph-request-state-change' => + array( + 'uri' => '/res/38f96ba8/rsrc/js/application/releeph/releeph-request-state-change.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-stratcom', + 3 => 'javelin-util', + 4 => 'phabricator-keyboard-shortcut', + 5 => 'phabricator-notification', + ), + 'disk' => '/rsrc/js/application/releeph/releeph-request-state-change.js', + ), + 'javelin-behavior-releeph-request-typeahead' => + array( + 'uri' => '/res/b52096e2/rsrc/js/application/releeph/releeph-request-typeahead.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-util', + 2 => 'javelin-dom', + 3 => 'javelin-typeahead', + 4 => 'javelin-tokenizer', + 5 => 'javelin-typeahead-preloaded-source', + 6 => 'javelin-typeahead-ondemand-source', + 7 => 'javelin-dom', + 8 => 'javelin-stratcom', + 9 => 'javelin-util', + ), + 'disk' => '/rsrc/js/application/releeph/releeph-request-typeahead.js', + ), 'javelin-behavior-repository-crossreference' => array( 'uri' => '/res/4b5fab1c/rsrc/js/application/repository/repository-crossreference.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-stratcom', 3 => 'javelin-uri', ), 'disk' => '/rsrc/js/application/repository/repository-crossreference.js', ), 'javelin-behavior-stripe-payment-form' => array( 'uri' => '/res/87c7b043/rsrc/js/application/phortune/behavior-stripe-payment-form.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-json', 3 => 'stripe-core', ), 'disk' => '/rsrc/js/application/phortune/behavior-stripe-payment-form.js', ), 'javelin-behavior-toggle-class' => array( 'uri' => '/res/fa818e0f/rsrc/js/application/core/behavior-toggle-class.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/behavior-toggle-class.js', ), 'javelin-behavior-view-placeholder' => array( 'uri' => '/res/5b89bdf5/rsrc/js/javelin/ext/view/ViewPlaceholder.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', 2 => 'javelin-view-renderer', ), 'disk' => '/rsrc/js/javelin/ext/view/ViewPlaceholder.js', ), 'javelin-behavior-workflow' => array( 'uri' => '/res/2c99beaf/rsrc/js/application/core/behavior-workflow.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-workflow', 3 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/behavior-workflow.js', ), 'javelin-color' => array( 'uri' => '/res/b0439fc9/rsrc/js/javelin/ext/fx/Color.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', ), 'disk' => '/rsrc/js/javelin/ext/fx/Color.js', ), 'javelin-cookie' => array( 'uri' => '/res/a9cddab0/rsrc/js/javelin/lib/Cookie.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/lib/Cookie.js', ), 'javelin-dom' => array( 'uri' => '/res/459f3c08/rsrc/js/javelin/lib/DOM.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-magical-init', 1 => 'javelin-install', 2 => 'javelin-util', 3 => 'javelin-vector', 4 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/javelin/lib/DOM.js', ), 'javelin-dynval' => array( 'uri' => '/res/d89c6f88/rsrc/js/javelin/ext/reactor/core/DynVal.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-reactornode', 2 => 'javelin-util', 3 => 'javelin-reactor', ), 'disk' => '/rsrc/js/javelin/ext/reactor/core/DynVal.js', ), 'javelin-event' => array( 'uri' => '/res/69d99d9f/rsrc/js/javelin/core/Event.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', ), 'disk' => '/rsrc/js/javelin/core/Event.js', ), 'javelin-fx' => array( 'uri' => '/res/30ef0914/rsrc/js/javelin/ext/fx/FX.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-color', 1 => 'javelin-install', 2 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/ext/fx/FX.js', ), 'javelin-history' => array( 'uri' => '/res/9bb36651/rsrc/js/javelin/lib/History.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-stratcom', 1 => 'javelin-install', 2 => 'javelin-uri', 3 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/lib/History.js', ), 'javelin-install' => array( 'uri' => '/res/cab679ff/rsrc/js/javelin/core/install.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-util', 1 => 'javelin-magical-init', ), 'disk' => '/rsrc/js/javelin/core/install.js', ), 'javelin-json' => array( 'uri' => '/res/561b8056/rsrc/js/javelin/lib/JSON.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', ), 'disk' => '/rsrc/js/javelin/lib/JSON.js', ), 'javelin-magical-init' => array( 'uri' => '/res/2f1554da/rsrc/js/javelin/core/init.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/core/init.js', ), 'javelin-mask' => array( 'uri' => '/res/d2a35fff/rsrc/js/javelin/lib/Mask.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-dom', ), 'disk' => '/rsrc/js/javelin/lib/Mask.js', ), 'javelin-reactor' => array( 'uri' => '/res/dfd87f3c/rsrc/js/javelin/ext/reactor/core/Reactor.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/ext/reactor/core/Reactor.js', ), 'javelin-reactor-dom' => array( 'uri' => '/res/701b6f39/rsrc/js/javelin/ext/reactor/dom/RDOM.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-dom', 1 => 'javelin-dynval', 2 => 'javelin-reactornode', 3 => 'javelin-install', 4 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/ext/reactor/dom/RDOM.js', ), 'javelin-reactor-node-calmer' => array( 'uri' => '/res/5a35920a/rsrc/js/javelin/ext/reactor/core/ReactorNodeCalmer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-reactor', 2 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/ext/reactor/core/ReactorNodeCalmer.js', ), 'javelin-reactornode' => array( 'uri' => '/res/f278cc27/rsrc/js/javelin/ext/reactor/core/ReactorNode.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-reactor', 2 => 'javelin-util', 3 => 'javelin-reactor-node-calmer', ), 'disk' => '/rsrc/js/javelin/ext/reactor/core/ReactorNode.js', ), 'javelin-request' => array( 'uri' => '/res/e25d75b3/rsrc/js/javelin/lib/Request.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-stratcom', 2 => 'javelin-util', 3 => 'javelin-behavior', 4 => 'javelin-json', 5 => 'javelin-dom', 6 => 'javelin-resource', ), 'disk' => '/rsrc/js/javelin/lib/Request.js', ), 'javelin-resource' => array( 'uri' => '/res/d5a3f835/rsrc/js/javelin/lib/Resource.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-magical-init', 1 => 'javelin-stratcom', 2 => 'javelin-util', 3 => 'javelin-uri', ), 'disk' => '/rsrc/js/javelin/lib/Resource.js', ), 'javelin-stratcom' => array( 'uri' => '/res/c81f64eb/rsrc/js/javelin/core/Stratcom.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-event', 2 => 'javelin-util', 3 => 'javelin-magical-init', ), 'disk' => '/rsrc/js/javelin/core/Stratcom.js', ), 'javelin-tokenizer' => array( 'uri' => '/res/c75c9e12/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-dom', 1 => 'javelin-util', 2 => 'javelin-stratcom', 3 => 'javelin-install', ), 'disk' => '/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js', ), 'javelin-typeahead' => array( 'uri' => '/res/dccb789e/rsrc/js/javelin/lib/control/typeahead/Typeahead.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-dom', 2 => 'javelin-vector', 3 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/lib/control/typeahead/Typeahead.js', ), 'javelin-typeahead-composite-source' => array( 'uri' => '/res/99705f64/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-typeahead-source', 2 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js', ), 'javelin-typeahead-normalizer' => array( 'uri' => '/res/a9e97c0d/rsrc/js/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', ), 'disk' => '/rsrc/js/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js', ), 'javelin-typeahead-ondemand-source' => array( 'uri' => '/res/81e531aa/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-stratcom', 3 => 'javelin-request', 4 => 'javelin-typeahead-source', ), 'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js', ), 'javelin-typeahead-preloaded-source' => array( 'uri' => '/res/d464efd2/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-stratcom', 3 => 'javelin-request', 4 => 'javelin-typeahead-source', ), 'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js', ), 'javelin-typeahead-source' => array( 'uri' => '/res/74b1f091/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-dom', 3 => 'javelin-typeahead-normalizer', ), 'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js', ), 'javelin-typeahead-static-source' => array( 'uri' => '/res/c8e247fc/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-typeahead-source', ), 'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js', ), 'javelin-uri' => array( 'uri' => '/res/c107d858/rsrc/js/javelin/lib/URI.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-stratcom', ), 'disk' => '/rsrc/js/javelin/lib/URI.js', ), 'javelin-util' => array( 'uri' => '/res/25786b6c/rsrc/js/javelin/core/util.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/core/util.js', ), 'javelin-vector' => array( 'uri' => '/res/f240bdb3/rsrc/js/javelin/lib/Vector.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-event', ), 'disk' => '/rsrc/js/javelin/lib/Vector.js', ), 'javelin-view' => array( 'uri' => '/res/b98657a7/rsrc/js/javelin/ext/view/View.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/ext/view/View.js', ), 'javelin-view-html' => array( 'uri' => '/res/7e5a2122/rsrc/js/javelin/ext/view/HTMLView.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', ), 'disk' => '/rsrc/js/javelin/ext/view/HTMLView.js', ), 'javelin-view-interpreter' => array( 'uri' => '/res/17e911ca/rsrc/js/javelin/ext/view/ViewInterpreter.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-view', 1 => 'javelin-install', ), 'disk' => '/rsrc/js/javelin/ext/view/ViewInterpreter.js', ), 'javelin-view-renderer' => array( 'uri' => '/res/db4ed5a2/rsrc/js/javelin/ext/view/ViewRenderer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', ), 'disk' => '/rsrc/js/javelin/ext/view/ViewRenderer.js', ), 'javelin-view-visitor' => array( 'uri' => '/res/0ef9dc43/rsrc/js/javelin/ext/view/ViewVisitor.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', ), 'disk' => '/rsrc/js/javelin/ext/view/ViewVisitor.js', ), 'javelin-workflow' => array( 'uri' => '/res/1535e366/rsrc/js/javelin/lib/Workflow.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-stratcom', 1 => 'javelin-request', 2 => 'javelin-dom', 3 => 'javelin-vector', 4 => 'javelin-install', 5 => 'javelin-util', 6 => 'javelin-mask', 7 => 'javelin-uri', ), 'disk' => '/rsrc/js/javelin/lib/Workflow.js', ), 'lightbox-attachment-css' => array( 'uri' => '/res/4657e15d/rsrc/css/aphront/lightbox-attachment.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/lightbox-attachment.css', ), 'maniphest-batch-editor' => array( 'uri' => '/res/fb15d744/rsrc/css/application/maniphest/batch-editor.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/maniphest/batch-editor.css', ), 'maniphest-report-css' => array( 'uri' => '/res/2e633fcf/rsrc/css/application/maniphest/report.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/maniphest/report.css', ), 'maniphest-task-edit-css' => array( 'uri' => '/res/68c7863e/rsrc/css/application/maniphest/task-edit.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/maniphest/task-edit.css', ), 'maniphest-task-summary-css' => array( 'uri' => '/res/b3930263/rsrc/css/application/maniphest/task-summary.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/maniphest/task-summary.css', ), 'maniphest-transaction-detail-css' => array( 'uri' => '/res/fb430d3e/rsrc/css/application/maniphest/transaction-detail.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/maniphest/transaction-detail.css', ), 'multirow-row-manager' => array( 'uri' => '/res/0a9b3dee/rsrc/js/application/core/MultirowRowManager.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-stratcom', 2 => 'javelin-dom', 3 => 'javelin-util', ), 'disk' => '/rsrc/js/application/core/MultirowRowManager.js', ), 'owners-path-editor' => array( 'uri' => '/res/29b68354/rsrc/js/application/owners/OwnersPathEditor.js', 'type' => 'js', 'requires' => array( 0 => 'multirow-row-manager', 1 => 'javelin-install', 2 => 'path-typeahead', 3 => 'javelin-dom', 4 => 'javelin-util', 5 => 'phabricator-prefab', ), 'disk' => '/rsrc/js/application/owners/OwnersPathEditor.js', ), 'owners-path-editor-css' => array( 'uri' => '/res/4fcaabf6/rsrc/css/application/owners/owners-path-editor.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/owners/owners-path-editor.css', ), 'paste-css' => array( - 'uri' => '/res/5081cf13/rsrc/css/application/paste/paste.css', + 'uri' => '/res/044639be/rsrc/css/application/paste/paste.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/paste/paste.css', ), 'path-typeahead' => array( 'uri' => '/res/50246fb6/rsrc/js/application/herald/PathTypeahead.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-typeahead', 2 => 'javelin-dom', 3 => 'javelin-request', 4 => 'javelin-typeahead-ondemand-source', 5 => 'javelin-util', ), 'disk' => '/rsrc/js/application/herald/PathTypeahead.js', ), 'phabricator-action-list-view-css' => array( 'uri' => '/res/7a67c3b9/rsrc/css/layout/phabricator-action-list-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-action-list-view.css', ), 'phabricator-application-launch-view-css' => array( 'uri' => '/res/13c3d7f3/rsrc/css/application/base/phabricator-application-launch-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/base/phabricator-application-launch-view.css', ), 'phabricator-busy' => array( 'uri' => '/res/6ec372e1/rsrc/js/application/core/Busy.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/Busy.js', ), 'phabricator-chatlog-css' => array( 'uri' => '/res/f6631adc/rsrc/css/application/chatlog/chatlog.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/chatlog/chatlog.css', ), 'phabricator-content-source-view-css' => array( 'uri' => '/res/8c738a93/rsrc/css/application/contentsource/content-source-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/contentsource/content-source-view.css', ), 'phabricator-core-buttons-css' => array( 'uri' => '/res/4e6b94c8/rsrc/css/core/buttons.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/buttons.css', ), 'phabricator-core-css' => array( 'uri' => '/res/9df0488c/rsrc/css/core/core.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/core.css', ), 'phabricator-countdown-css' => array( 'uri' => '/res/0f646281/rsrc/css/application/countdown/timer.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/countdown/timer.css', ), 'phabricator-crumbs-view-css' => array( 'uri' => '/res/69fdba64/rsrc/css/layout/phabricator-crumbs-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-crumbs-view.css', ), 'phabricator-directory-css' => array( 'uri' => '/res/61afca2b/rsrc/css/application/directory/phabricator-directory.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/directory/phabricator-directory.css', ), 'phabricator-drag-and-drop-file-upload' => array( 'uri' => '/res/ce71f19a/rsrc/js/application/core/DragAndDropFileUpload.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-request', 3 => 'javelin-dom', 4 => 'javelin-uri', 5 => 'phabricator-file-upload', ), 'disk' => '/rsrc/js/application/core/DragAndDropFileUpload.js', ), 'phabricator-dropdown-menu' => array( 'uri' => '/res/2b4aa4d8/rsrc/js/application/core/DropdownMenu.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-dom', 3 => 'javelin-vector', 4 => 'javelin-stratcom', 5 => 'phabricator-menu-item', ), 'disk' => '/rsrc/js/application/core/DropdownMenu.js', ), 'phabricator-fatal-config-template-css' => array( 'uri' => '/res/6e1a8d22/rsrc/css/application/config/config-template.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/config/config-template.css', ), 'phabricator-feed-css' => array( 'uri' => '/res/94a04b24/rsrc/css/application/feed/feed.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/feed/feed.css', ), 'phabricator-file-upload' => array( 'uri' => '/res/2de10295/rsrc/js/application/core/FileUpload.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-dom', 2 => 'phabricator-notification', ), 'disk' => '/rsrc/js/application/core/FileUpload.js', ), 'phabricator-filetree-view-css' => array( 'uri' => '/res/c912ed91/rsrc/css/layout/phabricator-filetree-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-filetree-view.css', ), 'phabricator-flag-css' => array( 'uri' => '/res/2eee890a/rsrc/css/application/flag/flag.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/flag/flag.css', ), 'phabricator-form-view-css' => array( 'uri' => '/res/676b1ad2/rsrc/css/layout/phabricator-form-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-form-view.css', ), 'phabricator-header-view-css' => array( 'uri' => '/res/585b771c/rsrc/css/layout/phabricator-header-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-header-view.css', ), 'phabricator-jump-nav' => array( 'uri' => '/res/2e0e2211/rsrc/css/application/directory/phabricator-jump-nav.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/directory/phabricator-jump-nav.css', ), 'phabricator-keyboard-shortcut' => array( 'uri' => '/res/beed38cd/rsrc/js/application/core/KeyboardShortcut.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'phabricator-keyboard-shortcut-manager', ), 'disk' => '/rsrc/js/application/core/KeyboardShortcut.js', ), 'phabricator-keyboard-shortcut-manager' => array( 'uri' => '/res/d0bee7c7/rsrc/js/application/core/KeyboardShortcutManager.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-stratcom', 3 => 'javelin-dom', 4 => 'javelin-vector', ), 'disk' => '/rsrc/js/application/core/KeyboardShortcutManager.js', ), 'phabricator-main-menu-view' => array( 'uri' => '/res/c1a73bc2/rsrc/css/application/base/main-menu-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/base/main-menu-view.css', ), 'phabricator-menu-item' => array( 'uri' => '/res/32fc2325/rsrc/js/application/core/DropdownMenuItem.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/core/DropdownMenuItem.js', ), 'phabricator-nav-view-css' => array( 'uri' => '/res/f3c78a53/rsrc/css/aphront/phabricator-nav-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/phabricator-nav-view.css', ), 'phabricator-notification' => array( 'uri' => '/res/ad727561/rsrc/js/application/core/Notification.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-dom', 2 => 'javelin-stratcom', 3 => 'javelin-util', 4 => 'phabricator-notification-css', ), 'disk' => '/rsrc/js/application/core/Notification.js', ), 'phabricator-notification-css' => array( 'uri' => '/res/664b9bec/rsrc/css/aphront/notification.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/notification.css', ), 'phabricator-notification-menu-css' => array( 'uri' => '/res/b7cc25af/rsrc/css/application/base/notification-menu.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/base/notification-menu.css', ), 'phabricator-object-item-list-view-css' => array( 'uri' => '/res/3fed6faf/rsrc/css/layout/phabricator-object-item-list-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-object-item-list-view.css', ), 'phabricator-object-list-view-css' => array( 'uri' => '/res/4f183668/rsrc/css/application/projects/phabricator-object-list-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/projects/phabricator-object-list-view.css', ), 'phabricator-object-selector-css' => array( 'uri' => '/res/7eb4c705/rsrc/css/application/objectselector/object-selector.css', 'type' => 'css', 'requires' => array( 0 => 'aphront-dialog-view-css', ), 'disk' => '/rsrc/css/application/objectselector/object-selector.css', ), 'phabricator-paste-file-upload' => array( 'uri' => '/res/b0b8afd8/rsrc/js/application/core/PasteFileUpload.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-request', 3 => 'javelin-dom', 4 => 'javelin-uri', ), 'disk' => '/rsrc/js/application/core/PasteFileUpload.js', ), 'phabricator-pinboard-view-css' => array( 'uri' => '/res/61ecd7cf/rsrc/css/layout/phabricator-pinboard-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-pinboard-view.css', ), 'phabricator-prefab' => array( 'uri' => '/res/2734e45f/rsrc/js/application/core/Prefab.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-dom', 3 => 'javelin-typeahead', 4 => 'javelin-tokenizer', 5 => 'javelin-typeahead-preloaded-source', 6 => 'javelin-typeahead-ondemand-source', 7 => 'javelin-dom', 8 => 'javelin-stratcom', 9 => 'javelin-util', ), 'disk' => '/rsrc/js/application/core/Prefab.js', ), 'phabricator-profile-css' => array( 'uri' => '/res/9869d10b/rsrc/css/application/profile/profile-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/profile/profile-view.css', ), 'phabricator-profile-header-css' => array( 'uri' => '/res/4b1cb23b/rsrc/css/application/profile/profile-header-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/profile/profile-header-view.css', ), 'phabricator-project-tag-css' => array( 'uri' => '/res/1b5efcb2/rsrc/css/application/projects/project-tag.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/projects/project-tag.css', ), 'phabricator-property-list-view-css' => array( 'uri' => '/res/a04cc81d/rsrc/css/layout/phabricator-property-list-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-property-list-view.css', ), 'phabricator-remarkup-css' => array( 'uri' => '/res/4265a372/rsrc/css/core/remarkup.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/remarkup.css', ), 'phabricator-search-results-css' => array( 'uri' => '/res/f8a86e27/rsrc/css/application/search/search-results.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/search/search-results.css', ), 'phabricator-shaped-request' => array( 'uri' => '/res/fbdb92db/rsrc/js/application/core/ShapedRequest.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-request', ), 'disk' => '/rsrc/js/application/core/ShapedRequest.js', ), 'phabricator-side-menu-view-css' => array( 'uri' => '/res/28a1e092/rsrc/css/layout/phabricator-side-menu-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-side-menu-view.css', ), 'phabricator-slowvote-css' => array( 'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/slowvote/slowvote.css', ), 'phabricator-source-code-view-css' => array( - 'uri' => '/res/9373e769/rsrc/css/layout/phabricator-source-code-view.css', + 'uri' => '/res/979d5280/rsrc/css/layout/phabricator-source-code-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-source-code-view.css', ), 'phabricator-standard-page-view' => array( 'uri' => '/res/70fa2da4/rsrc/css/application/base/standard-page-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/base/standard-page-view.css', ), 'phabricator-tag-view-css' => array( 'uri' => '/res/e10bf844/rsrc/css/layout/phabricator-tag-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-tag-view.css', ), 'phabricator-textareautils' => array( 'uri' => '/res/703614ea/rsrc/js/application/core/TextAreaUtils.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', ), 'disk' => '/rsrc/js/application/core/TextAreaUtils.js', ), 'phabricator-timeline-view-css' => array( 'uri' => '/res/5517bf1a/rsrc/css/layout/phabricator-timeline-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/layout/phabricator-timeline-view.css', ), 'phabricator-tooltip' => array( 'uri' => '/res/55d76b9b/rsrc/js/application/core/ToolTip.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-util', 2 => 'javelin-dom', 3 => 'javelin-vector', ), 'disk' => '/rsrc/js/application/core/ToolTip.js', ), 'phabricator-transaction-view-css' => array( 'uri' => '/res/00be4b1a/rsrc/css/aphront/transaction.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/transaction.css', ), 'phabricator-ui-example-css' => array( 'uri' => '/res/376ab671/rsrc/css/application/uiexample/example.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/uiexample/example.css', ), 'phabricator-uiexample-javelin-view' => array( 'uri' => '/res/a2ce2cfc/rsrc/js/application/uiexample/JavelinViewExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', ), 'disk' => '/rsrc/js/application/uiexample/JavelinViewExample.js', ), 'phabricator-uiexample-reactor-button' => array( 'uri' => '/res/142127f6/rsrc/js/application/uiexample/ReactorButtonExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', ), 'disk' => '/rsrc/js/application/uiexample/ReactorButtonExample.js', ), 'phabricator-uiexample-reactor-checkbox' => array( 'uri' => '/res/c75cb9e9/rsrc/js/application/uiexample/ReactorCheckboxExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', ), 'disk' => '/rsrc/js/application/uiexample/ReactorCheckboxExample.js', ), 'phabricator-uiexample-reactor-focus' => array( 'uri' => '/res/3cc992eb/rsrc/js/application/uiexample/ReactorFocusExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', ), 'disk' => '/rsrc/js/application/uiexample/ReactorFocusExample.js', ), 'phabricator-uiexample-reactor-input' => array( 'uri' => '/res/4953da16/rsrc/js/application/uiexample/ReactorInputExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', 5 => 'javelin-view-html', 6 => 'javelin-view-interpreter', 7 => 'javelin-view-renderer', ), 'disk' => '/rsrc/js/application/uiexample/ReactorInputExample.js', ), 'phabricator-uiexample-reactor-mouseover' => array( 'uri' => '/res/52a355b6/rsrc/js/application/uiexample/ReactorMouseoverExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', ), 'disk' => '/rsrc/js/application/uiexample/ReactorMouseoverExample.js', ), 'phabricator-uiexample-reactor-radio' => array( 'uri' => '/res/ae87f3af/rsrc/js/application/uiexample/ReactorRadioExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', ), 'disk' => '/rsrc/js/application/uiexample/ReactorRadioExample.js', ), 'phabricator-uiexample-reactor-select' => array( 'uri' => '/res/23cb448a/rsrc/js/application/uiexample/ReactorSelectExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', ), 'disk' => '/rsrc/js/application/uiexample/ReactorSelectExample.js', ), 'phabricator-uiexample-reactor-sendclass' => array( 'uri' => '/res/8cd34264/rsrc/js/application/uiexample/ReactorSendClassExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', ), 'disk' => '/rsrc/js/application/uiexample/ReactorSendClassExample.js', ), 'phabricator-uiexample-reactor-sendproperties' => array( 'uri' => '/res/18af54aa/rsrc/js/application/uiexample/ReactorSendPropertiesExample.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-install', 1 => 'javelin-view', 2 => 'javelin-util', 3 => 'javelin-dom', 4 => 'javelin-reactor-dom', ), 'disk' => '/rsrc/js/application/uiexample/ReactorSendPropertiesExample.js', ), 'phabricator-zindex-css' => array( 'uri' => '/res/fcbf82ad/rsrc/css/core/z-index.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/z-index.css', ), 'phame-css' => array( 'uri' => '/res/8e3edb71/rsrc/css/application/phame/phame.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/phame/phame.css', ), 'pholio-css' => array( - 'uri' => '/res/bc10bf21/rsrc/css/application/pholio/pholio.css', + 'uri' => '/res/b0947e46/rsrc/css/application/pholio/pholio.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/pholio/pholio.css', ), 'pholio-inline-comments-css' => array( 'uri' => '/res/8fe0edc7/rsrc/css/application/pholio/pholio-inline-comments.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/pholio/pholio-inline-comments.css', ), 'phriction-document-css' => array( 'uri' => '/res/8d09bd7f/rsrc/css/application/phriction/phriction-document-css.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/phriction/phriction-document-css.css', ), 'ponder-comment-table-css' => array( 'uri' => '/res/a1bb9056/rsrc/css/application/ponder/comments.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/ponder/comments.css', ), 'ponder-core-view-css' => array( 'uri' => '/res/3a2d5e18/rsrc/css/application/ponder/core.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/ponder/core.css', ), 'ponder-feed-view-css' => array( 'uri' => '/res/df22bd20/rsrc/css/application/ponder/feed.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/ponder/feed.css', ), 'ponder-post-css' => array( 'uri' => '/res/013b9e2c/rsrc/css/application/ponder/post.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/ponder/post.css', ), 'ponder-vote-css' => array( 'uri' => '/res/ea8316c2/rsrc/css/application/ponder/vote.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/ponder/vote.css', ), 'raphael-core' => array( 'uri' => '/res/3f48575a/rsrc/js/raphael/raphael.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/raphael/raphael.js', ), 'raphael-g' => array( 'uri' => '/res/b07e5245/rsrc/js/raphael/g.raphael.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/raphael/g.raphael.js', ), 'raphael-g-line' => array( 'uri' => '/res/a59c8556/rsrc/js/raphael/g.raphael.line.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/raphael/g.raphael.line.js', ), + 'releeph-branch' => + array( + 'uri' => '/res/6ad6420d/rsrc/css/application/releeph/releeph-branch.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-branch.css', + ), + 'releeph-colors' => + array( + 'uri' => '/res/dff4b26a/rsrc/css/application/releeph/releeph-colors.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-colors.css', + ), + 'releeph-core' => + array( + 'uri' => '/res/853f4a73/rsrc/css/application/releeph/releeph-core.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-core.css', + ), + 'releeph-intents' => + array( + 'uri' => '/res/4e73e9dd/rsrc/css/application/releeph/releeph-intents.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-intents.css', + ), + 'releeph-preview-branch' => + array( + 'uri' => '/res/65e5dece/rsrc/css/application/releeph/releeph-preview-branch.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-preview-branch.css', + ), + 'releeph-project' => + array( + 'uri' => '/res/b9376e59/rsrc/css/application/releeph/releeph-project.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-project.css', + ), + 'releeph-request-differential-create-dialog' => + array( + 'uri' => '/res/4df30ce1/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css', + ), + 'releeph-request-typeahead-css' => + array( + 'uri' => '/res/9c9a1acf/rsrc/css/application/releeph/releeph-request-typeahead.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-request-typeahead.css', + ), + 'releeph-status' => + array( + 'uri' => '/res/588529df/rsrc/css/application/releeph/releeph-status.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/releeph/releeph-status.css', + ), 'setup-issue-css' => array( 'uri' => '/res/efbb3673/rsrc/css/application/config/setup-issue.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/config/setup-issue.css', ), 'sprite-apps-css' => array( 'uri' => '/res/8de495b4/rsrc/css/sprite-apps.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-apps.css', ), 'sprite-apps-large-css' => array( 'uri' => '/res/174143b7/rsrc/css/sprite-apps-large.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-apps-large.css', ), 'sprite-apps-xlarge-css' => array( 'uri' => '/res/33a8e644/rsrc/css/sprite-apps-xlarge.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-apps-xlarge.css', ), 'sprite-conpherence-css' => array( 'uri' => '/res/f6793453/rsrc/css/sprite-conpherence.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-conpherence.css', ), 'sprite-docs-css' => array( 'uri' => '/res/b32f93bc/rsrc/css/sprite-docs.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-docs.css', ), 'sprite-gradient-css' => array( 'uri' => '/res/e62e7a0f/rsrc/css/sprite-gradient.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-gradient.css', ), 'sprite-icon-css' => array( 'uri' => '/res/e7d63fcf/rsrc/css/sprite-icon.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-icon.css', ), 'sprite-menu-css' => array( 'uri' => '/res/50bb9cc5/rsrc/css/sprite-menu.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-menu.css', ), 'sprite-tokens-css' => array( 'uri' => '/res/9ae0de5b/rsrc/css/sprite-tokens.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/sprite-tokens.css', ), 'stripe-core' => array( 'uri' => '/res/3b0f0ad4/rsrc/js/stripe/stripe_core.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/stripe/stripe_core.js', ), 'stripe-payment-form-css' => array( 'uri' => '/res/634a6371/rsrc/css/application/phortune/stripe-payment-form.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/phortune/stripe-payment-form.css', ), 'syntax-highlighting-css' => array( 'uri' => '/res/cb3b9dc0/rsrc/css/core/syntax.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/syntax.css', ), 'tokens-css' => array( 'uri' => '/res/6b3c65c7/rsrc/css/application/tokens/tokens.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/tokens/tokens.css', ), ), array( 'packages' => array( '7cb09b8b' => array( 'name' => 'core.pkg.css', 'symbols' => array( 0 => 'phabricator-core-css', 1 => 'phabricator-zindex-css', 2 => 'phabricator-core-buttons-css', 3 => 'phabricator-standard-page-view', 4 => 'aphront-dialog-view-css', 5 => 'aphront-form-view-css', 6 => 'aphront-panel-view-css', 7 => 'aphront-table-view-css', 8 => 'aphront-tokenizer-control-css', 9 => 'aphront-typeahead-control-css', 10 => 'aphront-list-filter-view-css', 11 => 'phabricator-directory-css', 12 => 'phabricator-jump-nav', 13 => 'phabricator-remarkup-css', 14 => 'syntax-highlighting-css', 15 => 'aphront-pager-view-css', 16 => 'phabricator-transaction-view-css', 17 => 'aphront-tooltip-css', 18 => 'phabricator-flag-css', 19 => 'aphront-error-view-css', 20 => 'sprite-icon-css', 21 => 'sprite-gradient-css', 22 => 'sprite-menu-css', 23 => 'sprite-apps-large-css', 24 => 'phabricator-main-menu-view', 25 => 'phabricator-notification-css', 26 => 'phabricator-notification-menu-css', 27 => 'lightbox-attachment-css', 28 => 'phabricator-header-view-css', 29 => 'phabricator-form-view-css', 30 => 'phabricator-filetree-view-css', 31 => 'phabricator-nav-view-css', 32 => 'phabricator-side-menu-view-css', 33 => 'phabricator-crumbs-view-css', 34 => 'phabricator-object-item-list-view-css', 35 => 'global-drag-and-drop-css', ), 'uri' => '/res/pkg/7cb09b8b/core.pkg.css', 'type' => 'css', ), '95ceba95' => array( 'name' => 'core.pkg.js', 'symbols' => array( 0 => 'javelin-behavior-aphront-basic-tokenizer', 1 => 'javelin-behavior-workflow', 2 => 'javelin-behavior-aphront-form-disable-on-submit', 3 => 'phabricator-keyboard-shortcut-manager', 4 => 'phabricator-keyboard-shortcut', 5 => 'javelin-behavior-phabricator-keyboard-shortcuts', 6 => 'javelin-behavior-refresh-csrf', 7 => 'javelin-behavior-phabricator-watch-anchor', 8 => 'javelin-behavior-phabricator-autofocus', 9 => 'phabricator-paste-file-upload', 10 => 'phabricator-menu-item', 11 => 'phabricator-dropdown-menu', 12 => 'javelin-behavior-phabricator-oncopy', 13 => 'phabricator-tooltip', 14 => 'javelin-behavior-phabricator-tooltips', 15 => 'phabricator-prefab', 16 => 'javelin-behavior-device', 17 => 'javelin-behavior-toggle-class', 18 => 'javelin-behavior-lightbox-attachments', 19 => 'phabricator-busy', 20 => 'javelin-aphlict', 21 => 'phabricator-notification', 22 => 'javelin-behavior-aphlict-listen', 23 => 'javelin-behavior-phabricator-search-typeahead', 24 => 'javelin-behavior-konami', 25 => 'javelin-behavior-aphlict-dropdown', 26 => 'javelin-behavior-history-install', 27 => 'javelin-behavior-phabricator-gesture', 28 => 'javelin-behavior-phabricator-active-nav', 29 => 'javelin-behavior-phabricator-nav', 30 => 'javelin-behavior-phabricator-remarkup-assist', 31 => 'phabricator-textareautils', 32 => 'phabricator-file-upload', 33 => 'javelin-behavior-global-drag-and-drop', 34 => 'javelin-behavior-phabricator-reveal-content', ), 'uri' => '/res/pkg/95ceba95/core.pkg.js', 'type' => 'js', ), 'dca4a03d' => array( 'name' => 'darkconsole.pkg.js', 'symbols' => array( 0 => 'javelin-behavior-dark-console', 1 => 'javelin-behavior-error-log', ), 'uri' => '/res/pkg/dca4a03d/darkconsole.pkg.js', 'type' => 'js', ), '8aaacd1b' => array( 'name' => 'differential.pkg.css', 'symbols' => array( 0 => 'differential-core-view-css', 1 => 'differential-changeset-view-css', 2 => 'differential-results-table-css', 3 => 'differential-revision-history-css', 4 => 'differential-revision-list-css', 5 => 'differential-table-of-contents-css', 6 => 'differential-revision-comment-css', 7 => 'differential-revision-add-comment-css', 8 => 'differential-revision-comment-list-css', 9 => 'phabricator-object-selector-css', 10 => 'phabricator-content-source-view-css', 11 => 'differential-local-commits-view-css', 12 => 'inline-comment-summary-css', ), 'uri' => '/res/pkg/8aaacd1b/differential.pkg.css', 'type' => 'css', ), '322728f3' => array( 'name' => 'differential.pkg.js', 'symbols' => array( 0 => 'phabricator-drag-and-drop-file-upload', 1 => 'phabricator-shaped-request', 2 => 'javelin-behavior-differential-feedback-preview', 3 => 'javelin-behavior-differential-edit-inline-comments', 4 => 'javelin-behavior-differential-populate', 5 => 'javelin-behavior-differential-show-more', 6 => 'javelin-behavior-differential-diff-radios', 7 => 'javelin-behavior-differential-accept-with-errors', 8 => 'javelin-behavior-differential-comment-jump', 9 => 'javelin-behavior-differential-add-reviewers-and-ccs', 10 => 'javelin-behavior-differential-keyboard-navigation', 11 => 'javelin-behavior-aphront-drag-and-drop', 12 => 'javelin-behavior-aphront-drag-and-drop-textarea', 13 => 'javelin-behavior-phabricator-object-selector', 14 => 'javelin-behavior-repository-crossreference', 15 => 'javelin-behavior-load-blame', 16 => 'differential-inline-comment-editor', 17 => 'javelin-behavior-differential-dropdown-menus', 18 => 'javelin-behavior-differential-toggle-files', 19 => 'javelin-behavior-differential-user-select', ), 'uri' => '/res/pkg/322728f3/differential.pkg.js', 'type' => 'js', ), 'c8ce2d88' => array( 'name' => 'diffusion.pkg.css', 'symbols' => array( 0 => 'diffusion-commit-view-css', 1 => 'diffusion-icons-css', ), 'uri' => '/res/pkg/c8ce2d88/diffusion.pkg.css', 'type' => 'css', ), 'f96657b8' => array( 'name' => 'diffusion.pkg.js', 'symbols' => array( 0 => 'javelin-behavior-diffusion-pull-lastmodified', 1 => 'javelin-behavior-diffusion-commit-graph', 2 => 'javelin-behavior-audit-preview', ), 'uri' => '/res/pkg/f96657b8/diffusion.pkg.js', 'type' => 'js', ), 'cd1d650a' => array( 'name' => 'javelin.pkg.js', 'symbols' => array( 0 => 'javelin-util', 1 => 'javelin-install', 2 => 'javelin-event', 3 => 'javelin-stratcom', 4 => 'javelin-behavior', 5 => 'javelin-resource', 6 => 'javelin-request', 7 => 'javelin-vector', 8 => 'javelin-dom', 9 => 'javelin-json', 10 => 'javelin-uri', 11 => 'javelin-workflow', 12 => 'javelin-mask', 13 => 'javelin-typeahead', 14 => 'javelin-typeahead-normalizer', 15 => 'javelin-typeahead-source', 16 => 'javelin-typeahead-preloaded-source', 17 => 'javelin-typeahead-ondemand-source', 18 => 'javelin-tokenizer', ), 'uri' => '/res/pkg/cd1d650a/javelin.pkg.js', 'type' => 'js', ), 'c41b4907' => array( 'name' => 'maniphest.pkg.css', 'symbols' => array( 0 => 'maniphest-task-summary-css', 1 => 'maniphest-transaction-detail-css', 2 => 'aphront-attached-file-view-css', 3 => 'phabricator-project-tag-css', ), 'uri' => '/res/pkg/c41b4907/maniphest.pkg.css', 'type' => 'css', ), '7707de41' => array( 'name' => 'maniphest.pkg.js', 'symbols' => array( 0 => 'javelin-behavior-maniphest-batch-selector', 1 => 'javelin-behavior-maniphest-transaction-controls', 2 => 'javelin-behavior-maniphest-transaction-preview', 3 => 'javelin-behavior-maniphest-transaction-expand', 4 => 'javelin-behavior-maniphest-subpriority-editor', ), 'uri' => '/res/pkg/7707de41/maniphest.pkg.js', 'type' => 'js', ), ), 'reverse' => array( 'aphront-attached-file-view-css' => 'c41b4907', 'aphront-dialog-view-css' => '7cb09b8b', 'aphront-error-view-css' => '7cb09b8b', 'aphront-form-view-css' => '7cb09b8b', 'aphront-list-filter-view-css' => '7cb09b8b', 'aphront-pager-view-css' => '7cb09b8b', 'aphront-panel-view-css' => '7cb09b8b', 'aphront-table-view-css' => '7cb09b8b', 'aphront-tokenizer-control-css' => '7cb09b8b', 'aphront-tooltip-css' => '7cb09b8b', 'aphront-typeahead-control-css' => '7cb09b8b', 'differential-changeset-view-css' => '8aaacd1b', 'differential-core-view-css' => '8aaacd1b', 'differential-inline-comment-editor' => '322728f3', 'differential-local-commits-view-css' => '8aaacd1b', 'differential-results-table-css' => '8aaacd1b', 'differential-revision-add-comment-css' => '8aaacd1b', 'differential-revision-comment-css' => '8aaacd1b', 'differential-revision-comment-list-css' => '8aaacd1b', 'differential-revision-history-css' => '8aaacd1b', 'differential-revision-list-css' => '8aaacd1b', 'differential-table-of-contents-css' => '8aaacd1b', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', 'global-drag-and-drop-css' => '7cb09b8b', 'inline-comment-summary-css' => '8aaacd1b', 'javelin-aphlict' => '95ceba95', 'javelin-behavior' => 'cd1d650a', 'javelin-behavior-aphlict-dropdown' => '95ceba95', 'javelin-behavior-aphlict-listen' => '95ceba95', 'javelin-behavior-aphront-basic-tokenizer' => '95ceba95', 'javelin-behavior-aphront-drag-and-drop' => '322728f3', 'javelin-behavior-aphront-drag-and-drop-textarea' => '322728f3', 'javelin-behavior-aphront-form-disable-on-submit' => '95ceba95', 'javelin-behavior-audit-preview' => 'f96657b8', 'javelin-behavior-dark-console' => 'dca4a03d', 'javelin-behavior-device' => '95ceba95', 'javelin-behavior-differential-accept-with-errors' => '322728f3', 'javelin-behavior-differential-add-reviewers-and-ccs' => '322728f3', 'javelin-behavior-differential-comment-jump' => '322728f3', 'javelin-behavior-differential-diff-radios' => '322728f3', 'javelin-behavior-differential-dropdown-menus' => '322728f3', 'javelin-behavior-differential-edit-inline-comments' => '322728f3', 'javelin-behavior-differential-feedback-preview' => '322728f3', 'javelin-behavior-differential-keyboard-navigation' => '322728f3', 'javelin-behavior-differential-populate' => '322728f3', 'javelin-behavior-differential-show-more' => '322728f3', 'javelin-behavior-differential-toggle-files' => '322728f3', 'javelin-behavior-differential-user-select' => '322728f3', 'javelin-behavior-diffusion-commit-graph' => 'f96657b8', 'javelin-behavior-diffusion-pull-lastmodified' => 'f96657b8', 'javelin-behavior-error-log' => 'dca4a03d', 'javelin-behavior-global-drag-and-drop' => '95ceba95', 'javelin-behavior-history-install' => '95ceba95', 'javelin-behavior-konami' => '95ceba95', 'javelin-behavior-lightbox-attachments' => '95ceba95', 'javelin-behavior-load-blame' => '322728f3', 'javelin-behavior-maniphest-batch-selector' => '7707de41', 'javelin-behavior-maniphest-subpriority-editor' => '7707de41', 'javelin-behavior-maniphest-transaction-controls' => '7707de41', 'javelin-behavior-maniphest-transaction-expand' => '7707de41', 'javelin-behavior-maniphest-transaction-preview' => '7707de41', 'javelin-behavior-phabricator-active-nav' => '95ceba95', 'javelin-behavior-phabricator-autofocus' => '95ceba95', 'javelin-behavior-phabricator-gesture' => '95ceba95', 'javelin-behavior-phabricator-keyboard-shortcuts' => '95ceba95', 'javelin-behavior-phabricator-nav' => '95ceba95', 'javelin-behavior-phabricator-object-selector' => '322728f3', 'javelin-behavior-phabricator-oncopy' => '95ceba95', 'javelin-behavior-phabricator-remarkup-assist' => '95ceba95', 'javelin-behavior-phabricator-reveal-content' => '95ceba95', 'javelin-behavior-phabricator-search-typeahead' => '95ceba95', 'javelin-behavior-phabricator-tooltips' => '95ceba95', 'javelin-behavior-phabricator-watch-anchor' => '95ceba95', 'javelin-behavior-refresh-csrf' => '95ceba95', 'javelin-behavior-repository-crossreference' => '322728f3', 'javelin-behavior-toggle-class' => '95ceba95', 'javelin-behavior-workflow' => '95ceba95', 'javelin-dom' => 'cd1d650a', 'javelin-event' => 'cd1d650a', 'javelin-install' => 'cd1d650a', 'javelin-json' => 'cd1d650a', 'javelin-mask' => 'cd1d650a', 'javelin-request' => 'cd1d650a', 'javelin-resource' => 'cd1d650a', 'javelin-stratcom' => 'cd1d650a', 'javelin-tokenizer' => 'cd1d650a', 'javelin-typeahead' => 'cd1d650a', 'javelin-typeahead-normalizer' => 'cd1d650a', 'javelin-typeahead-ondemand-source' => 'cd1d650a', 'javelin-typeahead-preloaded-source' => 'cd1d650a', 'javelin-typeahead-source' => 'cd1d650a', 'javelin-uri' => 'cd1d650a', 'javelin-util' => 'cd1d650a', 'javelin-vector' => 'cd1d650a', 'javelin-workflow' => 'cd1d650a', 'lightbox-attachment-css' => '7cb09b8b', 'maniphest-task-summary-css' => 'c41b4907', 'maniphest-transaction-detail-css' => 'c41b4907', 'phabricator-busy' => '95ceba95', 'phabricator-content-source-view-css' => '8aaacd1b', 'phabricator-core-buttons-css' => '7cb09b8b', 'phabricator-core-css' => '7cb09b8b', 'phabricator-crumbs-view-css' => '7cb09b8b', 'phabricator-directory-css' => '7cb09b8b', 'phabricator-drag-and-drop-file-upload' => '322728f3', 'phabricator-dropdown-menu' => '95ceba95', 'phabricator-file-upload' => '95ceba95', 'phabricator-filetree-view-css' => '7cb09b8b', 'phabricator-flag-css' => '7cb09b8b', 'phabricator-form-view-css' => '7cb09b8b', 'phabricator-header-view-css' => '7cb09b8b', 'phabricator-jump-nav' => '7cb09b8b', 'phabricator-keyboard-shortcut' => '95ceba95', 'phabricator-keyboard-shortcut-manager' => '95ceba95', 'phabricator-main-menu-view' => '7cb09b8b', 'phabricator-menu-item' => '95ceba95', 'phabricator-nav-view-css' => '7cb09b8b', 'phabricator-notification' => '95ceba95', 'phabricator-notification-css' => '7cb09b8b', 'phabricator-notification-menu-css' => '7cb09b8b', 'phabricator-object-item-list-view-css' => '7cb09b8b', 'phabricator-object-selector-css' => '8aaacd1b', 'phabricator-paste-file-upload' => '95ceba95', 'phabricator-prefab' => '95ceba95', 'phabricator-project-tag-css' => 'c41b4907', 'phabricator-remarkup-css' => '7cb09b8b', 'phabricator-shaped-request' => '322728f3', 'phabricator-side-menu-view-css' => '7cb09b8b', 'phabricator-standard-page-view' => '7cb09b8b', 'phabricator-textareautils' => '95ceba95', 'phabricator-tooltip' => '95ceba95', 'phabricator-transaction-view-css' => '7cb09b8b', 'phabricator-zindex-css' => '7cb09b8b', 'sprite-apps-large-css' => '7cb09b8b', 'sprite-gradient-css' => '7cb09b8b', 'sprite-icon-css' => '7cb09b8b', 'sprite-menu-css' => '7cb09b8b', 'syntax-highlighting-css' => '7cb09b8b', ), )); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index a13b97b6e..f22374905 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,3111 +1,3270 @@ <?php /** * This file is automatically generated. Use 'arc liberate' to rebuild it. * @generated * @phutil-library-version 2 */ phutil_register_library_map(array( '__library_version__' => 2, 'class' => array( 'Aphront304Response' => 'aphront/response/Aphront304Response.php', 'Aphront400Response' => 'aphront/response/Aphront400Response.php', 'Aphront403Response' => 'aphront/response/Aphront403Response.php', 'Aphront404Response' => 'aphront/response/Aphront404Response.php', 'AphrontAjaxResponse' => 'aphront/response/AphrontAjaxResponse.php', 'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php', 'AphrontAttachedFileView' => 'view/control/AphrontAttachedFileView.php', 'AphrontBarView' => 'view/widget/bars/AphrontBarView.php', 'AphrontCSRFException' => 'aphront/exception/AphrontCSRFException.php', 'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php', 'AphrontCalendarMonthView' => 'applications/calendar/view/AphrontCalendarMonthView.php', 'AphrontContextBarView' => 'view/layout/AphrontContextBarView.php', 'AphrontController' => 'aphront/AphrontController.php', 'AphrontCursorPagerView' => 'view/control/AphrontCursorPagerView.php', 'AphrontDefaultApplicationConfiguration' => 'aphront/configuration/AphrontDefaultApplicationConfiguration.php', 'AphrontDialogResponse' => 'aphront/response/AphrontDialogResponse.php', 'AphrontDialogView' => 'view/AphrontDialogView.php', 'AphrontErrorView' => 'view/form/AphrontErrorView.php', 'AphrontException' => 'aphront/exception/AphrontException.php', 'AphrontFileResponse' => 'aphront/response/AphrontFileResponse.php', 'AphrontFormCheckboxControl' => 'view/form/control/AphrontFormCheckboxControl.php', 'AphrontFormControl' => 'view/form/control/AphrontFormControl.php', 'AphrontFormCountedToggleButtonsControl' => 'view/form/control/AphrontFormCountedToggleButtonsControl.php', 'AphrontFormCropControl' => 'view/form/control/AphrontFormCropControl.php', 'AphrontFormDateControl' => 'view/form/control/AphrontFormDateControl.php', 'AphrontFormDividerControl' => 'view/form/control/AphrontFormDividerControl.php', 'AphrontFormDragAndDropUploadControl' => 'view/form/control/AphrontFormDragAndDropUploadControl.php', 'AphrontFormFileControl' => 'view/form/control/AphrontFormFileControl.php', 'AphrontFormImageControl' => 'view/form/control/AphrontFormImageControl.php', 'AphrontFormInsetView' => 'view/form/AphrontFormInsetView.php', 'AphrontFormLayoutView' => 'view/form/AphrontFormLayoutView.php', 'AphrontFormMarkupControl' => 'view/form/control/AphrontFormMarkupControl.php', 'AphrontFormPasswordControl' => 'view/form/control/AphrontFormPasswordControl.php', 'AphrontFormPolicyControl' => 'view/form/control/AphrontFormPolicyControl.php', 'AphrontFormRadioButtonControl' => 'view/form/control/AphrontFormRadioButtonControl.php', 'AphrontFormRecaptchaControl' => 'view/form/control/AphrontFormRecaptchaControl.php', 'AphrontFormSelectControl' => 'view/form/control/AphrontFormSelectControl.php', 'AphrontFormStaticControl' => 'view/form/control/AphrontFormStaticControl.php', 'AphrontFormSubmitControl' => 'view/form/control/AphrontFormSubmitControl.php', 'AphrontFormTextAreaControl' => 'view/form/control/AphrontFormTextAreaControl.php', 'AphrontFormTextControl' => 'view/form/control/AphrontFormTextControl.php', 'AphrontFormToggleButtonsControl' => 'view/form/control/AphrontFormToggleButtonsControl.php', 'AphrontFormTokenizerControl' => 'view/form/control/AphrontFormTokenizerControl.php', 'AphrontFormView' => 'view/form/AphrontFormView.php', 'AphrontGlyphBarView' => 'view/widget/bars/AphrontGlyphBarView.php', 'AphrontHTMLResponse' => 'aphront/response/AphrontHTMLResponse.php', 'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php', 'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php', 'AphrontIsolatedDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontIsolatedDatabaseConnectionTestCase.php', 'AphrontIsolatedHTTPSink' => 'aphront/sink/AphrontIsolatedHTTPSink.php', 'AphrontJSONResponse' => 'aphront/response/AphrontJSONResponse.php', 'AphrontJavelinView' => 'view/AphrontJavelinView.php', 'AphrontKeyboardShortcutsAvailableView' => 'view/widget/AphrontKeyboardShortcutsAvailableView.php', 'AphrontListFilterView' => 'view/layout/AphrontListFilterView.php', 'AphrontMiniPanelView' => 'view/layout/AphrontMiniPanelView.php', 'AphrontMoreView' => 'view/layout/AphrontMoreView.php', 'AphrontMySQLDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontMySQLDatabaseConnectionTestCase.php', 'AphrontNoteView' => 'view/widget/AphrontNoteView.php', 'AphrontNullView' => 'view/AphrontNullView.php', 'AphrontPHPHTTPSink' => 'aphront/sink/AphrontPHPHTTPSink.php', 'AphrontPageView' => 'view/page/AphrontPageView.php', 'AphrontPagerView' => 'view/control/AphrontPagerView.php', 'AphrontPanelView' => 'view/layout/AphrontPanelView.php', 'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php', 'AphrontProgressBarView' => 'view/widget/bars/AphrontProgressBarView.php', 'AphrontProxyResponse' => 'aphront/response/AphrontProxyResponse.php', 'AphrontRedirectException' => 'aphront/exception/AphrontRedirectException.php', 'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php', 'AphrontReloadResponse' => 'aphront/response/AphrontReloadResponse.php', 'AphrontRequest' => 'aphront/AphrontRequest.php', 'AphrontRequestFailureView' => 'view/page/AphrontRequestFailureView.php', 'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php', 'AphrontResponse' => 'aphront/response/AphrontResponse.php', 'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php', 'AphrontTableView' => 'view/control/AphrontTableView.php', 'AphrontTagView' => 'view/AphrontTagView.php', 'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php', 'AphrontTwoColumnView' => 'view/layout/AphrontTwoColumnView.php', 'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php', 'AphrontURIMapper' => 'aphront/AphrontURIMapper.php', 'AphrontUsageException' => 'aphront/exception/AphrontUsageException.php', 'AphrontView' => 'view/AphrontView.php', 'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php', 'AuditPeopleMenuEventListener' => 'applications/audit/events/AuditPeopleMenuEventListener.php', 'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php', 'CelerityPhabricatorResourceController' => 'infrastructure/celerity/CelerityPhabricatorResourceController.php', 'CelerityResourceController' => 'infrastructure/celerity/CelerityResourceController.php', 'CelerityResourceGraph' => 'infrastructure/celerity/CelerityResourceGraph.php', 'CelerityResourceMap' => 'infrastructure/celerity/CelerityResourceMap.php', 'CelerityResourceTransformer' => 'infrastructure/celerity/CelerityResourceTransformer.php', 'CelerityResourceTransformerTestCase' => 'infrastructure/celerity/__tests__/CelerityResourceTransformerTestCase.php', 'CeleritySpriteGenerator' => 'infrastructure/celerity/CeleritySpriteGenerator.php', 'CelerityStaticResourceResponse' => 'infrastructure/celerity/CelerityStaticResourceResponse.php', 'ConduitAPIMethod' => 'applications/conduit/method/ConduitAPIMethod.php', 'ConduitAPIRequest' => 'applications/conduit/protocol/ConduitAPIRequest.php', 'ConduitAPIResponse' => 'applications/conduit/protocol/ConduitAPIResponse.php', 'ConduitAPI_arcanist_Method' => 'applications/arcanist/conduit/ConduitAPI_arcanist_Method.php', 'ConduitAPI_arcanist_projectinfo_Method' => 'applications/arcanist/conduit/ConduitAPI_arcanist_projectinfo_Method.php', 'ConduitAPI_audit_Method' => 'applications/audit/conduit/ConduitAPI_audit_Method.php', 'ConduitAPI_audit_query_Method' => 'applications/audit/conduit/ConduitAPI_audit_query_Method.php', 'ConduitAPI_chatlog_Method' => 'applications/chatlog/conduit/ConduitAPI_chatlog_Method.php', 'ConduitAPI_chatlog_query_Method' => 'applications/chatlog/conduit/ConduitAPI_chatlog_query_Method.php', 'ConduitAPI_chatlog_record_Method' => 'applications/chatlog/conduit/ConduitAPI_chatlog_record_Method.php', 'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/ConduitAPI_conduit_connect_Method.php', 'ConduitAPI_conduit_getcertificate_Method' => 'applications/conduit/method/ConduitAPI_conduit_getcertificate_Method.php', 'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/ConduitAPI_conduit_ping_Method.php', 'ConduitAPI_conduit_query_Method' => 'applications/conduit/method/ConduitAPI_conduit_query_Method.php', 'ConduitAPI_daemon_launched_Method' => 'applications/daemon/conduit/ConduitAPI_daemon_launched_Method.php', 'ConduitAPI_daemon_log_Method' => 'applications/daemon/conduit/ConduitAPI_daemon_log_Method.php', 'ConduitAPI_daemon_setstatus_Method' => 'applications/daemon/conduit/ConduitAPI_daemon_setstatus_Method.php', 'ConduitAPI_differential_Method' => 'applications/differential/conduit/ConduitAPI_differential_Method.php', 'ConduitAPI_differential_close_Method' => 'applications/differential/conduit/ConduitAPI_differential_close_Method.php', 'ConduitAPI_differential_createcomment_Method' => 'applications/differential/conduit/ConduitAPI_differential_createcomment_Method.php', 'ConduitAPI_differential_creatediff_Method' => 'applications/differential/conduit/ConduitAPI_differential_creatediff_Method.php', 'ConduitAPI_differential_createinline_Method' => 'applications/differential/conduit/ConduitAPI_differential_createinline_Method.php', 'ConduitAPI_differential_createrawdiff_Method' => 'applications/differential/conduit/ConduitAPI_differential_createrawdiff_Method.php', 'ConduitAPI_differential_createrevision_Method' => 'applications/differential/conduit/ConduitAPI_differential_createrevision_Method.php', 'ConduitAPI_differential_find_Method' => 'applications/differential/conduit/ConduitAPI_differential_find_Method.php', 'ConduitAPI_differential_finishpostponedlinters_Method' => 'applications/differential/conduit/ConduitAPI_differential_finishpostponedlinters_Method.php', 'ConduitAPI_differential_getalldiffs_Method' => 'applications/differential/conduit/ConduitAPI_differential_getalldiffs_Method.php', 'ConduitAPI_differential_getcommitmessage_Method' => 'applications/differential/conduit/ConduitAPI_differential_getcommitmessage_Method.php', 'ConduitAPI_differential_getcommitpaths_Method' => 'applications/differential/conduit/ConduitAPI_differential_getcommitpaths_Method.php', 'ConduitAPI_differential_getdiff_Method' => 'applications/differential/conduit/ConduitAPI_differential_getdiff_Method.php', 'ConduitAPI_differential_getrevision_Method' => 'applications/differential/conduit/ConduitAPI_differential_getrevision_Method.php', 'ConduitAPI_differential_getrevisioncomments_Method' => 'applications/differential/conduit/ConduitAPI_differential_getrevisioncomments_Method.php', 'ConduitAPI_differential_getrevisionfeedback_Method' => 'applications/differential/conduit/ConduitAPI_differential_getrevisionfeedback_Method.php', 'ConduitAPI_differential_markcommitted_Method' => 'applications/differential/conduit/ConduitAPI_differential_markcommitted_Method.php', 'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/differential/conduit/ConduitAPI_differential_parsecommitmessage_Method.php', 'ConduitAPI_differential_query_Method' => 'applications/differential/conduit/ConduitAPI_differential_query_Method.php', 'ConduitAPI_differential_setdiffproperty_Method' => 'applications/differential/conduit/ConduitAPI_differential_setdiffproperty_Method.php', 'ConduitAPI_differential_updaterevision_Method' => 'applications/differential/conduit/ConduitAPI_differential_updaterevision_Method.php', 'ConduitAPI_differential_updateunitresults_Method' => 'applications/differential/conduit/ConduitAPI_differential_updateunitresults_Method.php', 'ConduitAPI_diffusion_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_Method.php', 'ConduitAPI_diffusion_findsymbols_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_findsymbols_Method.php', 'ConduitAPI_diffusion_getcommits_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_getcommits_Method.php', 'ConduitAPI_diffusion_getlintmessages_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_getlintmessages_Method.php', 'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_getrecentcommitsbypath_Method.php', 'ConduitAPI_feed_Method' => 'applications/feed/conduit/ConduitAPI_feed_Method.php', 'ConduitAPI_feed_publish_Method' => 'applications/feed/conduit/ConduitAPI_feed_publish_Method.php', 'ConduitAPI_feed_query_Method' => 'applications/feed/conduit/ConduitAPI_feed_query_Method.php', 'ConduitAPI_file_Method' => 'applications/files/conduit/ConduitAPI_file_Method.php', 'ConduitAPI_file_download_Method' => 'applications/files/conduit/ConduitAPI_file_download_Method.php', 'ConduitAPI_file_info_Method' => 'applications/files/conduit/ConduitAPI_file_info_Method.php', 'ConduitAPI_file_upload_Method' => 'applications/files/conduit/ConduitAPI_file_upload_Method.php', 'ConduitAPI_file_uploadhash_Method' => 'applications/files/conduit/ConduitAPI_file_uploadhash_Method.php', 'ConduitAPI_flag_Method' => 'applications/flag/conduit/ConduitAPI_flag_Method.php', 'ConduitAPI_flag_delete_Method' => 'applications/flag/conduit/ConduitAPI_flag_delete_Method.php', 'ConduitAPI_flag_edit_Method' => 'applications/flag/conduit/ConduitAPI_flag_edit_Method.php', 'ConduitAPI_flag_query_Method' => 'applications/flag/conduit/ConduitAPI_flag_query_Method.php', 'ConduitAPI_macro_Method' => 'applications/macro/conduit/ConduitAPI_macro_Method.php', 'ConduitAPI_macro_query_Method' => 'applications/macro/conduit/ConduitAPI_macro_query_Method.php', 'ConduitAPI_maniphest_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_Method.php', 'ConduitAPI_maniphest_createtask_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_createtask_Method.php', 'ConduitAPI_maniphest_find_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_find_Method.php', 'ConduitAPI_maniphest_gettasktransactions_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_gettasktransactions_Method.php', 'ConduitAPI_maniphest_info_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_info_Method.php', 'ConduitAPI_maniphest_query_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_query_Method.php', 'ConduitAPI_maniphest_update_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_update_Method.php', 'ConduitAPI_owners_Method' => 'applications/owners/conduit/ConduitAPI_owners_Method.php', 'ConduitAPI_owners_query_Method' => 'applications/owners/conduit/ConduitAPI_owners_query_Method.php', 'ConduitAPI_paste_Method' => 'applications/paste/conduit/ConduitAPI_paste_Method.php', 'ConduitAPI_paste_create_Method' => 'applications/paste/conduit/ConduitAPI_paste_create_Method.php', 'ConduitAPI_paste_info_Method' => 'applications/paste/conduit/ConduitAPI_paste_info_Method.php', 'ConduitAPI_paste_query_Method' => 'applications/paste/conduit/ConduitAPI_paste_query_Method.php', 'ConduitAPI_phid_Method' => 'applications/phid/conduit/ConduitAPI_phid_Method.php', 'ConduitAPI_phid_info_Method' => 'applications/phid/conduit/ConduitAPI_phid_info_Method.php', 'ConduitAPI_phid_lookup_Method' => 'applications/phid/conduit/ConduitAPI_phid_lookup_Method.php', 'ConduitAPI_phid_query_Method' => 'applications/phid/conduit/ConduitAPI_phid_query_Method.php', 'ConduitAPI_phpast_Method' => 'applications/phpast/conduit/ConduitAPI_phpast_Method.php', 'ConduitAPI_phpast_getast_Method' => 'applications/phpast/conduit/ConduitAPI_phpast_getast_Method.php', 'ConduitAPI_phpast_version_Method' => 'applications/phpast/conduit/ConduitAPI_phpast_version_Method.php', 'ConduitAPI_phriction_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_Method.php', 'ConduitAPI_phriction_edit_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_edit_Method.php', 'ConduitAPI_phriction_history_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_history_Method.php', 'ConduitAPI_phriction_info_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_info_Method.php', 'ConduitAPI_project_Method' => 'applications/project/conduit/ConduitAPI_project_Method.php', 'ConduitAPI_project_query_Method' => 'applications/project/conduit/ConduitAPI_project_query_Method.php', + 'ConduitAPI_releeph_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_Method.php', + 'ConduitAPI_releeph_getbranches_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_getbranches_Method.php', + 'ConduitAPI_releeph_projectinfo_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_projectinfo_Method.php', + 'ConduitAPI_releeph_request_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_request_Method.php', + 'ConduitAPI_releephwork_canpush_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_canpush_Method.php', + 'ConduitAPI_releephwork_getauthorinfo_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getauthorinfo_Method.php', + 'ConduitAPI_releephwork_getbranch_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getbranch_Method.php', + 'ConduitAPI_releephwork_getbranchcommitmessage_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php', + 'ConduitAPI_releephwork_getcommitmessage_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php', + 'ConduitAPI_releephwork_getorigcommitmessage_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getorigcommitmessage_Method.php', + 'ConduitAPI_releephwork_nextrequest_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php', + 'ConduitAPI_releephwork_record_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_record_Method.php', + 'ConduitAPI_releephwork_recordpickstatus_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_recordpickstatus_Method.php', 'ConduitAPI_remarkup_process_Method' => 'applications/remarkup/conduit/ConduitAPI_remarkup_process_Method.php', 'ConduitAPI_repository_Method' => 'applications/repository/conduit/ConduitAPI_repository_Method.php', 'ConduitAPI_repository_create_Method' => 'applications/repository/conduit/ConduitAPI_repository_create_Method.php', 'ConduitAPI_repository_query_Method' => 'applications/repository/conduit/ConduitAPI_repository_query_Method.php', 'ConduitAPI_slowvote_Method' => 'applications/slowvote/conduit/ConduitAPI_slowvote_Method.php', 'ConduitAPI_slowvote_info_Method' => 'applications/slowvote/conduit/ConduitAPI_slowvote_info_Method.php', 'ConduitAPI_token_Method' => 'applications/tokens/conduit/ConduitAPI_token_Method.php', 'ConduitAPI_token_give_Method' => 'applications/tokens/conduit/ConduitAPI_token_give_Method.php', 'ConduitAPI_token_given_Method' => 'applications/tokens/conduit/ConduitAPI_token_given_Method.php', 'ConduitAPI_token_query_Method' => 'applications/tokens/conduit/ConduitAPI_token_query_Method.php', 'ConduitAPI_user_Method' => 'applications/people/conduit/ConduitAPI_user_Method.php', 'ConduitAPI_user_addstatus_Method' => 'applications/people/conduit/ConduitAPI_user_addstatus_Method.php', 'ConduitAPI_user_disable_Method' => 'applications/people/conduit/ConduitAPI_user_disable_Method.php', 'ConduitAPI_user_enable_Method' => 'applications/people/conduit/ConduitAPI_user_enable_Method.php', 'ConduitAPI_user_find_Method' => 'applications/people/conduit/ConduitAPI_user_find_Method.php', 'ConduitAPI_user_info_Method' => 'applications/people/conduit/ConduitAPI_user_info_Method.php', 'ConduitAPI_user_query_Method' => 'applications/people/conduit/ConduitAPI_user_query_Method.php', 'ConduitAPI_user_removestatus_Method' => 'applications/people/conduit/ConduitAPI_user_removestatus_Method.php', 'ConduitAPI_user_whoami_Method' => 'applications/people/conduit/ConduitAPI_user_whoami_Method.php', 'ConduitCall' => 'applications/conduit/call/ConduitCall.php', 'ConduitCallTestCase' => 'applications/conduit/call/__tests__/ConduitCallTestCase.php', 'ConduitException' => 'applications/conduit/protocol/ConduitException.php', 'ConduitSSHWorkflow' => 'applications/conduit/ssh/ConduitSSHWorkflow.php', 'ConpherenceConfigOptions' => 'applications/conpherence/config/ConpherenceConfigOptions.php', 'ConpherenceConstants' => 'applications/conpherence/constants/ConpherenceConstants.php', 'ConpherenceController' => 'applications/conpherence/controller/ConpherenceController.php', 'ConpherenceDAO' => 'applications/conpherence/storage/ConpherenceDAO.php', 'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php', 'ConpherenceFileWidgetView' => 'applications/conpherence/view/ConpherenceFileWidgetView.php', 'ConpherenceFormDragAndDropUploadControl' => 'applications/conpherence/view/ConpherenceFormDragAndDropUploadControl.php', 'ConpherenceImageData' => 'applications/conpherence/constants/ConpherenceImageData.php', 'ConpherenceListController' => 'applications/conpherence/controller/ConpherenceListController.php', 'ConpherenceMenuItemView' => 'applications/conpherence/view/ConpherenceMenuItemView.php', 'ConpherenceNewController' => 'applications/conpherence/controller/ConpherenceNewController.php', 'ConpherenceParticipant' => 'applications/conpherence/storage/ConpherenceParticipant.php', 'ConpherenceParticipantQuery' => 'applications/conpherence/query/ConpherenceParticipantQuery.php', 'ConpherenceParticipationStatus' => 'applications/conpherence/constants/ConpherenceParticipationStatus.php', 'ConpherencePeopleMenuEventListener' => 'applications/conpherence/events/ConpherencePeopleMenuEventListener.php', 'ConpherencePontificateControl' => 'applications/conpherence/view/ConpherencePontificateControl.php', 'ConpherenceReplyHandler' => 'applications/conpherence/mail/ConpherenceReplyHandler.php', 'ConpherenceThread' => 'applications/conpherence/storage/ConpherenceThread.php', 'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php', 'ConpherenceTransaction' => 'applications/conpherence/storage/ConpherenceTransaction.php', 'ConpherenceTransactionComment' => 'applications/conpherence/storage/ConpherenceTransactionComment.php', 'ConpherenceTransactionQuery' => 'applications/conpherence/query/ConpherenceTransactionQuery.php', 'ConpherenceTransactionType' => 'applications/conpherence/constants/ConpherenceTransactionType.php', 'ConpherenceTransactionView' => 'applications/conpherence/view/ConpherenceTransactionView.php', 'ConpherenceUpdateController' => 'applications/conpherence/controller/ConpherenceUpdateController.php', 'ConpherenceViewController' => 'applications/conpherence/controller/ConpherenceViewController.php', 'ConpherenceWidgetController' => 'applications/conpherence/controller/ConpherenceWidgetController.php', 'DarkConsoleController' => 'aphront/console/DarkConsoleController.php', 'DarkConsoleCore' => 'aphront/console/DarkConsoleCore.php', 'DarkConsoleDataController' => 'aphront/console/DarkConsoleDataController.php', 'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/DarkConsoleErrorLogPlugin.php', 'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/DarkConsoleErrorLogPluginAPI.php', 'DarkConsoleEventPlugin' => 'aphront/console/plugin/DarkConsoleEventPlugin.php', 'DarkConsoleEventPluginAPI' => 'aphront/console/plugin/event/DarkConsoleEventPluginAPI.php', 'DarkConsolePlugin' => 'aphront/console/plugin/DarkConsolePlugin.php', 'DarkConsoleRequestPlugin' => 'aphront/console/plugin/DarkConsoleRequestPlugin.php', 'DarkConsoleServicesPlugin' => 'aphront/console/plugin/DarkConsoleServicesPlugin.php', 'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/DarkConsoleXHProfPlugin.php', 'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/DarkConsoleXHProfPluginAPI.php', 'DatabaseConfigurationProvider' => 'infrastructure/storage/configuration/DatabaseConfigurationProvider.php', 'DefaultDatabaseConfigurationProvider' => 'infrastructure/storage/configuration/DefaultDatabaseConfigurationProvider.php', 'DifferentialAction' => 'applications/differential/constants/DifferentialAction.php', 'DifferentialActionHasNoEffectException' => 'applications/differential/exception/DifferentialActionHasNoEffectException.php', 'DifferentialAddCommentView' => 'applications/differential/view/DifferentialAddCommentView.php', 'DifferentialAffectedPath' => 'applications/differential/storage/DifferentialAffectedPath.php', 'DifferentialApplyPatchFieldSpecification' => 'applications/differential/field/specification/DifferentialApplyPatchFieldSpecification.php', 'DifferentialArcanistProjectFieldSpecification' => 'applications/differential/field/specification/DifferentialArcanistProjectFieldSpecification.php', 'DifferentialAuditorsFieldSpecification' => 'applications/differential/field/specification/DifferentialAuditorsFieldSpecification.php', 'DifferentialAuthorFieldSpecification' => 'applications/differential/field/specification/DifferentialAuthorFieldSpecification.php', 'DifferentialAuxiliaryField' => 'applications/differential/storage/DifferentialAuxiliaryField.php', 'DifferentialBlameRevisionFieldSpecification' => 'applications/differential/field/specification/DifferentialBlameRevisionFieldSpecification.php', 'DifferentialBranchFieldSpecification' => 'applications/differential/field/specification/DifferentialBranchFieldSpecification.php', 'DifferentialCCWelcomeMail' => 'applications/differential/mail/DifferentialCCWelcomeMail.php', 'DifferentialCCsFieldSpecification' => 'applications/differential/field/specification/DifferentialCCsFieldSpecification.php', 'DifferentialChangeType' => 'applications/differential/constants/DifferentialChangeType.php', 'DifferentialChangeset' => 'applications/differential/storage/DifferentialChangeset.php', 'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php', 'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php', 'DifferentialChangesetHTMLRenderer' => 'applications/differential/render/DifferentialChangesetHTMLRenderer.php', 'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php', 'DifferentialChangesetOneUpRenderer' => 'applications/differential/render/DifferentialChangesetOneUpRenderer.php', 'DifferentialChangesetOneUpTestRenderer' => 'applications/differential/render/DifferentialChangesetOneUpTestRenderer.php', 'DifferentialChangesetParser' => 'applications/differential/parser/DifferentialChangesetParser.php', 'DifferentialChangesetParserTestCase' => 'applications/differential/parser/__tests__/DifferentialChangesetParserTestCase.php', 'DifferentialChangesetRenderer' => 'applications/differential/render/DifferentialChangesetRenderer.php', 'DifferentialChangesetTestRenderer' => 'applications/differential/render/DifferentialChangesetTestRenderer.php', 'DifferentialChangesetTwoUpRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpRenderer.php', 'DifferentialChangesetTwoUpTestRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpTestRenderer.php', 'DifferentialChangesetViewController' => 'applications/differential/controller/DifferentialChangesetViewController.php', 'DifferentialComment' => 'applications/differential/storage/DifferentialComment.php', 'DifferentialCommentEditor' => 'applications/differential/editor/DifferentialCommentEditor.php', 'DifferentialCommentMail' => 'applications/differential/mail/DifferentialCommentMail.php', 'DifferentialCommentPreviewController' => 'applications/differential/controller/DifferentialCommentPreviewController.php', 'DifferentialCommentSaveController' => 'applications/differential/controller/DifferentialCommentSaveController.php', 'DifferentialCommitsFieldSpecification' => 'applications/differential/field/specification/DifferentialCommitsFieldSpecification.php', 'DifferentialConflictsFieldSpecification' => 'applications/differential/field/specification/DifferentialConflictsFieldSpecification.php', 'DifferentialController' => 'applications/differential/controller/DifferentialController.php', 'DifferentialDAO' => 'applications/differential/storage/DifferentialDAO.php', 'DifferentialDateCreatedFieldSpecification' => 'applications/differential/field/specification/DifferentialDateCreatedFieldSpecification.php', 'DifferentialDateModifiedFieldSpecification' => 'applications/differential/field/specification/DifferentialDateModifiedFieldSpecification.php', 'DifferentialDefaultFieldSelector' => 'applications/differential/field/selector/DifferentialDefaultFieldSelector.php', 'DifferentialDependenciesFieldSpecification' => 'applications/differential/field/specification/DifferentialDependenciesFieldSpecification.php', 'DifferentialDependsOnFieldSpecification' => 'applications/differential/field/specification/DifferentialDependsOnFieldSpecification.php', 'DifferentialDiff' => 'applications/differential/storage/DifferentialDiff.php', 'DifferentialDiffContentMail' => 'applications/differential/mail/DifferentialDiffContentMail.php', 'DifferentialDiffCreateController' => 'applications/differential/controller/DifferentialDiffCreateController.php', 'DifferentialDiffProperty' => 'applications/differential/storage/DifferentialDiffProperty.php', 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/DifferentialDiffTableOfContentsView.php', 'DifferentialDiffTestCase' => 'applications/differential/storage/__tests__/DifferentialDiffTestCase.php', 'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php', 'DifferentialException' => 'applications/differential/exception/DifferentialException.php', 'DifferentialExceptionMail' => 'applications/differential/mail/DifferentialExceptionMail.php', 'DifferentialExportPatchFieldSpecification' => 'applications/differential/field/specification/DifferentialExportPatchFieldSpecification.php', 'DifferentialFieldDataNotAvailableException' => 'applications/differential/field/exception/DifferentialFieldDataNotAvailableException.php', 'DifferentialFieldParseException' => 'applications/differential/field/exception/DifferentialFieldParseException.php', 'DifferentialFieldSelector' => 'applications/differential/field/selector/DifferentialFieldSelector.php', 'DifferentialFieldSpecification' => 'applications/differential/field/specification/DifferentialFieldSpecification.php', 'DifferentialFieldSpecificationIncompleteException' => 'applications/differential/field/exception/DifferentialFieldSpecificationIncompleteException.php', 'DifferentialFieldValidationException' => 'applications/differential/field/exception/DifferentialFieldValidationException.php', 'DifferentialFreeformFieldSpecification' => 'applications/differential/field/specification/DifferentialFreeformFieldSpecification.php', 'DifferentialGitSVNIDFieldSpecification' => 'applications/differential/field/specification/DifferentialGitSVNIDFieldSpecification.php', 'DifferentialHostFieldSpecification' => 'applications/differential/field/specification/DifferentialHostFieldSpecification.php', 'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php', 'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php', 'DifferentialHunkParserTestCase' => 'applications/differential/parser/__tests__/DifferentialHunkParserTestCase.php', 'DifferentialHunkTestCase' => 'applications/differential/storage/__tests__/DifferentialHunkTestCase.php', 'DifferentialInlineComment' => 'applications/differential/storage/DifferentialInlineComment.php', 'DifferentialInlineCommentEditController' => 'applications/differential/controller/DifferentialInlineCommentEditController.php', 'DifferentialInlineCommentEditView' => 'applications/differential/view/DifferentialInlineCommentEditView.php', 'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/DifferentialInlineCommentPreviewController.php', 'DifferentialInlineCommentView' => 'applications/differential/view/DifferentialInlineCommentView.php', 'DifferentialLinesFieldSpecification' => 'applications/differential/field/specification/DifferentialLinesFieldSpecification.php', 'DifferentialLintFieldSpecification' => 'applications/differential/field/specification/DifferentialLintFieldSpecification.php', 'DifferentialLintStatus' => 'applications/differential/constants/DifferentialLintStatus.php', 'DifferentialLocalCommitsView' => 'applications/differential/view/DifferentialLocalCommitsView.php', 'DifferentialMail' => 'applications/differential/mail/DifferentialMail.php', 'DifferentialMailPhase' => 'applications/differential/constants/DifferentialMailPhase.php', 'DifferentialManiphestTasksFieldSpecification' => 'applications/differential/field/specification/DifferentialManiphestTasksFieldSpecification.php', 'DifferentialNewDiffMail' => 'applications/differential/mail/DifferentialNewDiffMail.php', 'DifferentialParseRenderTestCase' => 'applications/differential/__tests__/DifferentialParseRenderTestCase.php', 'DifferentialPathFieldSpecification' => 'applications/differential/field/specification/DifferentialPathFieldSpecification.php', 'DifferentialPeopleMenuEventListener' => 'applications/differential/events/DifferentialPeopleMenuEventListener.php', 'DifferentialPrimaryPaneView' => 'applications/differential/view/DifferentialPrimaryPaneView.php', + 'DifferentialReleephRequestFieldSpecification' => 'applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php', 'DifferentialRemarkupRule' => 'applications/differential/remarkup/DifferentialRemarkupRule.php', 'DifferentialReplyHandler' => 'applications/differential/DifferentialReplyHandler.php', 'DifferentialResultsTableView' => 'applications/differential/view/DifferentialResultsTableView.php', 'DifferentialRevertPlanFieldSpecification' => 'applications/differential/field/specification/DifferentialRevertPlanFieldSpecification.php', 'DifferentialReviewRequestMail' => 'applications/differential/mail/DifferentialReviewRequestMail.php', 'DifferentialReviewedByFieldSpecification' => 'applications/differential/field/specification/DifferentialReviewedByFieldSpecification.php', 'DifferentialReviewerStats' => 'applications/differential/stats/DifferentialReviewerStats.php', 'DifferentialReviewerStatsTestCase' => 'applications/differential/stats/__tests__/DifferentialReviewerStatsTestCase.php', 'DifferentialReviewersFieldSpecification' => 'applications/differential/field/specification/DifferentialReviewersFieldSpecification.php', 'DifferentialRevision' => 'applications/differential/storage/DifferentialRevision.php', 'DifferentialRevisionCommentListView' => 'applications/differential/view/DifferentialRevisionCommentListView.php', 'DifferentialRevisionCommentView' => 'applications/differential/view/DifferentialRevisionCommentView.php', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/DifferentialRevisionControlSystem.php', 'DifferentialRevisionDetailRenderer' => 'applications/differential/controller/DifferentialRevisionDetailRenderer.php', 'DifferentialRevisionDetailView' => 'applications/differential/view/DifferentialRevisionDetailView.php', 'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php', 'DifferentialRevisionEditor' => 'applications/differential/editor/DifferentialRevisionEditor.php', 'DifferentialRevisionIDFieldParserTestCase' => 'applications/differential/field/specification/__tests__/DifferentialRevisionIDFieldParserTestCase.php', 'DifferentialRevisionIDFieldSpecification' => 'applications/differential/field/specification/DifferentialRevisionIDFieldSpecification.php', 'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php', 'DifferentialRevisionListData' => 'applications/differential/data/DifferentialRevisionListData.php', 'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php', 'DifferentialRevisionQuery' => 'applications/differential/query/DifferentialRevisionQuery.php', 'DifferentialRevisionStatsController' => 'applications/differential/controller/DifferentialRevisionStatsController.php', 'DifferentialRevisionStatsView' => 'applications/differential/view/DifferentialRevisionStatsView.php', 'DifferentialRevisionStatus' => 'applications/differential/constants/DifferentialRevisionStatus.php', 'DifferentialRevisionStatusFieldSpecification' => 'applications/differential/field/specification/DifferentialRevisionStatusFieldSpecification.php', 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/DifferentialRevisionUpdateHistoryView.php', 'DifferentialRevisionViewController' => 'applications/differential/controller/DifferentialRevisionViewController.php', 'DifferentialSearchIndexer' => 'applications/differential/search/DifferentialSearchIndexer.php', 'DifferentialSubscribeController' => 'applications/differential/controller/DifferentialSubscribeController.php', 'DifferentialSummaryFieldSpecification' => 'applications/differential/field/specification/DifferentialSummaryFieldSpecification.php', 'DifferentialTasksAttacher' => 'applications/differential/DifferentialTasksAttacher.php', 'DifferentialTestPlanFieldSpecification' => 'applications/differential/field/specification/DifferentialTestPlanFieldSpecification.php', 'DifferentialTitleFieldSpecification' => 'applications/differential/field/specification/DifferentialTitleFieldSpecification.php', 'DifferentialUnitFieldSpecification' => 'applications/differential/field/specification/DifferentialUnitFieldSpecification.php', 'DifferentialUnitStatus' => 'applications/differential/constants/DifferentialUnitStatus.php', 'DifferentialUnitTestResult' => 'applications/differential/constants/DifferentialUnitTestResult.php', 'DiffusionBranchInformation' => 'applications/diffusion/data/DiffusionBranchInformation.php', 'DiffusionBranchQuery' => 'applications/diffusion/query/branch/DiffusionBranchQuery.php', 'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php', 'DiffusionBranchTableView' => 'applications/diffusion/view/DiffusionBranchTableView.php', 'DiffusionBrowseController' => 'applications/diffusion/controller/DiffusionBrowseController.php', 'DiffusionBrowseFileController' => 'applications/diffusion/controller/DiffusionBrowseFileController.php', 'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/DiffusionBrowseQuery.php', 'DiffusionBrowseTableView' => 'applications/diffusion/view/DiffusionBrowseTableView.php', 'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php', 'DiffusionCommentListView' => 'applications/diffusion/view/DiffusionCommentListView.php', 'DiffusionCommentView' => 'applications/diffusion/view/DiffusionCommentView.php', 'DiffusionCommitBranchesController' => 'applications/diffusion/controller/DiffusionCommitBranchesController.php', 'DiffusionCommitChangeTableView' => 'applications/diffusion/view/DiffusionCommitChangeTableView.php', 'DiffusionCommitController' => 'applications/diffusion/controller/DiffusionCommitController.php', 'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', 'DiffusionCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionCommitParentsQuery.php', 'DiffusionCommitQuery' => 'applications/diffusion/query/DiffusionCommitQuery.php', 'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', 'DiffusionCommitTagsQuery' => 'applications/diffusion/query/committags/DiffusionCommitTagsQuery.php', 'DiffusionContainsQuery' => 'applications/diffusion/query/contains/DiffusionContainsQuery.php', 'DiffusionController' => 'applications/diffusion/controller/DiffusionController.php', 'DiffusionDiffController' => 'applications/diffusion/controller/DiffusionDiffController.php', 'DiffusionDiffQuery' => 'applications/diffusion/query/diff/DiffusionDiffQuery.php', 'DiffusionEmptyResultView' => 'applications/diffusion/view/DiffusionEmptyResultView.php', 'DiffusionExistsQuery' => 'applications/diffusion/query/exists/DiffusionExistsQuery.php', 'DiffusionExternalController' => 'applications/diffusion/controller/DiffusionExternalController.php', 'DiffusionFileContent' => 'applications/diffusion/data/DiffusionFileContent.php', 'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionFileContentQuery.php', 'DiffusionGitBranchQuery' => 'applications/diffusion/query/branch/DiffusionGitBranchQuery.php', 'DiffusionGitBranchQueryTestCase' => 'applications/diffusion/query/branch/__tests__/DiffusionGitBranchQueryTestCase.php', 'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/DiffusionGitBrowseQuery.php', 'DiffusionGitCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionGitCommitParentsQuery.php', 'DiffusionGitCommitTagsQuery' => 'applications/diffusion/query/committags/DiffusionGitCommitTagsQuery.php', 'DiffusionGitContainsQuery' => 'applications/diffusion/query/contains/DiffusionGitContainsQuery.php', 'DiffusionGitDiffQuery' => 'applications/diffusion/query/diff/DiffusionGitDiffQuery.php', 'DiffusionGitExistsQuery' => 'applications/diffusion/query/exists/DiffusionGitExistsQuery.php', 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php', 'DiffusionGitHistoryQuery' => 'applications/diffusion/query/history/DiffusionGitHistoryQuery.php', 'DiffusionGitLastModifiedQuery' => 'applications/diffusion/query/lastmodified/DiffusionGitLastModifiedQuery.php', 'DiffusionGitMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/DiffusionGitMergedCommitsQuery.php', 'DiffusionGitRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php', 'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php', 'DiffusionGitTagListQuery' => 'applications/diffusion/query/taglist/DiffusionGitTagListQuery.php', 'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php', 'DiffusionHistoryQuery' => 'applications/diffusion/query/history/DiffusionHistoryQuery.php', 'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php', 'DiffusionHomeController' => 'applications/diffusion/controller/DiffusionHomeController.php', 'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php', 'DiffusionInlineCommentPreviewController' => 'applications/diffusion/controller/DiffusionInlineCommentPreviewController.php', 'DiffusionLastModifiedController' => 'applications/diffusion/controller/DiffusionLastModifiedController.php', 'DiffusionLastModifiedQuery' => 'applications/diffusion/query/lastmodified/DiffusionLastModifiedQuery.php', 'DiffusionLintController' => 'applications/diffusion/controller/DiffusionLintController.php', 'DiffusionLintDetailsController' => 'applications/diffusion/controller/DiffusionLintDetailsController.php', 'DiffusionLintSaveRunner' => 'applications/diffusion/DiffusionLintSaveRunner.php', 'DiffusionMercurialBranchQuery' => 'applications/diffusion/query/branch/DiffusionMercurialBranchQuery.php', 'DiffusionMercurialBrowseQuery' => 'applications/diffusion/query/browse/DiffusionMercurialBrowseQuery.php', 'DiffusionMercurialCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionMercurialCommitParentsQuery.php', 'DiffusionMercurialCommitTagsQuery' => 'applications/diffusion/query/committags/DiffusionMercurialCommitTagsQuery.php', 'DiffusionMercurialContainsQuery' => 'applications/diffusion/query/contains/DiffusionMercurialContainsQuery.php', 'DiffusionMercurialDiffQuery' => 'applications/diffusion/query/diff/DiffusionMercurialDiffQuery.php', 'DiffusionMercurialExistsQuery' => 'applications/diffusion/query/exists/DiffusionMercurialExistsQuery.php', 'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionMercurialFileContentQuery.php', 'DiffusionMercurialHistoryQuery' => 'applications/diffusion/query/history/DiffusionMercurialHistoryQuery.php', 'DiffusionMercurialLastModifiedQuery' => 'applications/diffusion/query/lastmodified/DiffusionMercurialLastModifiedQuery.php', 'DiffusionMercurialMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/DiffusionMercurialMergedCommitsQuery.php', 'DiffusionMercurialRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionMercurialRawDiffQuery.php', 'DiffusionMercurialRequest' => 'applications/diffusion/request/DiffusionMercurialRequest.php', 'DiffusionMercurialTagListQuery' => 'applications/diffusion/query/taglist/DiffusionMercurialTagListQuery.php', 'DiffusionMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/DiffusionMergedCommitsQuery.php', 'DiffusionPathChange' => 'applications/diffusion/data/DiffusionPathChange.php', 'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php', 'DiffusionPathCompleteController' => 'applications/diffusion/controller/DiffusionPathCompleteController.php', 'DiffusionPathIDQuery' => 'applications/diffusion/query/pathid/DiffusionPathIDQuery.php', 'DiffusionPathQuery' => 'applications/diffusion/query/DiffusionPathQuery.php', 'DiffusionPathQueryTestCase' => 'applications/diffusion/query/pathid/__tests__/DiffusionPathQueryTestCase.php', 'DiffusionPathValidateController' => 'applications/diffusion/controller/DiffusionPathValidateController.php', 'DiffusionPeopleMenuEventListener' => 'applications/diffusion/events/DiffusionPeopleMenuEventListener.php', 'DiffusionQuery' => 'applications/diffusion/query/DiffusionQuery.php', 'DiffusionRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionRawDiffQuery.php', 'DiffusionRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRemarkupRule.php', 'DiffusionRenameHistoryQuery' => 'applications/diffusion/query/DiffusionRenameHistoryQuery.php', 'DiffusionRepositoryController' => 'applications/diffusion/controller/DiffusionRepositoryController.php', 'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php', 'DiffusionRepositoryTag' => 'applications/diffusion/DiffusionRepositoryTag.php', 'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php', 'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php', 'DiffusionSvnBrowseQuery' => 'applications/diffusion/query/browse/DiffusionSvnBrowseQuery.php', 'DiffusionSvnCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionSvnCommitParentsQuery.php', 'DiffusionSvnCommitTagsQuery' => 'applications/diffusion/query/committags/DiffusionSvnCommitTagsQuery.php', 'DiffusionSvnContainsQuery' => 'applications/diffusion/query/contains/DiffusionSvnContainsQuery.php', 'DiffusionSvnDiffQuery' => 'applications/diffusion/query/diff/DiffusionSvnDiffQuery.php', 'DiffusionSvnExistsQuery' => 'applications/diffusion/query/exists/DiffusionSvnExistsQuery.php', 'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionSvnFileContentQuery.php', 'DiffusionSvnHistoryQuery' => 'applications/diffusion/query/history/DiffusionSvnHistoryQuery.php', 'DiffusionSvnLastModifiedQuery' => 'applications/diffusion/query/lastmodified/DiffusionSvnLastModifiedQuery.php', 'DiffusionSvnMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/DiffusionSvnMergedCommitsQuery.php', 'DiffusionSvnRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionSvnRawDiffQuery.php', 'DiffusionSvnRequest' => 'applications/diffusion/request/DiffusionSvnRequest.php', 'DiffusionSvnTagListQuery' => 'applications/diffusion/query/taglist/DiffusionSvnTagListQuery.php', 'DiffusionSymbolController' => 'applications/diffusion/controller/DiffusionSymbolController.php', 'DiffusionSymbolQuery' => 'applications/diffusion/query/DiffusionSymbolQuery.php', 'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php', 'DiffusionTagListQuery' => 'applications/diffusion/query/taglist/DiffusionTagListQuery.php', 'DiffusionTagListView' => 'applications/diffusion/view/DiffusionTagListView.php', 'DiffusionURITestCase' => 'applications/diffusion/request/__tests__/DiffusionURITestCase.php', 'DiffusionView' => 'applications/diffusion/view/DiffusionView.php', 'DivinerArticleAtomizer' => 'applications/diviner/atomizer/DivinerArticleAtomizer.php', 'DivinerAtom' => 'applications/diviner/atom/DivinerAtom.php', 'DivinerAtomCache' => 'applications/diviner/cache/DivinerAtomCache.php', 'DivinerAtomRef' => 'applications/diviner/atom/DivinerAtomRef.php', 'DivinerAtomizeWorkflow' => 'applications/diviner/workflow/DivinerAtomizeWorkflow.php', 'DivinerAtomizer' => 'applications/diviner/atomizer/DivinerAtomizer.php', 'DivinerDefaultRenderer' => 'applications/diviner/renderer/DivinerDefaultRenderer.php', 'DivinerDiskCache' => 'applications/diviner/cache/DivinerDiskCache.php', 'DivinerFileAtomizer' => 'applications/diviner/atomizer/DivinerFileAtomizer.php', 'DivinerGenerateWorkflow' => 'applications/diviner/workflow/DivinerGenerateWorkflow.php', 'DivinerListController' => 'applications/diviner/controller/DivinerListController.php', 'DivinerPublishCache' => 'applications/diviner/cache/DivinerPublishCache.php', 'DivinerPublisher' => 'applications/diviner/publisher/DivinerPublisher.php', 'DivinerRemarkupRuleSymbol' => 'applications/diviner/markup/DivinerRemarkupRuleSymbol.php', 'DivinerRenderer' => 'applications/diviner/renderer/DivinerRenderer.php', 'DivinerStaticPublisher' => 'applications/diviner/publisher/DivinerStaticPublisher.php', 'DivinerWorkflow' => 'applications/diviner/workflow/DivinerWorkflow.php', 'DrydockAllocatorWorker' => 'applications/drydock/worker/DrydockAllocatorWorker.php', 'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/DrydockApacheWebrootInterface.php', 'DrydockBlueprint' => 'applications/drydock/blueprint/DrydockBlueprint.php', 'DrydockBlueprintScopeGuard' => 'applications/drydock/util/DrydockBlueprintScopeGuard.php', 'DrydockCommandInterface' => 'applications/drydock/interface/command/DrydockCommandInterface.php', 'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php', 'DrydockController' => 'applications/drydock/controller/DrydockController.php', 'DrydockDAO' => 'applications/drydock/storage/DrydockDAO.php', 'DrydockInterface' => 'applications/drydock/interface/DrydockInterface.php', 'DrydockLease' => 'applications/drydock/storage/DrydockLease.php', 'DrydockLeaseListController' => 'applications/drydock/controller/DrydockLeaseListController.php', 'DrydockLeaseQuery' => 'applications/drydock/query/DrydockLeaseQuery.php', 'DrydockLeaseReleaseController' => 'applications/drydock/controller/DrydockLeaseReleaseController.php', 'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php', 'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.php', 'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/DrydockLocalCommandInterface.php', 'DrydockLocalHostBlueprint' => 'applications/drydock/blueprint/DrydockLocalHostBlueprint.php', 'DrydockLog' => 'applications/drydock/storage/DrydockLog.php', 'DrydockLogController' => 'applications/drydock/controller/DrydockLogController.php', 'DrydockLogQuery' => 'applications/drydock/query/DrydockLogQuery.php', 'DrydockManagementCloseWorkflow' => 'applications/drydock/management/DrydockManagementCloseWorkflow.php', 'DrydockManagementLeaseWorkflow' => 'applications/drydock/management/DrydockManagementLeaseWorkflow.php', 'DrydockManagementReleaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseWorkflow.php', 'DrydockManagementWaitForLeaseWorkflow' => 'applications/drydock/management/DrydockManagementWaitForLeaseWorkflow.php', 'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php', 'DrydockResource' => 'applications/drydock/storage/DrydockResource.php', 'DrydockResourceCloseController' => 'applications/drydock/controller/DrydockResourceCloseController.php', 'DrydockResourceListController' => 'applications/drydock/controller/DrydockResourceListController.php', 'DrydockResourceQuery' => 'applications/drydock/query/DrydockResourceQuery.php', 'DrydockResourceStatus' => 'applications/drydock/constants/DrydockResourceStatus.php', 'DrydockResourceViewController' => 'applications/drydock/controller/DrydockResourceViewController.php', 'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/DrydockSSHCommandInterface.php', 'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/DrydockWebrootInterface.php', 'DrydockWorkingCopyBlueprint' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php', 'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php', 'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', 'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', 'HarbormasterRunnerWorker' => 'applications/harbormaster/worker/HarbormasterRunnerWorker.php', 'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php', 'HeraldAction' => 'applications/herald/storage/HeraldAction.php', 'HeraldActionConfig' => 'applications/herald/config/HeraldActionConfig.php', 'HeraldApplyTranscript' => 'applications/herald/storage/transcript/HeraldApplyTranscript.php', 'HeraldCommitAdapter' => 'applications/herald/adapter/HeraldCommitAdapter.php', 'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php', 'HeraldConditionConfig' => 'applications/herald/config/HeraldConditionConfig.php', 'HeraldConditionTranscript' => 'applications/herald/storage/transcript/HeraldConditionTranscript.php', 'HeraldContentTypeConfig' => 'applications/herald/config/HeraldContentTypeConfig.php', 'HeraldController' => 'applications/herald/controller/HeraldController.php', 'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php', 'HeraldDeleteController' => 'applications/herald/controller/HeraldDeleteController.php', 'HeraldDifferentialRevisionAdapter' => 'applications/herald/adapter/HeraldDifferentialRevisionAdapter.php', 'HeraldDryRunAdapter' => 'applications/herald/adapter/HeraldDryRunAdapter.php', 'HeraldEditLogQuery' => 'applications/herald/query/HeraldEditLogQuery.php', 'HeraldEffect' => 'applications/herald/engine/HeraldEffect.php', 'HeraldEngine' => 'applications/herald/engine/HeraldEngine.php', 'HeraldFieldConfig' => 'applications/herald/config/HeraldFieldConfig.php', 'HeraldHomeController' => 'applications/herald/controller/HeraldHomeController.php', 'HeraldInvalidConditionException' => 'applications/herald/engine/engine/HeraldInvalidConditionException.php', 'HeraldInvalidFieldException' => 'applications/herald/engine/engine/HeraldInvalidFieldException.php', 'HeraldNewController' => 'applications/herald/controller/HeraldNewController.php', 'HeraldObjectAdapter' => 'applications/herald/adapter/HeraldObjectAdapter.php', 'HeraldObjectTranscript' => 'applications/herald/storage/transcript/HeraldObjectTranscript.php', 'HeraldRecursiveConditionsException' => 'applications/herald/engine/engine/HeraldRecursiveConditionsException.php', 'HeraldRepetitionPolicyConfig' => 'applications/herald/config/HeraldRepetitionPolicyConfig.php', 'HeraldRule' => 'applications/herald/storage/HeraldRule.php', 'HeraldRuleController' => 'applications/herald/controller/HeraldRuleController.php', 'HeraldRuleEdit' => 'applications/herald/storage/HeraldRuleEdit.php', 'HeraldRuleEditHistoryController' => 'applications/herald/controller/HeraldRuleEditHistoryController.php', 'HeraldRuleEditHistoryView' => 'applications/herald/view/HeraldRuleEditHistoryView.php', 'HeraldRuleListView' => 'applications/herald/view/HeraldRuleListView.php', 'HeraldRuleQuery' => 'applications/herald/query/HeraldRuleQuery.php', 'HeraldRuleTranscript' => 'applications/herald/storage/transcript/HeraldRuleTranscript.php', 'HeraldRuleTypeConfig' => 'applications/herald/config/HeraldRuleTypeConfig.php', 'HeraldTestConsoleController' => 'applications/herald/controller/HeraldTestConsoleController.php', 'HeraldTranscript' => 'applications/herald/storage/transcript/HeraldTranscript.php', 'HeraldTranscriptController' => 'applications/herald/controller/HeraldTranscriptController.php', 'HeraldTranscriptListController' => 'applications/herald/controller/HeraldTranscriptListController.php', 'HeraldValueTypeConfig' => 'applications/herald/config/HeraldValueTypeConfig.php', 'Javelin' => 'infrastructure/javelin/Javelin.php', 'JavelinReactorExample' => 'applications/uiexample/examples/JavelinReactorExample.php', 'JavelinUIExample' => 'applications/uiexample/examples/JavelinUIExample.php', 'JavelinViewExample' => 'applications/uiexample/examples/JavelinViewExample.php', 'JavelinViewExampleServerView' => 'applications/uiexample/examples/JavelinViewExampleServerView.php', 'LiskChunkTestCase' => 'infrastructure/storage/lisk/__tests__/LiskChunkTestCase.php', 'LiskDAO' => 'infrastructure/storage/lisk/LiskDAO.php', 'LiskDAOSet' => 'infrastructure/storage/lisk/LiskDAOSet.php', 'LiskDAOTestCase' => 'infrastructure/storage/lisk/__tests__/LiskDAOTestCase.php', 'LiskEphemeralObjectException' => 'infrastructure/storage/lisk/LiskEphemeralObjectException.php', 'LiskFixtureTestCase' => 'infrastructure/storage/lisk/__tests__/LiskFixtureTestCase.php', 'LiskIsolationTestCase' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestCase.php', 'LiskIsolationTestDAO' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestDAO.php', 'LiskIsolationTestDAOException' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestDAOException.php', 'LiskMigrationIterator' => 'infrastructure/storage/lisk/LiskMigrationIterator.php', 'ManiphestAction' => 'applications/maniphest/constants/ManiphestAction.php', 'ManiphestAuxiliaryFieldDefaultSpecification' => 'applications/maniphest/auxiliaryfield/ManiphestAuxiliaryFieldDefaultSpecification.php', 'ManiphestAuxiliaryFieldSpecification' => 'applications/maniphest/auxiliaryfield/ManiphestAuxiliaryFieldSpecification.php', 'ManiphestAuxiliaryFieldTypeException' => 'applications/maniphest/auxiliaryfield/ManiphestAuxiliaryFieldTypeException.php', 'ManiphestAuxiliaryFieldValidationException' => 'applications/maniphest/auxiliaryfield/ManiphestAuxiliaryFieldValidationException.php', 'ManiphestBatchEditController' => 'applications/maniphest/controller/ManiphestBatchEditController.php', 'ManiphestConstants' => 'applications/maniphest/constants/ManiphestConstants.php', 'ManiphestController' => 'applications/maniphest/controller/ManiphestController.php', 'ManiphestDAO' => 'applications/maniphest/storage/ManiphestDAO.php', 'ManiphestDefaultTaskExtensions' => 'applications/maniphest/extensions/ManiphestDefaultTaskExtensions.php', 'ManiphestEdgeEventListener' => 'applications/maniphest/event/ManiphestEdgeEventListener.php', 'ManiphestExportController' => 'applications/maniphest/controller/ManiphestExportController.php', 'ManiphestPeopleMenuEventListener' => 'applications/maniphest/event/ManiphestPeopleMenuEventListener.php', 'ManiphestRemarkupRule' => 'applications/maniphest/remarkup/ManiphestRemarkupRule.php', 'ManiphestReplyHandler' => 'applications/maniphest/ManiphestReplyHandler.php', 'ManiphestReportController' => 'applications/maniphest/controller/ManiphestReportController.php', 'ManiphestSavedQuery' => 'applications/maniphest/storage/ManiphestSavedQuery.php', 'ManiphestSavedQueryDeleteController' => 'applications/maniphest/controller/ManiphestSavedQueryDeleteController.php', 'ManiphestSavedQueryEditController' => 'applications/maniphest/controller/ManiphestSavedQueryEditController.php', 'ManiphestSavedQueryListController' => 'applications/maniphest/controller/ManiphestSavedQueryListController.php', 'ManiphestSearchIndexer' => 'applications/maniphest/search/ManiphestSearchIndexer.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', 'ManiphestTaskAuxiliaryStorage' => 'applications/maniphest/storage/ManiphestTaskAuxiliaryStorage.php', 'ManiphestTaskDescriptionChangeController' => 'applications/maniphest/controller/ManiphestTaskDescriptionChangeController.php', 'ManiphestTaskDescriptionPreviewController' => 'applications/maniphest/controller/ManiphestTaskDescriptionPreviewController.php', 'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php', 'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php', 'ManiphestTaskExtensions' => 'applications/maniphest/extensions/ManiphestTaskExtensions.php', 'ManiphestTaskListController' => 'applications/maniphest/controller/ManiphestTaskListController.php', 'ManiphestTaskListView' => 'applications/maniphest/view/ManiphestTaskListView.php', 'ManiphestTaskOwner' => 'applications/maniphest/constants/ManiphestTaskOwner.php', 'ManiphestTaskPriority' => 'applications/maniphest/constants/ManiphestTaskPriority.php', 'ManiphestTaskProject' => 'applications/maniphest/storage/ManiphestTaskProject.php', 'ManiphestTaskProjectsView' => 'applications/maniphest/view/ManiphestTaskProjectsView.php', 'ManiphestTaskQuery' => 'applications/maniphest/ManiphestTaskQuery.php', 'ManiphestTaskStatus' => 'applications/maniphest/constants/ManiphestTaskStatus.php', 'ManiphestTaskSubscriber' => 'applications/maniphest/storage/ManiphestTaskSubscriber.php', 'ManiphestTaskSummaryView' => 'applications/maniphest/view/ManiphestTaskSummaryView.php', 'ManiphestTransaction' => 'applications/maniphest/storage/ManiphestTransaction.php', 'ManiphestTransactionDetailView' => 'applications/maniphest/view/ManiphestTransactionDetailView.php', 'ManiphestTransactionEditor' => 'applications/maniphest/editor/ManiphestTransactionEditor.php', 'ManiphestTransactionListView' => 'applications/maniphest/view/ManiphestTransactionListView.php', 'ManiphestTransactionPreviewController' => 'applications/maniphest/controller/ManiphestTransactionPreviewController.php', 'ManiphestTransactionSaveController' => 'applications/maniphest/controller/ManiphestTransactionSaveController.php', 'ManiphestTransactionType' => 'applications/maniphest/constants/ManiphestTransactionType.php', 'ManiphestView' => 'applications/maniphest/view/ManiphestView.php', 'MetaMTAConstants' => 'applications/metamta/constants/MetaMTAConstants.php', 'MetaMTANotificationType' => 'applications/metamta/constants/MetaMTANotificationType.php', 'ObjectHandleLoader' => 'applications/phid/handle/ObjectHandleLoader.php', 'OwnersPackageReplyHandler' => 'applications/owners/OwnersPackageReplyHandler.php', 'PackageCreateMail' => 'applications/owners/mail/PackageCreateMail.php', 'PackageDeleteMail' => 'applications/owners/mail/PackageDeleteMail.php', 'PackageMail' => 'applications/owners/mail/PackageMail.php', 'PackageModifyMail' => 'applications/owners/mail/PackageModifyMail.php', 'PasteEmbedView' => 'applications/paste/view/PasteEmbedView.php', 'Phabricator404Controller' => 'applications/base/controller/Phabricator404Controller.php', 'PhabricatorAWSConfigOptions' => 'applications/config/option/PhabricatorAWSConfigOptions.php', 'PhabricatorAccessLog' => 'infrastructure/PhabricatorAccessLog.php', 'PhabricatorAccessLogConfigOptions' => 'applications/config/option/PhabricatorAccessLogConfigOptions.php', 'PhabricatorActionListExample' => 'applications/uiexample/examples/PhabricatorActionListExample.php', 'PhabricatorActionListView' => 'view/layout/PhabricatorActionListView.php', 'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php', 'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/PhabricatorAllCapsTranslation.php', 'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php', 'PhabricatorAphrontBarExample' => 'applications/uiexample/examples/PhabricatorAphrontBarExample.php', 'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php', 'PhabricatorApplicationApplications' => 'applications/meta/application/PhabricatorApplicationApplications.php', 'PhabricatorApplicationAudit' => 'applications/audit/application/PhabricatorApplicationAudit.php', 'PhabricatorApplicationAuth' => 'applications/auth/application/PhabricatorApplicationAuth.php', 'PhabricatorApplicationCalendar' => 'applications/calendar/application/PhabricatorApplicationCalendar.php', 'PhabricatorApplicationChatLog' => 'applications/chatlog/applications/PhabricatorApplicationChatLog.php', 'PhabricatorApplicationConduit' => 'applications/conduit/application/PhabricatorApplicationConduit.php', 'PhabricatorApplicationConfig' => 'applications/config/application/PhabricatorApplicationConfig.php', 'PhabricatorApplicationConfigOptions' => 'applications/config/option/PhabricatorApplicationConfigOptions.php', 'PhabricatorApplicationConpherence' => 'applications/conpherence/application/PhabricatorApplicationConpherence.php', 'PhabricatorApplicationCountdown' => 'applications/countdown/application/PhabricatorApplicationCountdown.php', 'PhabricatorApplicationDaemons' => 'applications/daemon/application/PhabricatorApplicationDaemons.php', 'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php', 'PhabricatorApplicationDifferential' => 'applications/differential/application/PhabricatorApplicationDifferential.php', 'PhabricatorApplicationDiffusion' => 'applications/diffusion/application/PhabricatorApplicationDiffusion.php', 'PhabricatorApplicationDiviner' => 'applications/diviner/application/PhabricatorApplicationDiviner.php', 'PhabricatorApplicationDrydock' => 'applications/drydock/application/PhabricatorApplicationDrydock.php', 'PhabricatorApplicationFact' => 'applications/fact/application/PhabricatorApplicationFact.php', 'PhabricatorApplicationFeed' => 'applications/feed/application/PhabricatorApplicationFeed.php', 'PhabricatorApplicationFiles' => 'applications/files/application/PhabricatorApplicationFiles.php', 'PhabricatorApplicationFlags' => 'applications/flag/application/PhabricatorApplicationFlags.php', 'PhabricatorApplicationHerald' => 'applications/herald/application/PhabricatorApplicationHerald.php', 'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php', 'PhabricatorApplicationMacro' => 'applications/macro/application/PhabricatorApplicationMacro.php', 'PhabricatorApplicationMailingLists' => 'applications/mailinglists/application/PhabricatorApplicationMailingLists.php', 'PhabricatorApplicationManiphest' => 'applications/maniphest/application/PhabricatorApplicationManiphest.php', 'PhabricatorApplicationMetaMTA' => 'applications/metamta/application/PhabricatorApplicationMetaMTA.php', 'PhabricatorApplicationOwners' => 'applications/owners/application/PhabricatorApplicationOwners.php', 'PhabricatorApplicationPHID' => 'applications/phid/application/PhabricatorApplicationPHID.php', 'PhabricatorApplicationPHPAST' => 'applications/phpast/application/PhabricatorApplicationPHPAST.php', 'PhabricatorApplicationPaste' => 'applications/paste/application/PhabricatorApplicationPaste.php', 'PhabricatorApplicationPeople' => 'applications/people/application/PhabricatorApplicationPeople.php', 'PhabricatorApplicationPhame' => 'applications/phame/application/PhabricatorApplicationPhame.php', 'PhabricatorApplicationPholio' => 'applications/pholio/application/PhabricatorApplicationPholio.php', 'PhabricatorApplicationPhriction' => 'applications/phriction/application/PhabricatorApplicationPhriction.php', 'PhabricatorApplicationPonder' => 'applications/ponder/application/PhabricatorApplicationPonder.php', 'PhabricatorApplicationProject' => 'applications/project/application/PhabricatorApplicationProject.php', + 'PhabricatorApplicationReleeph' => 'applications/releeph/application/PhabricatorApplicationReleeph.php', + 'PhabricatorApplicationReleephConfigOptions' => 'applications/releeph/config/PhabricatorApplicationReleephConfigOptions.php', 'PhabricatorApplicationRepositories' => 'applications/repository/application/PhabricatorApplicationRepositories.php', 'PhabricatorApplicationSettings' => 'applications/settings/application/PhabricatorApplicationSettings.php', 'PhabricatorApplicationSlowvote' => 'applications/slowvote/application/PhabricatorApplicationSlowvote.php', 'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php', 'PhabricatorApplicationSubscriptions' => 'applications/subscriptions/application/PhabricatorApplicationSubscriptions.php', 'PhabricatorApplicationTokens' => 'applications/tokens/application/PhabricatorApplicationTokens.php', 'PhabricatorApplicationTransaction' => 'applications/transactions/storage/PhabricatorApplicationTransaction.php', 'PhabricatorApplicationTransactionComment' => 'applications/transactions/storage/PhabricatorApplicationTransactionComment.php', 'PhabricatorApplicationTransactionCommentEditController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentEditController.php', 'PhabricatorApplicationTransactionCommentEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php', 'PhabricatorApplicationTransactionCommentHistoryController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentHistoryController.php', 'PhabricatorApplicationTransactionCommentQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php', 'PhabricatorApplicationTransactionCommentView' => 'applications/transactions/view/PhabricatorApplicationTransactionCommentView.php', 'PhabricatorApplicationTransactionController' => 'applications/transactions/controller/PhabricatorApplicationTransactionController.php', 'PhabricatorApplicationTransactionEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionEditor.php', 'PhabricatorApplicationTransactionFeedStory' => 'applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php', 'PhabricatorApplicationTransactionInterface' => 'applications/transactions/interface/PhabricatorApplicationTransactionInterface.php', 'PhabricatorApplicationTransactionNoEffectException' => 'applications/transactions/exception/PhabricatorApplicationTransactionNoEffectException.php', 'PhabricatorApplicationTransactionNoEffectResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionNoEffectResponse.php', 'PhabricatorApplicationTransactionQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionQuery.php', 'PhabricatorApplicationTransactionResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionResponse.php', 'PhabricatorApplicationTransactionTextDiffDetailView' => 'applications/transactions/view/PhabricatorApplicationTransactionTextDiffDetailView.php', 'PhabricatorApplicationTransactionView' => 'applications/transactions/view/PhabricatorApplicationTransactionView.php', 'PhabricatorApplicationTransactions' => 'applications/transactions/application/PhabricatorApplicationTransactions.php', 'PhabricatorApplicationUIExamples' => 'applications/uiexample/application/PhabricatorApplicationUIExamples.php', 'PhabricatorApplicationUninstallController' => 'applications/meta/controller/PhabricatorApplicationUninstallController.php', 'PhabricatorApplicationsController' => 'applications/meta/controller/PhabricatorApplicationsController.php', 'PhabricatorApplicationsListController' => 'applications/meta/controller/PhabricatorApplicationsListController.php', 'PhabricatorAuditActionConstants' => 'applications/audit/constants/PhabricatorAuditActionConstants.php', 'PhabricatorAuditAddCommentController' => 'applications/audit/controller/PhabricatorAuditAddCommentController.php', 'PhabricatorAuditComment' => 'applications/audit/storage/PhabricatorAuditComment.php', 'PhabricatorAuditCommentEditor' => 'applications/audit/editor/PhabricatorAuditCommentEditor.php', 'PhabricatorAuditCommitListView' => 'applications/audit/view/PhabricatorAuditCommitListView.php', 'PhabricatorAuditCommitQuery' => 'applications/audit/query/PhabricatorAuditCommitQuery.php', 'PhabricatorAuditCommitStatusConstants' => 'applications/audit/constants/PhabricatorAuditCommitStatusConstants.php', 'PhabricatorAuditController' => 'applications/audit/controller/PhabricatorAuditController.php', 'PhabricatorAuditDAO' => 'applications/audit/storage/PhabricatorAuditDAO.php', 'PhabricatorAuditInlineComment' => 'applications/audit/storage/PhabricatorAuditInlineComment.php', 'PhabricatorAuditListController' => 'applications/audit/controller/PhabricatorAuditListController.php', 'PhabricatorAuditListView' => 'applications/audit/view/PhabricatorAuditListView.php', 'PhabricatorAuditPreviewController' => 'applications/audit/controller/PhabricatorAuditPreviewController.php', 'PhabricatorAuditQuery' => 'applications/audit/query/PhabricatorAuditQuery.php', 'PhabricatorAuditReplyHandler' => 'applications/audit/PhabricatorAuditReplyHandler.php', 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', 'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php', 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', 'PhabricatorBarePageExample' => 'applications/uiexample/examples/PhabricatorBarePageExample.php', 'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php', 'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php', 'PhabricatorBaseProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBaseProtocolAdapter.php', 'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php', 'PhabricatorBotBaseStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBotBaseStreamingProtocolAdapter.php', 'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php', 'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php', 'PhabricatorBotDifferentialNotificationHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDifferentialNotificationHandler.php', 'PhabricatorBotFeedNotificationHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotFeedNotificationHandler.php', 'PhabricatorBotFlowdockProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBotFlowdockProtocolAdapter.php', 'PhabricatorBotHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotHandler.php', 'PhabricatorBotLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotLogHandler.php', 'PhabricatorBotMacroHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php', 'PhabricatorBotMessage' => 'infrastructure/daemon/bot/PhabricatorBotMessage.php', 'PhabricatorBotObjectNameHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php', 'PhabricatorBotSymbolHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotSymbolHandler.php', 'PhabricatorBotTarget' => 'infrastructure/daemon/bot/target/PhabricatorBotTarget.php', 'PhabricatorBotUser' => 'infrastructure/daemon/bot/target/PhabricatorBotUser.php', 'PhabricatorBotWhatsNewHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php', 'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php', 'PhabricatorButtonsExample' => 'applications/uiexample/examples/PhabricatorButtonsExample.php', 'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php', 'PhabricatorCaches' => 'applications/cache/PhabricatorCaches.php', 'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php', 'PhabricatorCalendarController' => 'applications/calendar/controller/PhabricatorCalendarController.php', 'PhabricatorCalendarDAO' => 'applications/calendar/storage/PhabricatorCalendarDAO.php', 'PhabricatorCalendarDeleteStatusController' => 'applications/calendar/controller/PhabricatorCalendarDeleteStatusController.php', 'PhabricatorCalendarEditStatusController' => 'applications/calendar/controller/PhabricatorCalendarEditStatusController.php', 'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php', 'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php', 'PhabricatorCalendarViewStatusController' => 'applications/calendar/controller/PhabricatorCalendarViewStatusController.php', 'PhabricatorCampfireProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php', 'PhabricatorChangesetResponse' => 'infrastructure/diff/PhabricatorChangesetResponse.php', 'PhabricatorChatLogChannel' => 'applications/chatlog/storage/PhabricatorChatLogChannel.php', 'PhabricatorChatLogChannelListController' => 'applications/chatlog/controller/PhabricatorChatLogChannelListController.php', 'PhabricatorChatLogChannelLogController' => 'applications/chatlog/controller/PhabricatorChatLogChannelLogController.php', 'PhabricatorChatLogChannelQuery' => 'applications/chatlog/PhabricatorChatLogChannelQuery.php', 'PhabricatorChatLogConstants' => 'applications/chatlog/constants/PhabricatorChatLogConstants.php', 'PhabricatorChatLogController' => 'applications/chatlog/controller/PhabricatorChatLogController.php', 'PhabricatorChatLogDAO' => 'applications/chatlog/storage/PhabricatorChatLogDAO.php', 'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php', 'PhabricatorChatLogEventType' => 'applications/chatlog/constants/PhabricatorChatLogEventType.php', 'PhabricatorChatLogQuery' => 'applications/chatlog/PhabricatorChatLogQuery.php', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php', 'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/PhabricatorConduitConnectionLog.php', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/PhabricatorConduitConsoleController.php', 'PhabricatorConduitController' => 'applications/conduit/controller/PhabricatorConduitController.php', 'PhabricatorConduitDAO' => 'applications/conduit/storage/PhabricatorConduitDAO.php', 'PhabricatorConduitListController' => 'applications/conduit/controller/PhabricatorConduitListController.php', 'PhabricatorConduitLogController' => 'applications/conduit/controller/PhabricatorConduitLogController.php', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php', 'PhabricatorConduitTokenController' => 'applications/conduit/controller/PhabricatorConduitTokenController.php', 'PhabricatorConfigAllController' => 'applications/config/controller/PhabricatorConfigAllController.php', 'PhabricatorConfigController' => 'applications/config/controller/PhabricatorConfigController.php', 'PhabricatorConfigDatabaseSource' => 'infrastructure/env/PhabricatorConfigDatabaseSource.php', 'PhabricatorConfigDefaultSource' => 'infrastructure/env/PhabricatorConfigDefaultSource.php', 'PhabricatorConfigDictionarySource' => 'infrastructure/env/PhabricatorConfigDictionarySource.php', 'PhabricatorConfigEditController' => 'applications/config/controller/PhabricatorConfigEditController.php', 'PhabricatorConfigEditor' => 'applications/config/editor/PhabricatorConfigEditor.php', 'PhabricatorConfigEntry' => 'applications/config/storage/PhabricatorConfigEntry.php', 'PhabricatorConfigEntryDAO' => 'applications/config/storage/PhabricatorConfigEntryDAO.php', 'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php', 'PhabricatorConfigGroupController' => 'applications/config/controller/PhabricatorConfigGroupController.php', 'PhabricatorConfigIgnoreController' => 'applications/config/controller/PhabricatorConfigIgnoreController.php', 'PhabricatorConfigIssueListController' => 'applications/config/controller/PhabricatorConfigIssueListController.php', 'PhabricatorConfigIssueViewController' => 'applications/config/controller/PhabricatorConfigIssueViewController.php', 'PhabricatorConfigJSON' => 'applications/config/json/PhabricatorConfigJSON.php', 'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php', 'PhabricatorConfigLocalSource' => 'infrastructure/env/PhabricatorConfigLocalSource.php', 'PhabricatorConfigManagementDeleteWorkflow' => 'applications/config/management/PhabricatorConfigManagementDeleteWorkflow.php', 'PhabricatorConfigManagementGetWorkflow' => 'applications/config/management/PhabricatorConfigManagementGetWorkflow.php', 'PhabricatorConfigManagementListWorkflow' => 'applications/config/management/PhabricatorConfigManagementListWorkflow.php', 'PhabricatorConfigManagementSetWorkflow' => 'applications/config/management/PhabricatorConfigManagementSetWorkflow.php', 'PhabricatorConfigManagementWorkflow' => 'applications/config/management/PhabricatorConfigManagementWorkflow.php', 'PhabricatorConfigOption' => 'applications/config/option/PhabricatorConfigOption.php', 'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php', 'PhabricatorConfigResponse' => 'applications/config/response/PhabricatorConfigResponse.php', 'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php', 'PhabricatorConfigStackSource' => 'infrastructure/env/PhabricatorConfigStackSource.php', 'PhabricatorConfigTransaction' => 'applications/config/storage/PhabricatorConfigTransaction.php', 'PhabricatorConfigTransactionQuery' => 'applications/config/query/PhabricatorConfigTransactionQuery.php', 'PhabricatorConfigValidationException' => 'applications/config/exception/PhabricatorConfigValidationException.php', 'PhabricatorContentSource' => 'applications/metamta/contentsource/PhabricatorContentSource.php', 'PhabricatorContentSourceView' => 'applications/metamta/contentsource/PhabricatorContentSourceView.php', 'PhabricatorController' => 'applications/base/controller/PhabricatorController.php', 'PhabricatorCoreConfigOptions' => 'applications/config/option/PhabricatorCoreConfigOptions.php', 'PhabricatorCountdownController' => 'applications/countdown/controller/PhabricatorCountdownController.php', 'PhabricatorCountdownDAO' => 'applications/countdown/storage/PhabricatorCountdownDAO.php', 'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/PhabricatorCountdownDeleteController.php', 'PhabricatorCountdownEditController' => 'applications/countdown/controller/PhabricatorCountdownEditController.php', 'PhabricatorCountdownListController' => 'applications/countdown/controller/PhabricatorCountdownListController.php', 'PhabricatorCountdownRemarkupRule' => 'applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php', 'PhabricatorCountdownViewController' => 'applications/countdown/controller/PhabricatorCountdownViewController.php', 'PhabricatorCountedToggleButtonsExample' => 'applications/uiexample/examples/PhabricatorCountedToggleButtonsExample.php', 'PhabricatorCrumbView' => 'view/layout/PhabricatorCrumbView.php', 'PhabricatorCrumbsView' => 'view/layout/PhabricatorCrumbsView.php', 'PhabricatorCursorPagedPolicyAwareQuery' => 'infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php', 'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php', 'PhabricatorDaemonCombinedLogController' => 'applications/daemon/controller/PhabricatorDaemonCombinedLogController.php', 'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/PhabricatorDaemonConsoleController.php', 'PhabricatorDaemonControl' => 'infrastructure/daemon/PhabricatorDaemonControl.php', 'PhabricatorDaemonController' => 'applications/daemon/controller/PhabricatorDaemonController.php', 'PhabricatorDaemonDAO' => 'infrastructure/daemon/storage/PhabricatorDaemonDAO.php', 'PhabricatorDaemonLog' => 'infrastructure/daemon/storage/PhabricatorDaemonLog.php', 'PhabricatorDaemonLogEvent' => 'infrastructure/daemon/storage/PhabricatorDaemonLogEvent.php', 'PhabricatorDaemonLogEventsView' => 'applications/daemon/view/PhabricatorDaemonLogEventsView.php', 'PhabricatorDaemonLogListController' => 'applications/daemon/controller/PhabricatorDaemonLogListController.php', 'PhabricatorDaemonLogListView' => 'applications/daemon/view/PhabricatorDaemonLogListView.php', 'PhabricatorDaemonLogViewController' => 'applications/daemon/controller/PhabricatorDaemonLogViewController.php', 'PhabricatorDaemonReference' => 'infrastructure/daemon/control/PhabricatorDaemonReference.php', 'PhabricatorDebugController' => 'applications/system/PhabricatorDebugController.php', 'PhabricatorDefaultFileStorageEngineSelector' => 'applications/files/engineselector/PhabricatorDefaultFileStorageEngineSelector.php', 'PhabricatorDefaultSearchEngineSelector' => 'applications/search/selector/PhabricatorDefaultSearchEngineSelector.php', 'PhabricatorDeveloperConfigOptions' => 'applications/config/option/PhabricatorDeveloperConfigOptions.php', 'PhabricatorDifferenceEngine' => 'infrastructure/diff/PhabricatorDifferenceEngine.php', 'PhabricatorDifferentialConfigOptions' => 'applications/differential/config/PhabricatorDifferentialConfigOptions.php', 'PhabricatorDiffusionConfigOptions' => 'applications/diffusion/config/PhabricatorDiffusionConfigOptions.php', 'PhabricatorDirectoryController' => 'applications/directory/controller/PhabricatorDirectoryController.php', 'PhabricatorDirectoryMainController' => 'applications/directory/controller/PhabricatorDirectoryMainController.php', 'PhabricatorDisabledUserController' => 'applications/auth/controller/PhabricatorDisabledUserController.php', 'PhabricatorDisqusConfigOptions' => 'applications/config/option/PhabricatorDisqusConfigOptions.php', 'PhabricatorDraft' => 'applications/draft/storage/PhabricatorDraft.php', 'PhabricatorDraftDAO' => 'applications/draft/storage/PhabricatorDraftDAO.php', 'PhabricatorEdgeConfig' => 'infrastructure/edges/constants/PhabricatorEdgeConfig.php', 'PhabricatorEdgeConstants' => 'infrastructure/edges/constants/PhabricatorEdgeConstants.php', 'PhabricatorEdgeCycleException' => 'infrastructure/edges/exception/PhabricatorEdgeCycleException.php', 'PhabricatorEdgeEditor' => 'infrastructure/edges/editor/PhabricatorEdgeEditor.php', 'PhabricatorEdgeGraph' => 'infrastructure/edges/util/PhabricatorEdgeGraph.php', 'PhabricatorEdgeQuery' => 'infrastructure/edges/query/PhabricatorEdgeQuery.php', 'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php', 'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php', 'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php', 'PhabricatorEmailTokenController' => 'applications/auth/controller/PhabricatorEmailTokenController.php', 'PhabricatorEmailVerificationController' => 'applications/people/controller/PhabricatorEmailVerificationController.php', 'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php', 'PhabricatorEnglishTranslation' => 'infrastructure/internationalization/PhabricatorEnglishTranslation.php', 'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php', 'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php', 'PhabricatorErrorExample' => 'applications/uiexample/examples/PhabricatorErrorExample.php', 'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php', 'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php', 'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php', 'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php', 'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php', 'PhabricatorFacebookConfigOptions' => 'applications/config/option/PhabricatorFacebookConfigOptions.php', 'PhabricatorFactAggregate' => 'applications/fact/storage/PhabricatorFactAggregate.php', 'PhabricatorFactChartController' => 'applications/fact/controller/PhabricatorFactChartController.php', 'PhabricatorFactController' => 'applications/fact/controller/PhabricatorFactController.php', 'PhabricatorFactCountEngine' => 'applications/fact/engine/PhabricatorFactCountEngine.php', 'PhabricatorFactCursor' => 'applications/fact/storage/PhabricatorFactCursor.php', 'PhabricatorFactDAO' => 'applications/fact/storage/PhabricatorFactDAO.php', 'PhabricatorFactDaemon' => 'applications/fact/daemon/PhabricatorFactDaemon.php', 'PhabricatorFactEngine' => 'applications/fact/engine/PhabricatorFactEngine.php', 'PhabricatorFactHomeController' => 'applications/fact/controller/PhabricatorFactHomeController.php', 'PhabricatorFactLastUpdatedEngine' => 'applications/fact/engine/PhabricatorFactLastUpdatedEngine.php', 'PhabricatorFactManagementAnalyzeWorkflow' => 'applications/fact/management/PhabricatorFactManagementAnalyzeWorkflow.php', 'PhabricatorFactManagementCursorsWorkflow' => 'applications/fact/management/PhabricatorFactManagementCursorsWorkflow.php', 'PhabricatorFactManagementDestroyWorkflow' => 'applications/fact/management/PhabricatorFactManagementDestroyWorkflow.php', 'PhabricatorFactManagementListWorkflow' => 'applications/fact/management/PhabricatorFactManagementListWorkflow.php', 'PhabricatorFactManagementStatusWorkflow' => 'applications/fact/management/PhabricatorFactManagementStatusWorkflow.php', 'PhabricatorFactManagementWorkflow' => 'applications/fact/management/PhabricatorFactManagementWorkflow.php', 'PhabricatorFactRaw' => 'applications/fact/storage/PhabricatorFactRaw.php', 'PhabricatorFactSimpleSpec' => 'applications/fact/spec/PhabricatorFactSimpleSpec.php', 'PhabricatorFactSpec' => 'applications/fact/spec/PhabricatorFactSpec.php', 'PhabricatorFactUpdateIterator' => 'applications/fact/extract/PhabricatorFactUpdateIterator.php', 'PhabricatorFeedBuilder' => 'applications/feed/builder/PhabricatorFeedBuilder.php', 'PhabricatorFeedConfigOptions' => 'applications/feed/config/PhabricatorFeedConfigOptions.php', 'PhabricatorFeedConstants' => 'applications/feed/constants/PhabricatorFeedConstants.php', 'PhabricatorFeedController' => 'applications/feed/controller/PhabricatorFeedController.php', 'PhabricatorFeedDAO' => 'applications/feed/storage/PhabricatorFeedDAO.php', 'PhabricatorFeedMainController' => 'applications/feed/controller/PhabricatorFeedMainController.php', 'PhabricatorFeedPublicStreamController' => 'applications/feed/controller/PhabricatorFeedPublicStreamController.php', 'PhabricatorFeedQuery' => 'applications/feed/PhabricatorFeedQuery.php', 'PhabricatorFeedStory' => 'applications/feed/story/PhabricatorFeedStory.php', 'PhabricatorFeedStoryAggregate' => 'applications/feed/story/PhabricatorFeedStoryAggregate.php', 'PhabricatorFeedStoryAudit' => 'applications/feed/story/PhabricatorFeedStoryAudit.php', 'PhabricatorFeedStoryCommit' => 'applications/feed/story/PhabricatorFeedStoryCommit.php', 'PhabricatorFeedStoryData' => 'applications/feed/storage/PhabricatorFeedStoryData.php', 'PhabricatorFeedStoryDifferential' => 'applications/feed/story/PhabricatorFeedStoryDifferential.php', 'PhabricatorFeedStoryDifferentialAggregate' => 'applications/feed/story/PhabricatorFeedStoryDifferentialAggregate.php', 'PhabricatorFeedStoryManiphest' => 'applications/feed/story/PhabricatorFeedStoryManiphest.php', 'PhabricatorFeedStoryManiphestAggregate' => 'applications/feed/story/PhabricatorFeedStoryManiphestAggregate.php', 'PhabricatorFeedStoryNotification' => 'applications/notification/storage/PhabricatorFeedStoryNotification.php', 'PhabricatorFeedStoryPhriction' => 'applications/feed/story/PhabricatorFeedStoryPhriction.php', 'PhabricatorFeedStoryProject' => 'applications/feed/story/PhabricatorFeedStoryProject.php', 'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php', 'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php', 'PhabricatorFeedStoryStatus' => 'applications/feed/story/PhabricatorFeedStoryStatus.php', 'PhabricatorFeedStoryTypeConstants' => 'applications/feed/constants/PhabricatorFeedStoryTypeConstants.php', 'PhabricatorFeedStoryView' => 'applications/feed/view/PhabricatorFeedStoryView.php', 'PhabricatorFeedView' => 'applications/feed/view/PhabricatorFeedView.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFileController' => 'applications/files/controller/PhabricatorFileController.php', 'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php', 'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php', 'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php', 'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php', 'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php', 'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php', 'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php', 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', 'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php', 'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php', 'PhabricatorFileShortcutController' => 'applications/files/controller/PhabricatorFileShortcutController.php', 'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php', 'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php', 'PhabricatorFileStorageEngine' => 'applications/files/engine/PhabricatorFileStorageEngine.php', 'PhabricatorFileStorageEngineSelector' => 'applications/files/engineselector/PhabricatorFileStorageEngineSelector.php', 'PhabricatorFileTestCase' => 'applications/files/storage/__tests__/PhabricatorFileTestCase.php', 'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php', 'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php', 'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php', 'PhabricatorFilesConfigOptions' => 'applications/files/config/PhabricatorFilesConfigOptions.php', 'PhabricatorFilesManagementEnginesWorkflow' => 'applications/files/management/PhabricatorFilesManagementEnginesWorkflow.php', 'PhabricatorFilesManagementMetadataWorkflow' => 'applications/files/management/PhabricatorFilesManagementMetadataWorkflow.php', 'PhabricatorFilesManagementMigrateWorkflow' => 'applications/files/management/PhabricatorFilesManagementMigrateWorkflow.php', 'PhabricatorFilesManagementWorkflow' => 'applications/files/management/PhabricatorFilesManagementWorkflow.php', 'PhabricatorFlag' => 'applications/flag/storage/PhabricatorFlag.php', 'PhabricatorFlagColor' => 'applications/flag/constants/PhabricatorFlagColor.php', 'PhabricatorFlagConstants' => 'applications/flag/constants/PhabricatorFlagConstants.php', 'PhabricatorFlagController' => 'applications/flag/controller/PhabricatorFlagController.php', 'PhabricatorFlagDAO' => 'applications/flag/storage/PhabricatorFlagDAO.php', 'PhabricatorFlagDeleteController' => 'applications/flag/controller/PhabricatorFlagDeleteController.php', 'PhabricatorFlagEditController' => 'applications/flag/controller/PhabricatorFlagEditController.php', 'PhabricatorFlagListController' => 'applications/flag/controller/PhabricatorFlagListController.php', 'PhabricatorFlagListView' => 'applications/flag/view/PhabricatorFlagListView.php', 'PhabricatorFlagQuery' => 'applications/flag/query/PhabricatorFlagQuery.php', 'PhabricatorFlagsUIEventListener' => 'applications/flag/events/PhabricatorFlagsUIEventListener.php', 'PhabricatorFormExample' => 'applications/uiexample/examples/PhabricatorFormExample.php', 'PhabricatorGarbageCollectorConfigOptions' => 'applications/config/option/PhabricatorGarbageCollectorConfigOptions.php', 'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/PhabricatorGarbageCollectorDaemon.php', 'PhabricatorGestureExample' => 'applications/uiexample/examples/PhabricatorGestureExample.php', 'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php', 'PhabricatorGitHubConfigOptions' => 'applications/config/option/PhabricatorGitHubConfigOptions.php', 'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php', 'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php', 'PhabricatorGoogleConfigOptions' => 'applications/config/option/PhabricatorGoogleConfigOptions.php', 'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php', 'PhabricatorHash' => 'infrastructure/util/PhabricatorHash.php', 'PhabricatorHashTestCase' => 'infrastructure/util/__tests__/PhabricatorHashTestCase.php', 'PhabricatorHeaderView' => 'view/layout/PhabricatorHeaderView.php', 'PhabricatorHelpController' => 'applications/help/controller/PhabricatorHelpController.php', 'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php', 'PhabricatorIRCBot' => 'infrastructure/daemon/bot/PhabricatorIRCBot.php', 'PhabricatorIRCProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php', 'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/bot/handler/PhabricatorIRCProtocolHandler.php', 'PhabricatorImageTransformer' => 'applications/files/PhabricatorImageTransformer.php', 'PhabricatorInfrastructureTestCase' => 'infrastructure/__tests__/PhabricatorInfrastructureTestCase.php', 'PhabricatorInlineCommentController' => 'infrastructure/diff/PhabricatorInlineCommentController.php', 'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/PhabricatorInlineCommentInterface.php', 'PhabricatorInlineCommentPreviewController' => 'infrastructure/diff/PhabricatorInlineCommentPreviewController.php', 'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', 'PhabricatorLDAPConfigOptions' => 'applications/config/option/PhabricatorLDAPConfigOptions.php', 'PhabricatorLDAPLoginController' => 'applications/auth/controller/PhabricatorLDAPLoginController.php', 'PhabricatorLDAPProvider' => 'applications/auth/ldap/PhabricatorLDAPProvider.php', 'PhabricatorLDAPRegistrationController' => 'applications/auth/controller/PhabricatorLDAPRegistrationController.php', 'PhabricatorLDAPUnknownUserException' => 'applications/auth/ldap/PhabricatorLDAPUnknownUserException.php', 'PhabricatorLDAPUnlinkController' => 'applications/auth/controller/PhabricatorLDAPUnlinkController.php', 'PhabricatorLintEngine' => 'infrastructure/lint/PhabricatorLintEngine.php', 'PhabricatorLiskDAO' => 'infrastructure/storage/lisk/PhabricatorLiskDAO.php', 'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php', 'PhabricatorLocalTimeTestCase' => 'view/__tests__/PhabricatorLocalTimeTestCase.php', 'PhabricatorLoginController' => 'applications/auth/controller/PhabricatorLoginController.php', 'PhabricatorLoginValidateController' => 'applications/auth/controller/PhabricatorLoginValidateController.php', 'PhabricatorLogoutController' => 'applications/auth/controller/PhabricatorLogoutController.php', 'PhabricatorMacroCommentController' => 'applications/macro/controller/PhabricatorMacroCommentController.php', 'PhabricatorMacroConfigOptions' => 'applications/macro/config/PhabricatorMacroConfigOptions.php', 'PhabricatorMacroController' => 'applications/macro/controller/PhabricatorMacroController.php', 'PhabricatorMacroDisableController' => 'applications/macro/controller/PhabricatorMacroDisableController.php', 'PhabricatorMacroEditController' => 'applications/macro/controller/PhabricatorMacroEditController.php', 'PhabricatorMacroEditor' => 'applications/macro/editor/PhabricatorMacroEditor.php', 'PhabricatorMacroListController' => 'applications/macro/controller/PhabricatorMacroListController.php', 'PhabricatorMacroMemeController' => 'applications/macro/controller/PhabricatorMacroMemeController.php', 'PhabricatorMacroMemeDialogController' => 'applications/macro/controller/PhabricatorMacroMemeDialogController.php', 'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php', 'PhabricatorMacroTransaction' => 'applications/macro/storage/PhabricatorMacroTransaction.php', 'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php', 'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php', 'PhabricatorMacroTransactionType' => 'applications/macro/constants/PhabricatorMacroTransactionType.php', 'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php', 'PhabricatorMail' => 'applications/metamta/PhabricatorMail.php', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php', 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php', 'PhabricatorMailImplementationPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php', 'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php', 'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php', 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php', 'PhabricatorMailingListsController' => 'applications/mailinglists/controller/PhabricatorMailingListsController.php', 'PhabricatorMailingListsEditController' => 'applications/mailinglists/controller/PhabricatorMailingListsEditController.php', 'PhabricatorMailingListsListController' => 'applications/mailinglists/controller/PhabricatorMailingListsListController.php', 'PhabricatorMainMenuGroupView' => 'view/page/menu/PhabricatorMainMenuGroupView.php', 'PhabricatorMainMenuIconView' => 'view/page/menu/PhabricatorMainMenuIconView.php', 'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php', 'PhabricatorMainMenuView' => 'view/page/menu/PhabricatorMainMenuView.php', 'PhabricatorManiphestConfigOptions' => 'applications/maniphest/config/PhabricatorManiphestConfigOptions.php', 'PhabricatorMarkupCache' => 'applications/cache/storage/PhabricatorMarkupCache.php', 'PhabricatorMarkupEngine' => 'infrastructure/markup/PhabricatorMarkupEngine.php', 'PhabricatorMarkupInterface' => 'infrastructure/markup/PhabricatorMarkupInterface.php', 'PhabricatorMenuItemView' => 'view/layout/PhabricatorMenuItemView.php', 'PhabricatorMenuView' => 'view/layout/PhabricatorMenuView.php', 'PhabricatorMenuViewTestCase' => 'view/layout/__tests__/PhabricatorMenuViewTestCase.php', 'PhabricatorMercurialGraphStream' => 'applications/repository/daemon/PhabricatorMercurialGraphStream.php', 'PhabricatorMetaMTAAttachment' => 'applications/metamta/storage/PhabricatorMetaMTAAttachment.php', 'PhabricatorMetaMTAConfigOptions' => 'applications/config/option/PhabricatorMetaMTAConfigOptions.php', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/PhabricatorMetaMTAController.php', 'PhabricatorMetaMTADAO' => 'applications/metamta/storage/PhabricatorMetaMTADAO.php', 'PhabricatorMetaMTAEmailBodyParser' => 'applications/metamta/PhabricatorMetaMTAEmailBodyParser.php', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'applications/metamta/__tests__/PhabricatorMetaMTAEmailBodyParserTestCase.php', 'PhabricatorMetaMTAListController' => 'applications/metamta/controller/PhabricatorMetaMTAListController.php', 'PhabricatorMetaMTAMail' => 'applications/metamta/storage/PhabricatorMetaMTAMail.php', 'PhabricatorMetaMTAMailBody' => 'applications/metamta/view/PhabricatorMetaMTAMailBody.php', 'PhabricatorMetaMTAMailBodyTestCase' => 'applications/metamta/view/__tests__/PhabricatorMetaMTAMailBodyTestCase.php', 'PhabricatorMetaMTAMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php', 'PhabricatorMetaMTAMailingList' => 'applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php', 'PhabricatorMetaMTAReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAReceiveController.php', 'PhabricatorMetaMTAReceivedListController' => 'applications/metamta/controller/PhabricatorMetaMTAReceivedListController.php', 'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php', 'PhabricatorMetaMTASendController' => 'applications/metamta/controller/PhabricatorMetaMTASendController.php', 'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php', 'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/PhabricatorMetaMTAViewController.php', 'PhabricatorMetaMTAWorker' => 'applications/metamta/PhabricatorMetaMTAWorker.php', 'PhabricatorMustVerifyEmailController' => 'applications/auth/controller/PhabricatorMustVerifyEmailController.php', 'PhabricatorMySQLConfigOptions' => 'applications/config/option/PhabricatorMySQLConfigOptions.php', 'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php', 'PhabricatorNoteExample' => 'applications/uiexample/examples/PhabricatorNoteExample.php', 'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php', 'PhabricatorNotificationClearController' => 'applications/notification/controller/PhabricatorNotificationClearController.php', 'PhabricatorNotificationConfigOptions' => 'applications/config/option/PhabricatorNotificationConfigOptions.php', 'PhabricatorNotificationController' => 'applications/notification/controller/PhabricatorNotificationController.php', 'PhabricatorNotificationIndividualController' => 'applications/notification/controller/PhabricatorNotificationIndividualController.php', 'PhabricatorNotificationListController' => 'applications/notification/controller/PhabricatorNotificationListController.php', 'PhabricatorNotificationPanelController' => 'applications/notification/controller/PhabricatorNotificationPanelController.php', 'PhabricatorNotificationQuery' => 'applications/notification/PhabricatorNotificationQuery.php', 'PhabricatorNotificationStatusController' => 'applications/notification/controller/PhabricatorNotificationStatusController.php', 'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php', 'PhabricatorOAuthClientAuthorizationBaseController' => 'applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationBaseController.php', 'PhabricatorOAuthClientAuthorizationDeleteController' => 'applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationDeleteController.php', 'PhabricatorOAuthClientAuthorizationEditController' => 'applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationEditController.php', 'PhabricatorOAuthClientAuthorizationListController' => 'applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationListController.php', 'PhabricatorOAuthClientAuthorizationQuery' => 'applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php', 'PhabricatorOAuthClientBaseController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientBaseController.php', 'PhabricatorOAuthClientDeleteController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php', 'PhabricatorOAuthClientEditController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientEditController.php', 'PhabricatorOAuthClientListController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientListController.php', 'PhabricatorOAuthClientViewController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientViewController.php', 'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/PhabricatorOAuthDefaultRegistrationController.php', 'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/PhabricatorOAuthDiagnosticsController.php', 'PhabricatorOAuthFailureView' => 'applications/auth/view/PhabricatorOAuthFailureView.php', 'PhabricatorOAuthLoginController' => 'applications/auth/controller/PhabricatorOAuthLoginController.php', 'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/PhabricatorOAuthProvider.php', 'PhabricatorOAuthProviderDisqus' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderDisqus.php', 'PhabricatorOAuthProviderException' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderException.php', 'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderFacebook.php', 'PhabricatorOAuthProviderGitHub' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderGitHub.php', 'PhabricatorOAuthProviderGoogle' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderGoogle.php', 'PhabricatorOAuthProviderPhabricator' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderPhabricator.php', 'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/PhabricatorOAuthRegistrationController.php', 'PhabricatorOAuthResponse' => 'applications/oauthserver/PhabricatorOAuthResponse.php', 'PhabricatorOAuthServer' => 'applications/oauthserver/PhabricatorOAuthServer.php', 'PhabricatorOAuthServerAccessToken' => 'applications/oauthserver/storage/PhabricatorOAuthServerAccessToken.php', 'PhabricatorOAuthServerAuthController' => 'applications/oauthserver/controller/PhabricatorOAuthServerAuthController.php', 'PhabricatorOAuthServerAuthorizationCode' => 'applications/oauthserver/storage/PhabricatorOAuthServerAuthorizationCode.php', 'PhabricatorOAuthServerClient' => 'applications/oauthserver/storage/PhabricatorOAuthServerClient.php', 'PhabricatorOAuthServerClientQuery' => 'applications/oauthserver/query/PhabricatorOAuthServerClientQuery.php', 'PhabricatorOAuthServerController' => 'applications/oauthserver/controller/PhabricatorOAuthServerController.php', 'PhabricatorOAuthServerDAO' => 'applications/oauthserver/storage/PhabricatorOAuthServerDAO.php', 'PhabricatorOAuthServerScope' => 'applications/oauthserver/PhabricatorOAuthServerScope.php', 'PhabricatorOAuthServerTestCase' => 'applications/oauthserver/__tests__/PhabricatorOAuthServerTestCase.php', 'PhabricatorOAuthServerTestController' => 'applications/oauthserver/controller/PhabricatorOAuthServerTestController.php', 'PhabricatorOAuthServerTokenController' => 'applications/oauthserver/controller/PhabricatorOAuthServerTokenController.php', 'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/PhabricatorOAuthUnlinkController.php', 'PhabricatorObjectHandle' => 'applications/phid/PhabricatorObjectHandle.php', 'PhabricatorObjectHandleConstants' => 'applications/phid/handle/const/PhabricatorObjectHandleConstants.php', 'PhabricatorObjectHandleData' => 'applications/phid/handle/PhabricatorObjectHandleData.php', 'PhabricatorObjectHandleStatus' => 'applications/phid/handle/const/PhabricatorObjectHandleStatus.php', 'PhabricatorObjectItemListExample' => 'applications/uiexample/examples/PhabricatorObjectItemListExample.php', 'PhabricatorObjectItemListView' => 'view/layout/PhabricatorObjectItemListView.php', 'PhabricatorObjectItemView' => 'view/layout/PhabricatorObjectItemView.php', 'PhabricatorObjectListView' => 'view/control/PhabricatorObjectListView.php', 'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php', 'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php', 'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php', 'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php', 'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php', 'PhabricatorOwnersDAO' => 'applications/owners/storage/PhabricatorOwnersDAO.php', 'PhabricatorOwnersDeleteController' => 'applications/owners/controller/PhabricatorOwnersDeleteController.php', 'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php', 'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php', 'PhabricatorOwnersListController' => 'applications/owners/controller/PhabricatorOwnersListController.php', 'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php', 'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php', 'PhabricatorOwnersPackagePathValidator' => 'applications/repository/worker/commitchangeparser/PhabricatorOwnersPackagePathValidator.php', 'PhabricatorOwnersPackageQuery' => 'applications/owners/query/PhabricatorOwnersPackageQuery.php', 'PhabricatorOwnersPackageTestCase' => 'applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php', 'PhabricatorOwnersPath' => 'applications/owners/storage/PhabricatorOwnersPath.php', 'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php', 'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php', 'PhabricatorPHIDConfigOptions' => 'applications/phid/config/PhabricatorPHIDConfigOptions.php', 'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php', 'PhabricatorPHIDController' => 'applications/phid/controller/PhabricatorPHIDController.php', 'PhabricatorPHIDLookupController' => 'applications/phid/controller/PhabricatorPHIDLookupController.php', 'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php', 'PhabricatorPaste' => 'applications/paste/storage/PhabricatorPaste.php', 'PhabricatorPasteController' => 'applications/paste/controller/PhabricatorPasteController.php', 'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php', 'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php', 'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php', 'PhabricatorPasteQuery' => 'applications/paste/query/PhabricatorPasteQuery.php', 'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php', 'PhabricatorPasteViewController' => 'applications/paste/controller/PhabricatorPasteViewController.php', 'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php', 'PhabricatorPeopleEditController' => 'applications/people/controller/PhabricatorPeopleEditController.php', 'PhabricatorPeopleLdapController' => 'applications/people/controller/PhabricatorPeopleLdapController.php', 'PhabricatorPeopleListController' => 'applications/people/controller/PhabricatorPeopleListController.php', 'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php', 'PhabricatorPeopleProfileController' => 'applications/people/controller/PhabricatorPeopleProfileController.php', 'PhabricatorPeopleQuery' => 'applications/people/PhabricatorPeopleQuery.php', 'PhabricatorPhabricatorOAuthConfigOptions' => 'applications/config/option/PhabricatorPhabricatorOAuthConfigOptions.php', 'PhabricatorPhameConfigOptions' => 'applications/phame/config/PhabricatorPhameConfigOptions.php', 'PhabricatorPholioConfigOptions' => 'applications/pholio/config/PhabricatorPholioConfigOptions.php', 'PhabricatorPhrictionConfigOptions' => 'applications/phriction/config/PhabricatorPhrictionConfigOptions.php', 'PhabricatorPinboardItemView' => 'view/layout/PhabricatorPinboardItemView.php', 'PhabricatorPinboardView' => 'view/layout/PhabricatorPinboardView.php', 'PhabricatorPolicies' => 'applications/policy/constants/PhabricatorPolicies.php', 'PhabricatorPolicy' => 'applications/policy/filter/PhabricatorPolicy.php', 'PhabricatorPolicyAwareQuery' => 'infrastructure/query/policy/PhabricatorPolicyAwareQuery.php', 'PhabricatorPolicyAwareTestQuery' => 'applications/policy/__tests__/PhabricatorPolicyAwareTestQuery.php', 'PhabricatorPolicyCapability' => 'applications/policy/constants/PhabricatorPolicyCapability.php', 'PhabricatorPolicyConfigOptions' => 'applications/config/option/PhabricatorPolicyConfigOptions.php', 'PhabricatorPolicyConstants' => 'applications/policy/constants/PhabricatorPolicyConstants.php', 'PhabricatorPolicyException' => 'applications/policy/exception/PhabricatorPolicyException.php', 'PhabricatorPolicyFilter' => 'applications/policy/filter/PhabricatorPolicyFilter.php', 'PhabricatorPolicyInterface' => 'applications/policy/interface/PhabricatorPolicyInterface.php', 'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php', 'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php', 'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php', 'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php', 'PhabricatorProfileHeaderView' => 'view/layout/PhabricatorProfileHeaderView.php', 'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php', 'PhabricatorProjectConstants' => 'applications/project/constants/PhabricatorProjectConstants.php', 'PhabricatorProjectController' => 'applications/project/controller/PhabricatorProjectController.php', 'PhabricatorProjectCreateController' => 'applications/project/controller/PhabricatorProjectCreateController.php', 'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php', 'PhabricatorProjectEditor' => 'applications/project/editor/PhabricatorProjectEditor.php', 'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php', 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', 'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php', 'PhabricatorProjectNameCollisionException' => 'applications/project/exception/PhabricatorProjectNameCollisionException.php', 'PhabricatorProjectProfile' => 'applications/project/storage/PhabricatorProjectProfile.php', 'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php', 'PhabricatorProjectProfileEditController' => 'applications/project/controller/PhabricatorProjectProfileEditController.php', 'PhabricatorProjectQuery' => 'applications/project/query/PhabricatorProjectQuery.php', 'PhabricatorProjectStatus' => 'applications/project/constants/PhabricatorProjectStatus.php', 'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php', 'PhabricatorProjectTransactionType' => 'applications/project/constants/PhabricatorProjectTransactionType.php', 'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php', 'PhabricatorPropertyListExample' => 'applications/uiexample/examples/PhabricatorPropertyListExample.php', 'PhabricatorPropertyListView' => 'view/layout/PhabricatorPropertyListView.php', 'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php', 'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php', 'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php', 'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php', 'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php', 'PhabricatorRemarkupRuleEmbedFile' => 'applications/files/remarkup/PhabricatorRemarkupRuleEmbedFile.php', 'PhabricatorRemarkupRuleImageMacro' => 'applications/macro/remarkup/PhabricatorRemarkupRuleImageMacro.php', 'PhabricatorRemarkupRuleMeme' => 'applications/macro/remarkup/PhabricatorRemarkupRuleMeme.php', 'PhabricatorRemarkupRuleMention' => 'applications/people/remarkup/PhabricatorRemarkupRuleMention.php', 'PhabricatorRemarkupRuleObject' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObject.php', 'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php', 'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php', 'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/PhabricatorRepositoryArcanistProject.php', 'PhabricatorRepositoryArcanistProjectDeleteController' => 'applications/repository/controller/PhabricatorRepositoryArcanistProjectDeleteController.php', 'PhabricatorRepositoryArcanistProjectEditController' => 'applications/repository/controller/PhabricatorRepositoryArcanistProjectEditController.php', 'PhabricatorRepositoryAuditRequest' => 'applications/repository/storage/PhabricatorRepositoryAuditRequest.php', 'PhabricatorRepositoryBranch' => 'applications/repository/storage/PhabricatorRepositoryBranch.php', 'PhabricatorRepositoryCommit' => 'applications/repository/storage/PhabricatorRepositoryCommit.php', 'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php', 'PhabricatorRepositoryCommitData' => 'applications/repository/storage/PhabricatorRepositoryCommitData.php', 'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php', 'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php', 'PhabricatorRepositoryCommitOwnersWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php', 'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php', 'PhabricatorRepositoryCommitSearchIndexer' => 'applications/repository/search/PhabricatorRepositoryCommitSearchIndexer.php', 'PhabricatorRepositoryConfigOptions' => 'applications/repository/PhabricatorRepositoryConfigOptions.php', 'PhabricatorRepositoryController' => 'applications/repository/controller/PhabricatorRepositoryController.php', 'PhabricatorRepositoryCreateController' => 'applications/repository/controller/PhabricatorRepositoryCreateController.php', 'PhabricatorRepositoryDAO' => 'applications/repository/storage/PhabricatorRepositoryDAO.php', 'PhabricatorRepositoryDeleteController' => 'applications/repository/controller/PhabricatorRepositoryDeleteController.php', 'PhabricatorRepositoryEditController' => 'applications/repository/controller/PhabricatorRepositoryEditController.php', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryGitCommitChangeParserWorker.php', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryGitCommitMessageParserWorker.php', 'PhabricatorRepositoryListController' => 'applications/repository/controller/PhabricatorRepositoryListController.php', 'PhabricatorRepositoryManagementDeleteWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDeleteWorkflow.php', 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php', 'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php', 'PhabricatorRepositoryManagementPullWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php', 'PhabricatorRepositoryManagementWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementWorkflow.php', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryMercurialCommitChangeParserWorker.php', 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryMercurialCommitMessageParserWorker.php', 'PhabricatorRepositoryPullLocalDaemon' => 'applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php', 'PhabricatorRepositoryPullLocalDaemonTestCase' => 'applications/repository/daemon/__tests__/PhabricatorRepositoryPullLocalDaemonTestCase.php', 'PhabricatorRepositoryQuery' => 'applications/repository/query/PhabricatorRepositoryQuery.php', 'PhabricatorRepositoryShortcut' => 'applications/repository/storage/PhabricatorRepositoryShortcut.php', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositorySvnCommitChangeParserWorker.php', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositorySvnCommitMessageParserWorker.php', 'PhabricatorRepositorySymbol' => 'applications/repository/storage/PhabricatorRepositorySymbol.php', 'PhabricatorRepositoryTestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php', 'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php', 'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php', 'PhabricatorSQLPatchList' => 'infrastructure/storage/patch/PhabricatorSQLPatchList.php', 'PhabricatorSSHWorkflow' => 'infrastructure/ssh/PhabricatorSSHWorkflow.php', 'PhabricatorScopedEnv' => 'infrastructure/env/PhabricatorScopedEnv.php', 'PhabricatorSearchAbstractDocument' => 'applications/search/index/PhabricatorSearchAbstractDocument.php', 'PhabricatorSearchAttachController' => 'applications/search/controller/PhabricatorSearchAttachController.php', 'PhabricatorSearchBaseController' => 'applications/search/controller/PhabricatorSearchBaseController.php', 'PhabricatorSearchConfigOptions' => 'applications/search/config/PhabricatorSearchConfigOptions.php', 'PhabricatorSearchController' => 'applications/search/controller/PhabricatorSearchController.php', 'PhabricatorSearchDAO' => 'applications/search/storage/PhabricatorSearchDAO.php', 'PhabricatorSearchDocument' => 'applications/search/storage/document/PhabricatorSearchDocument.php', 'PhabricatorSearchDocumentField' => 'applications/search/storage/document/PhabricatorSearchDocumentField.php', 'PhabricatorSearchDocumentIndexer' => 'applications/search/index/PhabricatorSearchDocumentIndexer.php', 'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/PhabricatorSearchDocumentRelationship.php', 'PhabricatorSearchEngine' => 'applications/search/engine/PhabricatorSearchEngine.php', 'PhabricatorSearchEngineElastic' => 'applications/search/engine/PhabricatorSearchEngineElastic.php', 'PhabricatorSearchEngineMySQL' => 'applications/search/engine/PhabricatorSearchEngineMySQL.php', 'PhabricatorSearchEngineSelector' => 'applications/search/selector/PhabricatorSearchEngineSelector.php', 'PhabricatorSearchField' => 'applications/search/constants/PhabricatorSearchField.php', 'PhabricatorSearchIndexer' => 'applications/search/index/PhabricatorSearchIndexer.php', 'PhabricatorSearchManagementIndexWorkflow' => 'applications/search/management/PhabricatorSearchManagementIndexWorkflow.php', 'PhabricatorSearchManagementWorkflow' => 'applications/search/management/PhabricatorSearchManagementWorkflow.php', 'PhabricatorSearchQuery' => 'applications/search/storage/PhabricatorSearchQuery.php', 'PhabricatorSearchRelationship' => 'applications/search/constants/PhabricatorSearchRelationship.php', 'PhabricatorSearchResultView' => 'applications/search/view/PhabricatorSearchResultView.php', 'PhabricatorSearchScope' => 'applications/search/constants/PhabricatorSearchScope.php', 'PhabricatorSearchSelectController' => 'applications/search/controller/PhabricatorSearchSelectController.php', 'PhabricatorSecurityConfigOptions' => 'applications/config/option/PhabricatorSecurityConfigOptions.php', 'PhabricatorSendGridConfigOptions' => 'applications/config/option/PhabricatorSendGridConfigOptions.php', 'PhabricatorSettingsAdjustController' => 'applications/settings/controller/PhabricatorSettingsAdjustController.php', 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 'PhabricatorSettingsPanelAccount' => 'applications/settings/panel/PhabricatorSettingsPanelAccount.php', 'PhabricatorSettingsPanelConduit' => 'applications/settings/panel/PhabricatorSettingsPanelConduit.php', 'PhabricatorSettingsPanelDiffPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDiffPreferences.php', 'PhabricatorSettingsPanelDisplayPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDisplayPreferences.php', 'PhabricatorSettingsPanelEmailAddresses' => 'applications/settings/panel/PhabricatorSettingsPanelEmailAddresses.php', 'PhabricatorSettingsPanelEmailPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelEmailPreferences.php', 'PhabricatorSettingsPanelHomePreferences' => 'applications/settings/panel/PhabricatorSettingsPanelHomePreferences.php', 'PhabricatorSettingsPanelLDAP' => 'applications/settings/panel/PhabricatorSettingsPanelLDAP.php', 'PhabricatorSettingsPanelOAuth' => 'applications/settings/panel/PhabricatorSettingsPanelOAuth.php', 'PhabricatorSettingsPanelPassword' => 'applications/settings/panel/PhabricatorSettingsPanelPassword.php', 'PhabricatorSettingsPanelProfile' => 'applications/settings/panel/PhabricatorSettingsPanelProfile.php', 'PhabricatorSettingsPanelSSHKeys' => 'applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php', 'PhabricatorSettingsPanelSearchPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelSearchPreferences.php', 'PhabricatorSetupCheck' => 'applications/config/check/PhabricatorSetupCheck.php', 'PhabricatorSetupCheckAPC' => 'applications/config/check/PhabricatorSetupCheckAPC.php', 'PhabricatorSetupCheckBaseURI' => 'applications/config/check/PhabricatorSetupCheckBaseURI.php', 'PhabricatorSetupCheckDatabase' => 'applications/config/check/PhabricatorSetupCheckDatabase.php', 'PhabricatorSetupCheckExtensions' => 'applications/config/check/PhabricatorSetupCheckExtensions.php', 'PhabricatorSetupCheckExtraConfig' => 'applications/config/check/PhabricatorSetupCheckExtraConfig.php', 'PhabricatorSetupCheckFacebook' => 'applications/config/check/PhabricatorSetupCheckFacebook.php', 'PhabricatorSetupCheckGD' => 'applications/config/check/PhabricatorSetupCheckGD.php', 'PhabricatorSetupCheckImagemagick' => 'applications/config/check/PhabricatorSetupCheckImagemagick.php', 'PhabricatorSetupCheckInvalidConfig' => 'applications/config/check/PhabricatorSetupCheckInvalidConfig.php', 'PhabricatorSetupCheckMail' => 'applications/config/check/PhabricatorSetupCheckMail.php', 'PhabricatorSetupCheckMySQL' => 'applications/config/check/PhabricatorSetupCheckMySQL.php', 'PhabricatorSetupCheckPHPConfig' => 'applications/config/check/PhabricatorSetupCheckPHPConfig.php', 'PhabricatorSetupCheckPath' => 'applications/config/check/PhabricatorSetupCheckPath.php', 'PhabricatorSetupCheckPygment' => 'applications/config/check/PhabricatorSetupCheckPygment.php', 'PhabricatorSetupCheckStorage' => 'applications/config/check/PhabricatorSetupCheckStorage.php', 'PhabricatorSetupCheckTimezone' => 'applications/config/check/PhabricatorSetupCheckTimezone.php', 'PhabricatorSetupIssue' => 'applications/config/issue/PhabricatorSetupIssue.php', 'PhabricatorSetupIssueExample' => 'applications/uiexample/examples/PhabricatorSetupIssueExample.php', 'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php', 'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/PhabricatorSlowvoteChoice.php', 'PhabricatorSlowvoteComment' => 'applications/slowvote/storage/PhabricatorSlowvoteComment.php', 'PhabricatorSlowvoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteController.php', 'PhabricatorSlowvoteCreateController' => 'applications/slowvote/controller/PhabricatorSlowvoteCreateController.php', 'PhabricatorSlowvoteDAO' => 'applications/slowvote/storage/PhabricatorSlowvoteDAO.php', 'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/PhabricatorSlowvoteListController.php', 'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/PhabricatorSlowvoteOption.php', 'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/PhabricatorSlowvotePoll.php', 'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/PhabricatorSlowvotePollController.php', 'PhabricatorSlug' => 'infrastructure/util/PhabricatorSlug.php', 'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php', 'PhabricatorSortTableExample' => 'applications/uiexample/examples/PhabricatorSortTableExample.php', 'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php', 'PhabricatorStandardPageView' => 'view/page/PhabricatorStandardPageView.php', 'PhabricatorStatusController' => 'applications/system/PhabricatorStatusController.php', 'PhabricatorStorageFixtureScopeGuard' => 'infrastructure/testing/fixture/PhabricatorStorageFixtureScopeGuard.php', 'PhabricatorStorageManagementAPI' => 'infrastructure/storage/management/PhabricatorStorageManagementAPI.php', 'PhabricatorStorageManagementDatabasesWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDatabasesWorkflow.php', 'PhabricatorStorageManagementDestroyWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php', 'PhabricatorStorageManagementDumpWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php', 'PhabricatorStorageManagementStatusWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementStatusWorkflow.php', 'PhabricatorStorageManagementUpgradeWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php', 'PhabricatorStorageManagementWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php', 'PhabricatorStoragePatch' => 'infrastructure/storage/management/PhabricatorStoragePatch.php', 'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php', 'PhabricatorSubscribersQuery' => 'applications/subscriptions/query/PhabricatorSubscribersQuery.php', 'PhabricatorSubscriptionsEditController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php', 'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php', 'PhabricatorSubscriptionsUIEventListener' => 'applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php', 'PhabricatorSymbolNameLinter' => 'infrastructure/lint/hook/PhabricatorSymbolNameLinter.php', 'PhabricatorSyntaxHighlighter' => 'infrastructure/markup/PhabricatorSyntaxHighlighter.php', 'PhabricatorSyntaxHighlightingConfigOptions' => 'applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php', 'PhabricatorTagExample' => 'applications/uiexample/examples/PhabricatorTagExample.php', 'PhabricatorTagView' => 'view/layout/PhabricatorTagView.php', 'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php', 'PhabricatorTestCase' => 'infrastructure/testing/PhabricatorTestCase.php', 'PhabricatorTestStorageEngine' => 'applications/files/engine/PhabricatorTestStorageEngine.php', 'PhabricatorTestWorker' => 'infrastructure/daemon/workers/__tests__/PhabricatorTestWorker.php', 'PhabricatorTimelineCursor' => 'infrastructure/daemon/timeline/storage/PhabricatorTimelineCursor.php', 'PhabricatorTimelineDAO' => 'infrastructure/daemon/timeline/storage/PhabricatorTimelineDAO.php', 'PhabricatorTimelineEvent' => 'infrastructure/daemon/timeline/storage/PhabricatorTimelineEvent.php', 'PhabricatorTimelineEventData' => 'infrastructure/daemon/timeline/storage/PhabricatorTimelineEventData.php', 'PhabricatorTimelineEventView' => 'view/layout/PhabricatorTimelineEventView.php', 'PhabricatorTimelineExample' => 'applications/uiexample/examples/PhabricatorTimelineExample.php', 'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/PhabricatorTimelineIterator.php', 'PhabricatorTimelineView' => 'view/layout/PhabricatorTimelineView.php', 'PhabricatorTimer' => 'applications/countdown/storage/PhabricatorTimer.php', 'PhabricatorToken' => 'applications/tokens/storage/PhabricatorToken.php', 'PhabricatorTokenController' => 'applications/tokens/controller/PhabricatorTokenController.php', 'PhabricatorTokenCount' => 'applications/tokens/storage/PhabricatorTokenCount.php', 'PhabricatorTokenCountQuery' => 'applications/tokens/query/PhabricatorTokenCountQuery.php', 'PhabricatorTokenDAO' => 'applications/tokens/storage/PhabricatorTokenDAO.php', 'PhabricatorTokenGiveController' => 'applications/tokens/controller/PhabricatorTokenGiveController.php', 'PhabricatorTokenGiven' => 'applications/tokens/storage/PhabricatorTokenGiven.php', 'PhabricatorTokenGivenController' => 'applications/tokens/controller/PhabricatorTokenGivenController.php', 'PhabricatorTokenGivenEditor' => 'applications/tokens/editor/PhabricatorTokenGivenEditor.php', 'PhabricatorTokenGivenFeedStory' => 'applications/tokens/feed/PhabricatorTokenGivenFeedStory.php', 'PhabricatorTokenGivenQuery' => 'applications/tokens/query/PhabricatorTokenGivenQuery.php', 'PhabricatorTokenQuery' => 'applications/tokens/query/PhabricatorTokenQuery.php', 'PhabricatorTokenReceiverInterface' => 'applications/tokens/interface/PhabricatorTokenReceiverInterface.php', 'PhabricatorTokenUIEventListener' => 'applications/tokens/event/PhabricatorTokenUIEventListener.php', 'PhabricatorTransactionView' => 'view/layout/PhabricatorTransactionView.php', 'PhabricatorTransactions' => 'applications/transactions/constants/PhabricatorTransactions.php', 'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php', 'PhabricatorTranslation' => 'infrastructure/internationalization/PhabricatorTranslation.php', 'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php', 'PhabricatorTrivialTestCase' => 'infrastructure/testing/__tests__/PhabricatorTrivialTestCase.php', 'PhabricatorTwoColumnExample' => 'applications/uiexample/examples/PhabricatorTwoColumnExample.php', 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadDatasourceController.php', 'PhabricatorTypeaheadResult' => 'applications/typeahead/storage/PhabricatorTypeaheadResult.php', 'PhabricatorUIExample' => 'applications/uiexample/examples/PhabricatorUIExample.php', 'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/PhabricatorUIExampleRenderController.php', 'PhabricatorUIListFilterExample' => 'applications/uiexample/examples/PhabricatorUIListFilterExample.php', 'PhabricatorUINotificationExample' => 'applications/uiexample/examples/PhabricatorUINotificationExample.php', 'PhabricatorUIPagerExample' => 'applications/uiexample/examples/PhabricatorUIPagerExample.php', 'PhabricatorUITooltipExample' => 'applications/uiexample/examples/PhabricatorUITooltipExample.php', 'PhabricatorUnitsTestCase' => 'view/__tests__/PhabricatorUnitsTestCase.php', 'PhabricatorUser' => 'applications/people/storage/PhabricatorUser.php', 'PhabricatorUserDAO' => 'applications/people/storage/PhabricatorUserDAO.php', 'PhabricatorUserEditor' => 'applications/people/PhabricatorUserEditor.php', 'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php', 'PhabricatorUserLDAPInfo' => 'applications/people/storage/PhabricatorUserLDAPInfo.php', 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', 'PhabricatorUserOAuthInfo' => 'applications/people/storage/PhabricatorUserOAuthInfo.php', 'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php', 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', 'PhabricatorUserSSHKey' => 'applications/settings/storage/PhabricatorUserSSHKey.php', 'PhabricatorUserSearchIndexer' => 'applications/people/search/PhabricatorUserSearchIndexer.php', 'PhabricatorUserStatus' => 'applications/people/storage/PhabricatorUserStatus.php', 'PhabricatorUserStatusInvalidEpochException' => 'applications/people/exception/PhabricatorUserStatusInvalidEpochException.php', 'PhabricatorUserStatusOverlapException' => 'applications/people/exception/PhabricatorUserStatusOverlapException.php', 'PhabricatorUserTestCase' => 'applications/people/storage/__tests__/PhabricatorUserTestCase.php', 'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php', 'PhabricatorWorkerActiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php', 'PhabricatorWorkerArchiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php', 'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerDAO.php', 'PhabricatorWorkerLeaseQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php', 'PhabricatorWorkerPermanentFailureException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerPermanentFailureException.php', 'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php', 'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTaskData.php', 'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/PhabricatorWorkerTaskDetailController.php', 'PhabricatorWorkerTaskUpdateController' => 'applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php', 'PhabricatorWorkerTestCase' => 'infrastructure/daemon/workers/__tests__/PhabricatorWorkerTestCase.php', 'PhabricatorXHPASTViewController' => 'applications/phpast/controller/PhabricatorXHPASTViewController.php', 'PhabricatorXHPASTViewDAO' => 'applications/phpast/storage/PhabricatorXHPASTViewDAO.php', 'PhabricatorXHPASTViewFrameController' => 'applications/phpast/controller/PhabricatorXHPASTViewFrameController.php', 'PhabricatorXHPASTViewFramesetController' => 'applications/phpast/controller/PhabricatorXHPASTViewFramesetController.php', 'PhabricatorXHPASTViewInputController' => 'applications/phpast/controller/PhabricatorXHPASTViewInputController.php', 'PhabricatorXHPASTViewPanelController' => 'applications/phpast/controller/PhabricatorXHPASTViewPanelController.php', 'PhabricatorXHPASTViewParseTree' => 'applications/phpast/storage/PhabricatorXHPASTViewParseTree.php', 'PhabricatorXHPASTViewRunController' => 'applications/phpast/controller/PhabricatorXHPASTViewRunController.php', 'PhabricatorXHPASTViewStreamController' => 'applications/phpast/controller/PhabricatorXHPASTViewStreamController.php', 'PhabricatorXHPASTViewTreeController' => 'applications/phpast/controller/PhabricatorXHPASTViewTreeController.php', 'PhabricatorXHProfController' => 'applications/xhprof/controller/PhabricatorXHProfController.php', 'PhabricatorXHProfDAO' => 'applications/xhprof/storage/PhabricatorXHProfDAO.php', 'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/PhabricatorXHProfProfileController.php', 'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/PhabricatorXHProfProfileSymbolView.php', 'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/PhabricatorXHProfProfileTopLevelView.php', 'PhabricatorXHProfProfileView' => 'applications/xhprof/view/PhabricatorXHProfProfileView.php', 'PhabricatorXHProfSample' => 'applications/xhprof/storage/PhabricatorXHProfSample.php', 'PhabricatorXHProfSampleListController' => 'applications/xhprof/controller/PhabricatorXHProfSampleListController.php', 'PhabricatorXHProfSampleListView' => 'applications/xhprof/view/PhabricatorXHProfSampleListView.php', 'PhameBasicBlogSkin' => 'applications/phame/skins/PhameBasicBlogSkin.php', 'PhameBasicTemplateBlogSkin' => 'applications/phame/skins/PhameBasicTemplateBlogSkin.php', 'PhameBlog' => 'applications/phame/storage/PhameBlog.php', 'PhameBlogDeleteController' => 'applications/phame/controller/blog/PhameBlogDeleteController.php', 'PhameBlogEditController' => 'applications/phame/controller/blog/PhameBlogEditController.php', 'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php', 'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php', 'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php', 'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php', 'PhameBlogSkin' => 'applications/phame/skins/PhameBlogSkin.php', 'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php', 'PhameController' => 'applications/phame/controller/PhameController.php', 'PhameDAO' => 'applications/phame/storage/PhameDAO.php', 'PhamePost' => 'applications/phame/storage/PhamePost.php', 'PhamePostDeleteController' => 'applications/phame/controller/post/PhamePostDeleteController.php', 'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php', 'PhamePostFramedController' => 'applications/phame/controller/post/PhamePostFramedController.php', 'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php', 'PhamePostNewController' => 'applications/phame/controller/post/PhamePostNewController.php', 'PhamePostNotLiveController' => 'applications/phame/controller/post/PhamePostNotLiveController.php', 'PhamePostPreviewController' => 'applications/phame/controller/post/PhamePostPreviewController.php', 'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php', 'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php', 'PhamePostUnpublishController' => 'applications/phame/controller/post/PhamePostUnpublishController.php', 'PhamePostView' => 'applications/phame/view/PhamePostView.php', 'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php', 'PhameResourceController' => 'applications/phame/controller/PhameResourceController.php', 'PhameSkinSpecification' => 'applications/phame/skins/PhameSkinSpecification.php', 'PholioConstants' => 'applications/pholio/constants/PholioConstants.php', 'PholioController' => 'applications/pholio/controller/PholioController.php', 'PholioDAO' => 'applications/pholio/storage/PholioDAO.php', 'PholioImage' => 'applications/pholio/storage/PholioImage.php', 'PholioInlineCommentEditView' => 'applications/pholio/view/PholioInlineCommentEditView.php', 'PholioInlineCommentSaveView' => 'applications/pholio/view/PholioInlineCommentSaveView.php', 'PholioInlineCommentView' => 'applications/pholio/view/PholioInlineCommentView.php', 'PholioInlineController' => 'applications/pholio/controller/PholioInlineController.php', 'PholioInlineDeleteController' => 'applications/pholio/controller/PholioInlineDeleteController.php', 'PholioInlineEditController' => 'applications/pholio/controller/PholioInlineEditController.php', 'PholioInlineSaveController' => 'applications/pholio/controller/PholioInlineSaveController.php', 'PholioInlineViewController' => 'applications/pholio/controller/PholioInlineViewController.php', 'PholioMock' => 'applications/pholio/storage/PholioMock.php', 'PholioMockCommentController' => 'applications/pholio/controller/PholioMockCommentController.php', 'PholioMockEditController' => 'applications/pholio/controller/PholioMockEditController.php', 'PholioMockEditor' => 'applications/pholio/editor/PholioMockEditor.php', 'PholioMockEmbedView' => 'applications/pholio/view/PholioMockEmbedView.php', 'PholioMockImagesView' => 'applications/pholio/view/PholioMockImagesView.php', 'PholioMockListController' => 'applications/pholio/controller/PholioMockListController.php', 'PholioMockQuery' => 'applications/pholio/query/PholioMockQuery.php', 'PholioMockViewController' => 'applications/pholio/controller/PholioMockViewController.php', 'PholioRemarkupRule' => 'applications/pholio/remarkup/PholioRemarkupRule.php', 'PholioReplyHandler' => 'applications/pholio/mail/PholioReplyHandler.php', 'PholioSearchIndexer' => 'applications/pholio/search/PholioSearchIndexer.php', 'PholioTransaction' => 'applications/pholio/storage/PholioTransaction.php', 'PholioTransactionComment' => 'applications/pholio/storage/PholioTransactionComment.php', 'PholioTransactionQuery' => 'applications/pholio/query/PholioTransactionQuery.php', 'PholioTransactionType' => 'applications/pholio/constants/PholioTransactionType.php', 'PholioTransactionView' => 'applications/pholio/view/PholioTransactionView.php', 'PhortuneMonthYearExpiryControl' => 'applications/phortune/control/PhortuneMonthYearExpiryControl.php', 'PhortuneStripeBaseController' => 'applications/phortune/stripe/controller/PhortuneStripeBaseController.php', 'PhortuneStripePaymentFormView' => 'applications/phortune/stripe/view/PhortuneStripePaymentFormView.php', 'PhortuneStripeTestPaymentFormController' => 'applications/phortune/stripe/controller/PhortuneStripeTestPaymentFormController.php', 'PhrictionActionConstants' => 'applications/phriction/constants/PhrictionActionConstants.php', 'PhrictionChangeType' => 'applications/phriction/constants/PhrictionChangeType.php', 'PhrictionConstants' => 'applications/phriction/constants/PhrictionConstants.php', 'PhrictionContent' => 'applications/phriction/storage/PhrictionContent.php', 'PhrictionController' => 'applications/phriction/controller/PhrictionController.php', 'PhrictionDAO' => 'applications/phriction/storage/PhrictionDAO.php', 'PhrictionDeleteController' => 'applications/phriction/controller/PhrictionDeleteController.php', 'PhrictionDiffController' => 'applications/phriction/controller/PhrictionDiffController.php', 'PhrictionDocument' => 'applications/phriction/storage/PhrictionDocument.php', 'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php', 'PhrictionDocumentEditor' => 'applications/phriction/editor/PhrictionDocumentEditor.php', 'PhrictionDocumentPreviewController' => 'applications/phriction/controller/PhrictionDocumentPreviewController.php', 'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php', 'PhrictionDocumentStatus' => 'applications/phriction/constants/PhrictionDocumentStatus.php', 'PhrictionDocumentTestCase' => 'applications/phriction/storage/__tests__/PhrictionDocumentTestCase.php', 'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php', 'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php', 'PhrictionListController' => 'applications/phriction/controller/PhrictionListController.php', 'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php', 'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php', 'PhrictionRemarkupRule' => 'applications/phriction/remarkup/PhrictionRemarkupRule.php', 'PhrictionSearchIndexer' => 'applications/phriction/search/PhrictionSearchIndexer.php', 'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php', 'PonderAddCommentView' => 'applications/ponder/view/PonderAddCommentView.php', 'PonderAnswer' => 'applications/ponder/storage/PonderAnswer.php', 'PonderAnswerEditor' => 'applications/ponder/editor/PonderAnswerEditor.php', 'PonderAnswerListView' => 'applications/ponder/view/PonderAnswerListView.php', 'PonderAnswerPreviewController' => 'applications/ponder/controller/PonderAnswerPreviewController.php', 'PonderAnswerQuery' => 'applications/ponder/query/PonderAnswerQuery.php', 'PonderAnswerSaveController' => 'applications/ponder/controller/PonderAnswerSaveController.php', 'PonderAnswerViewController' => 'applications/ponder/controller/PonderAnswerViewController.php', 'PonderAnsweredMail' => 'applications/ponder/mail/PonderAnsweredMail.php', 'PonderComment' => 'applications/ponder/storage/PonderComment.php', 'PonderCommentEditor' => 'applications/ponder/editor/PonderCommentEditor.php', 'PonderCommentListView' => 'applications/ponder/view/PonderCommentListView.php', 'PonderCommentMail' => 'applications/ponder/mail/PonderCommentMail.php', 'PonderCommentQuery' => 'applications/ponder/query/PonderCommentQuery.php', 'PonderCommentSaveController' => 'applications/ponder/controller/PonderCommentSaveController.php', 'PonderConstants' => 'applications/ponder/PonderConstants.php', 'PonderController' => 'applications/ponder/controller/PonderController.php', 'PonderDAO' => 'applications/ponder/storage/PonderDAO.php', 'PonderFeedController' => 'applications/ponder/controller/PonderFeedController.php', 'PonderMail' => 'applications/ponder/mail/PonderMail.php', 'PonderMentionMail' => 'applications/ponder/mail/PonderMentionMail.php', 'PonderPostBodyView' => 'applications/ponder/view/PonderPostBodyView.php', 'PonderQuestion' => 'applications/ponder/storage/PonderQuestion.php', 'PonderQuestionAskController' => 'applications/ponder/controller/PonderQuestionAskController.php', 'PonderQuestionDetailView' => 'applications/ponder/view/PonderQuestionDetailView.php', 'PonderQuestionEditor' => 'applications/ponder/editor/PonderQuestionEditor.php', 'PonderQuestionPreviewController' => 'applications/ponder/controller/PonderQuestionPreviewController.php', 'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php', 'PonderQuestionSummaryView' => 'applications/ponder/view/PonderQuestionSummaryView.php', 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php', 'PonderReplyHandler' => 'applications/ponder/PonderReplyHandler.php', 'PonderSearchIndexer' => 'applications/ponder/search/PonderSearchIndexer.php', 'PonderUserProfileView' => 'applications/ponder/view/PonderUserProfileView.php', 'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php', 'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php', 'PonderVoteEditor' => 'applications/ponder/editor/PonderVoteEditor.php', 'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php', 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', + 'ReleephActiveProjectListView' => 'applications/releeph/view/project/list/ReleephActiveProjectListView.php', + 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', + 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', + 'ReleephBranchAccessController' => 'applications/releeph/controller/branch/ReleephBranchAccessController.php', + 'ReleephBranchBoxView' => 'applications/releeph/view/branch/ReleephBranchBoxView.php', + 'ReleephBranchCommitFieldSpecification' => 'applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php', + 'ReleephBranchCreateController' => 'applications/releeph/controller/branch/ReleephBranchCreateController.php', + 'ReleephBranchEditController' => 'applications/releeph/controller/branch/ReleephBranchEditController.php', + 'ReleephBranchEditor' => 'applications/releeph/editor/ReleephBranchEditor.php', + 'ReleephBranchNamePreviewController' => 'applications/releeph/controller/branch/ReleephBranchNamePreviewController.php', + 'ReleephBranchPreviewView' => 'applications/releeph/view/branch/ReleephBranchPreviewView.php', + 'ReleephBranchTemplate' => 'applications/releeph/view/branch/ReleephBranchTemplate.php', + 'ReleephBranchViewController' => 'applications/releeph/controller/branch/ReleephBranchViewController.php', + 'ReleephCommitFinder' => 'applications/releeph/commitfinder/ReleephCommitFinder.php', + 'ReleephCommitFinderException' => 'applications/releeph/commitfinder/ReleephCommitFinderException.php', + 'ReleephCommitMessageFieldSpecification' => 'applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php', + 'ReleephController' => 'applications/releeph/controller/ReleephController.php', + 'ReleephDAO' => 'applications/releeph/storage/ReleephDAO.php', + 'ReleephDefaultFieldSelector' => 'applications/releeph/field/selector/ReleephDefaultFieldSelector.php', + 'ReleephDefaultUserView' => 'applications/releeph/view/user/ReleephDefaultUserView.php', + 'ReleephDiffChurnFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php', + 'ReleephDiffMessageFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php', + 'ReleephDiffSizeFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php', + 'ReleephDifferentialRevisionDetailRenderer' => 'applications/releeph/differential/ReleephDifferentialRevisionDetailRenderer.php', + 'ReleephEvent' => 'applications/releeph/storage/event/ReleephEvent.php', + 'ReleephFieldParseException' => 'applications/releeph/field/exception/ReleephFieldParseException.php', + 'ReleephFieldSelector' => 'applications/releeph/field/selector/ReleephFieldSelector.php', + 'ReleephFieldSpecification' => 'applications/releeph/field/specification/ReleephFieldSpecification.php', + 'ReleephFieldSpecificationIncompleteException' => 'applications/releeph/field/exception/ReleephFieldSpecificationIncompleteException.php', + 'ReleephInactiveProjectListView' => 'applications/releeph/view/project/list/ReleephInactiveProjectListView.php', + 'ReleephIntentFieldSpecification' => 'applications/releeph/field/specification/ReleephIntentFieldSpecification.php', + 'ReleephLevelFieldSpecification' => 'applications/releeph/field/specification/ReleephLevelFieldSpecification.php', + 'ReleephObjectHandleLoader' => 'applications/releeph/ReleephObjectHandleLoader.php', + 'ReleephOriginalCommitFieldSpecification' => 'applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php', + 'ReleephPHIDConstants' => 'applications/releeph/ReleephPHIDConstants.php', + 'ReleephProject' => 'applications/releeph/storage/ReleephProject.php', + 'ReleephProjectActionController' => 'applications/releeph/controller/project/ReleephProjectActionController.php', + 'ReleephProjectCreateController' => 'applications/releeph/controller/project/ReleephProjectCreateController.php', + 'ReleephProjectEditController' => 'applications/releeph/controller/project/ReleephProjectEditController.php', + 'ReleephProjectListController' => 'applications/releeph/controller/project/ReleephProjectListController.php', + 'ReleephProjectView' => 'applications/releeph/view/ReleephProjectView.php', + 'ReleephProjectViewController' => 'applications/releeph/controller/project/ReleephProjectViewController.php', + 'ReleephReasonFieldSpecification' => 'applications/releeph/field/specification/ReleephReasonFieldSpecification.php', + 'ReleephRequest' => 'applications/releeph/storage/ReleephRequest.php', + 'ReleephRequestActionController' => 'applications/releeph/controller/request/ReleephRequestActionController.php', + 'ReleephRequestCreateController' => 'applications/releeph/controller/request/ReleephRequestCreateController.php', + 'ReleephRequestDifferentialCreateController' => 'applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php', + 'ReleephRequestEditController' => 'applications/releeph/controller/request/ReleephRequestEditController.php', + 'ReleephRequestEditor' => 'applications/releeph/editor/ReleephRequestEditor.php', + 'ReleephRequestEvent' => 'applications/releeph/storage/request/ReleephRequestEvent.php', + 'ReleephRequestEventListView' => 'applications/releeph/view/requestevent/ReleephRequestEventListView.php', + 'ReleephRequestException' => 'applications/releeph/storage/request/exception/ReleephRequestException.php', + 'ReleephRequestHeaderListView' => 'applications/releeph/view/request/header/ReleephRequestHeaderListView.php', + 'ReleephRequestHeaderView' => 'applications/releeph/view/request/header/ReleephRequestHeaderView.php', + 'ReleephRequestIntentsView' => 'applications/releeph/view/request/ReleephRequestIntentsView.php', + 'ReleephRequestMail' => 'applications/releeph/editor/mail/ReleephRequestMail.php', + 'ReleephRequestStatusView' => 'applications/releeph/view/request/ReleephRequestStatusView.php', + 'ReleephRequestTypeaheadControl' => 'applications/releeph/view/request/ReleephRequestTypeaheadControl.php', + 'ReleephRequestTypeaheadController' => 'applications/releeph/controller/request/ReleephRequestTypeaheadController.php', + 'ReleephRequestViewController' => 'applications/releeph/controller/request/ReleephRequestViewController.php', + 'ReleephRequestorFieldSpecification' => 'applications/releeph/field/specification/ReleephRequestorFieldSpecification.php', + 'ReleephRevisionFieldSpecification' => 'applications/releeph/field/specification/ReleephRevisionFieldSpecification.php', + 'ReleephRiskFieldSpecification' => 'applications/releeph/field/specification/ReleephRiskFieldSpecification.php', + 'ReleephSeverityFieldSpecification' => 'applications/releeph/field/specification/ReleephSeverityFieldSpecification.php', + 'ReleephStatusFieldSpecification' => 'applications/releeph/field/specification/ReleephStatusFieldSpecification.php', + 'ReleephSummaryFieldSpecification' => 'applications/releeph/field/specification/ReleephSummaryFieldSpecification.php', + 'ReleephUserView' => 'applications/releeph/view/user/ReleephUserView.php', ), 'function' => array( '_phabricator_date_format' => 'view/viewutils.php', 'celerity_generate_unique_node_id' => 'infrastructure/celerity/api.php', 'celerity_get_resource_uri' => 'infrastructure/celerity/api.php', 'celerity_register_resource_map' => 'infrastructure/celerity/map.php', 'javelin_render_tag' => 'infrastructure/javelin/markup.php', 'javelin_tag' => 'infrastructure/javelin/markup.php', 'phabricator_date' => 'view/viewutils.php', 'phabricator_datetime' => 'view/viewutils.php', 'phabricator_form' => 'infrastructure/javelin/markup.php', 'phabricator_format_bytes' => 'view/viewutils.php', 'phabricator_format_local_time' => 'view/viewutils.php', 'phabricator_format_relative_time' => 'view/viewutils.php', 'phabricator_format_relative_time_detailed' => 'view/viewutils.php', 'phabricator_format_units_generic' => 'view/viewutils.php', 'phabricator_on_relative_date' => 'view/viewutils.php', 'phabricator_parse_bytes' => 'view/viewutils.php', 'phabricator_relative_date' => 'view/viewutils.php', 'phabricator_render_form' => 'infrastructure/javelin/markup.php', 'phabricator_time' => 'view/viewutils.php', 'phid_get_subtype' => 'applications/phid/utils.php', 'phid_get_type' => 'applications/phid/utils.php', 'phid_group_by_type' => 'applications/phid/utils.php', 'require_celerity_resource' => 'infrastructure/celerity/api.php', ), 'xmap' => array( 'Aphront304Response' => 'AphrontResponse', 'Aphront400Response' => 'AphrontResponse', 'Aphront403Response' => 'AphrontHTMLResponse', 'Aphront404Response' => 'AphrontHTMLResponse', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontAttachedFileView' => 'AphrontView', 'AphrontBarView' => 'AphrontView', 'AphrontCSRFException' => 'AphrontException', 'AphrontCalendarEventView' => 'AphrontView', 'AphrontCalendarMonthView' => 'AphrontView', 'AphrontContextBarView' => 'AphrontView', 'AphrontController' => 'Phobject', 'AphrontCursorPagerView' => 'AphrontView', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => 'AphrontView', 'AphrontErrorView' => 'AphrontView', 'AphrontException' => 'Exception', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormCheckboxControl' => 'AphrontFormControl', 'AphrontFormControl' => 'AphrontView', 'AphrontFormCountedToggleButtonsControl' => 'AphrontFormControl', 'AphrontFormCropControl' => 'AphrontFormControl', 'AphrontFormDateControl' => 'AphrontFormControl', 'AphrontFormDividerControl' => 'AphrontFormControl', 'AphrontFormDragAndDropUploadControl' => 'AphrontFormControl', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormImageControl' => 'AphrontFormControl', 'AphrontFormInsetView' => 'AphrontView', 'AphrontFormLayoutView' => 'AphrontView', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormPasswordControl' => 'AphrontFormControl', 'AphrontFormPolicyControl' => 'AphrontFormControl', 'AphrontFormRadioButtonControl' => 'AphrontFormControl', 'AphrontFormRecaptchaControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormToggleButtonsControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontGlyphBarView' => 'AphrontBarView', 'AphrontHTMLResponse' => 'AphrontResponse', 'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink', 'AphrontJSONResponse' => 'AphrontResponse', 'AphrontJavelinView' => 'AphrontView', 'AphrontKeyboardShortcutsAvailableView' => 'AphrontView', 'AphrontListFilterView' => 'AphrontView', 'AphrontMiniPanelView' => 'AphrontView', 'AphrontMoreView' => 'AphrontView', 'AphrontMySQLDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontNoteView' => 'AphrontView', 'AphrontNullView' => 'AphrontView', 'AphrontPHPHTTPSink' => 'AphrontHTTPSink', 'AphrontPageView' => 'AphrontView', 'AphrontPagerView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontPlainTextResponse' => 'AphrontResponse', 'AphrontProgressBarView' => 'AphrontBarView', 'AphrontProxyResponse' => 'AphrontResponse', 'AphrontRedirectException' => 'AphrontException', 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontReloadResponse' => 'AphrontRedirectResponse', 'AphrontRequestFailureView' => 'AphrontView', 'AphrontRequestTestCase' => 'PhabricatorTestCase', 'AphrontSideNavFilterView' => 'AphrontView', 'AphrontTableView' => 'AphrontView', 'AphrontTagView' => 'AphrontView', 'AphrontTokenizerTemplateView' => 'AphrontView', 'AphrontTwoColumnView' => 'AphrontView', 'AphrontTypeaheadTemplateView' => 'AphrontView', 'AphrontUsageException' => 'AphrontException', 'AphrontView' => array( 0 => 'Phobject', 1 => 'PhutilSafeHTMLProducerInterface', ), 'AphrontWebpageResponse' => 'AphrontHTMLResponse', 'AuditPeopleMenuEventListener' => 'PhutilEventListener', 'CelerityPhabricatorResourceController' => 'CelerityResourceController', 'CelerityResourceController' => 'PhabricatorController', 'CelerityResourceGraph' => 'AbstractDirectedGraph', 'CelerityResourceTransformerTestCase' => 'PhabricatorTestCase', 'ConduitAPI_arcanist_Method' => 'ConduitAPIMethod', 'ConduitAPI_arcanist_projectinfo_Method' => 'ConduitAPI_arcanist_Method', 'ConduitAPI_audit_Method' => 'ConduitAPIMethod', 'ConduitAPI_audit_query_Method' => 'ConduitAPI_audit_Method', 'ConduitAPI_chatlog_Method' => 'ConduitAPIMethod', 'ConduitAPI_chatlog_query_Method' => 'ConduitAPI_chatlog_Method', 'ConduitAPI_chatlog_record_Method' => 'ConduitAPI_chatlog_Method', 'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_getcertificate_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_query_Method' => 'ConduitAPIMethod', 'ConduitAPI_daemon_launched_Method' => 'ConduitAPIMethod', 'ConduitAPI_daemon_log_Method' => 'ConduitAPIMethod', 'ConduitAPI_daemon_setstatus_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_close_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_createcomment_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_createinline_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_createrawdiff_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_finishpostponedlinters_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getalldiffs_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getcommitmessage_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getcommitpaths_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getdiff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getrevision_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getrevisioncomments_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_getrevisionfeedback_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_markcommitted_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_query_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_updateunitresults_Method' => 'ConduitAPIMethod', 'ConduitAPI_diffusion_Method' => 'ConduitAPIMethod', 'ConduitAPI_diffusion_findsymbols_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_getlintmessages_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_feed_Method' => 'ConduitAPIMethod', 'ConduitAPI_feed_publish_Method' => 'ConduitAPI_feed_Method', 'ConduitAPI_feed_query_Method' => 'ConduitAPI_feed_Method', 'ConduitAPI_file_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_download_Method' => 'ConduitAPI_file_Method', 'ConduitAPI_file_info_Method' => 'ConduitAPI_file_Method', 'ConduitAPI_file_upload_Method' => 'ConduitAPI_file_Method', 'ConduitAPI_file_uploadhash_Method' => 'ConduitAPI_file_Method', 'ConduitAPI_flag_Method' => 'ConduitAPIMethod', 'ConduitAPI_flag_delete_Method' => 'ConduitAPI_flag_Method', 'ConduitAPI_flag_edit_Method' => 'ConduitAPI_flag_Method', 'ConduitAPI_flag_query_Method' => 'ConduitAPI_flag_Method', 'ConduitAPI_macro_Method' => 'ConduitAPIMethod', 'ConduitAPI_macro_query_Method' => 'ConduitAPI_macro_Method', 'ConduitAPI_maniphest_Method' => 'ConduitAPIMethod', 'ConduitAPI_maniphest_createtask_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_find_Method' => 'ConduitAPI_maniphest_query_Method', 'ConduitAPI_maniphest_gettasktransactions_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_info_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_query_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_update_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_owners_Method' => 'ConduitAPIMethod', 'ConduitAPI_owners_query_Method' => 'ConduitAPI_owners_Method', 'ConduitAPI_paste_Method' => 'ConduitAPIMethod', 'ConduitAPI_paste_create_Method' => 'ConduitAPI_paste_Method', 'ConduitAPI_paste_info_Method' => 'ConduitAPI_paste_Method', 'ConduitAPI_paste_query_Method' => 'ConduitAPI_paste_Method', 'ConduitAPI_phid_Method' => 'ConduitAPIMethod', 'ConduitAPI_phid_info_Method' => 'ConduitAPI_phid_Method', 'ConduitAPI_phid_lookup_Method' => 'ConduitAPI_phid_Method', 'ConduitAPI_phid_query_Method' => 'ConduitAPI_phid_Method', 'ConduitAPI_phpast_Method' => 'ConduitAPIMethod', 'ConduitAPI_phpast_getast_Method' => 'ConduitAPI_phpast_Method', 'ConduitAPI_phpast_version_Method' => 'ConduitAPI_phpast_Method', 'ConduitAPI_phriction_Method' => 'ConduitAPIMethod', 'ConduitAPI_phriction_edit_Method' => 'ConduitAPI_phriction_Method', 'ConduitAPI_phriction_history_Method' => 'ConduitAPI_phriction_Method', 'ConduitAPI_phriction_info_Method' => 'ConduitAPI_phriction_Method', 'ConduitAPI_project_Method' => 'ConduitAPIMethod', 'ConduitAPI_project_query_Method' => 'ConduitAPI_project_Method', + 'ConduitAPI_releeph_Method' => 'ConduitAPIMethod', + 'ConduitAPI_releeph_getbranches_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releeph_projectinfo_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releeph_request_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_canpush_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_getauthorinfo_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_getbranch_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_getbranchcommitmessage_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_getcommitmessage_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_getorigcommitmessage_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_nextrequest_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_record_Method' => 'ConduitAPI_releeph_Method', + 'ConduitAPI_releephwork_recordpickstatus_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_remarkup_process_Method' => 'ConduitAPIMethod', 'ConduitAPI_repository_Method' => 'ConduitAPIMethod', 'ConduitAPI_repository_create_Method' => 'ConduitAPI_repository_Method', 'ConduitAPI_repository_query_Method' => 'ConduitAPI_repository_Method', 'ConduitAPI_slowvote_Method' => 'ConduitAPIMethod', 'ConduitAPI_slowvote_info_Method' => 'ConduitAPI_slowvote_Method', 'ConduitAPI_token_Method' => 'ConduitAPIMethod', 'ConduitAPI_token_give_Method' => 'ConduitAPI_token_Method', 'ConduitAPI_token_given_Method' => 'ConduitAPI_token_Method', 'ConduitAPI_token_query_Method' => 'ConduitAPI_token_Method', 'ConduitAPI_user_Method' => 'ConduitAPIMethod', 'ConduitAPI_user_addstatus_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_disable_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_enable_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_find_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_info_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_query_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_removestatus_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_whoami_Method' => 'ConduitAPI_user_Method', 'ConduitCallTestCase' => 'PhabricatorTestCase', 'ConduitException' => 'Exception', 'ConduitSSHWorkflow' => 'PhabricatorSSHWorkflow', 'ConpherenceConfigOptions' => 'PhabricatorApplicationConfigOptions', 'ConpherenceController' => 'PhabricatorController', 'ConpherenceDAO' => 'PhabricatorLiskDAO', 'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor', 'ConpherenceFileWidgetView' => 'AphrontView', 'ConpherenceFormDragAndDropUploadControl' => 'AphrontFormControl', 'ConpherenceImageData' => 'ConpherenceConstants', 'ConpherenceListController' => 'ConpherenceController', 'ConpherenceMenuItemView' => 'AphrontTagView', 'ConpherenceNewController' => 'ConpherenceController', 'ConpherenceParticipant' => 'ConpherenceDAO', 'ConpherenceParticipantQuery' => 'PhabricatorOffsetPagedQuery', 'ConpherenceParticipationStatus' => 'ConpherenceConstants', 'ConpherencePeopleMenuEventListener' => 'PhutilEventListener', 'ConpherencePontificateControl' => 'AphrontFormControl', 'ConpherenceReplyHandler' => 'PhabricatorMailReplyHandler', 'ConpherenceThread' => array( 0 => 'ConpherenceDAO', 1 => 'PhabricatorPolicyInterface', ), 'ConpherenceThreadQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ConpherenceTransaction' => 'PhabricatorApplicationTransaction', 'ConpherenceTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ConpherenceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ConpherenceTransactionType' => 'ConpherenceConstants', 'ConpherenceTransactionView' => 'AphrontView', 'ConpherenceUpdateController' => 'ConpherenceController', 'ConpherenceViewController' => 'ConpherenceController', 'ConpherenceWidgetController' => 'ConpherenceController', 'DarkConsoleController' => 'PhabricatorController', 'DarkConsoleDataController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', 'DarkConsoleEventPlugin' => 'DarkConsolePlugin', 'DarkConsoleEventPluginAPI' => 'PhutilEventListener', 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', 'DefaultDatabaseConfigurationProvider' => 'DatabaseConfigurationProvider', 'DifferentialActionHasNoEffectException' => 'DifferentialException', 'DifferentialAddCommentView' => 'AphrontView', 'DifferentialAffectedPath' => 'DifferentialDAO', 'DifferentialApplyPatchFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialArcanistProjectFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialAuditorsFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialAuthorFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialAuxiliaryField' => 'DifferentialDAO', 'DifferentialBlameRevisionFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialBranchFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail', 'DifferentialCCsFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialChangeset' => 'DifferentialDAO', 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetOneUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetOneUpTestRenderer' => 'DifferentialChangesetTestRenderer', 'DifferentialChangesetParserTestCase' => 'PhabricatorTestCase', 'DifferentialChangesetTestRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetTwoUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetTwoUpTestRenderer' => 'DifferentialChangesetTestRenderer', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialComment' => array( 0 => 'DifferentialDAO', 1 => 'PhabricatorMarkupInterface', ), 'DifferentialCommentEditor' => 'PhabricatorEditor', 'DifferentialCommentMail' => 'DifferentialMail', 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialCommitsFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialConflictsFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialController' => 'PhabricatorController', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDateCreatedFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialDateModifiedFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialDefaultFieldSelector' => 'DifferentialFieldSelector', 'DifferentialDependenciesFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialDependsOnFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialDiff' => 'DifferentialDAO', 'DifferentialDiffContentMail' => 'DifferentialMail', 'DifferentialDiffCreateController' => 'DifferentialController', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffTestCase' => 'ArcanistPhutilTestCase', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialException' => 'Exception', 'DifferentialExceptionMail' => 'DifferentialMail', 'DifferentialExportPatchFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialFieldDataNotAvailableException' => 'Exception', 'DifferentialFieldParseException' => 'Exception', 'DifferentialFieldSpecificationIncompleteException' => 'Exception', 'DifferentialFieldValidationException' => 'Exception', 'DifferentialFreeformFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialGitSVNIDFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialHostFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialHunkParserTestCase' => 'PhabricatorTestCase', 'DifferentialHunkTestCase' => 'ArcanistPhutilTestCase', 'DifferentialInlineComment' => array( 0 => 'DifferentialDAO', 1 => 'PhabricatorInlineCommentInterface', ), 'DifferentialInlineCommentEditController' => 'PhabricatorInlineCommentController', 'DifferentialInlineCommentEditView' => 'AphrontView', 'DifferentialInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController', 'DifferentialInlineCommentView' => 'AphrontView', 'DifferentialLinesFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialLintFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialLocalCommitsView' => 'AphrontView', 'DifferentialMail' => 'PhabricatorMail', 'DifferentialManiphestTasksFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail', 'DifferentialParseRenderTestCase' => 'PhabricatorTestCase', 'DifferentialPathFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialPeopleMenuEventListener' => 'PhutilEventListener', 'DifferentialPrimaryPaneView' => 'AphrontView', + 'DifferentialReleephRequestFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler', 'DifferentialResultsTableView' => 'AphrontView', 'DifferentialRevertPlanFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialReviewRequestMail' => 'DifferentialMail', 'DifferentialReviewedByFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialReviewerStatsTestCase' => 'PhabricatorTestCase', 'DifferentialReviewersFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialRevision' => array( 0 => 'DifferentialDAO', 1 => 'PhabricatorTokenReceiverInterface', 2 => 'PhabricatorPolicyInterface', ), 'DifferentialRevisionCommentListView' => 'AphrontView', 'DifferentialRevisionCommentView' => 'AphrontView', 'DifferentialRevisionDetailView' => 'AphrontView', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionEditor' => 'PhabricatorEditor', 'DifferentialRevisionIDFieldParserTestCase' => 'PhabricatorTestCase', 'DifferentialRevisionIDFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionListView' => 'AphrontView', 'DifferentialRevisionStatsController' => 'DifferentialController', 'DifferentialRevisionStatsView' => 'AphrontView', 'DifferentialRevisionStatusFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'DifferentialSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'DifferentialSubscribeController' => 'DifferentialController', 'DifferentialSummaryFieldSpecification' => 'DifferentialFreeformFieldSpecification', 'DifferentialTestPlanFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialTitleFieldSpecification' => 'DifferentialFreeformFieldSpecification', 'DifferentialUnitFieldSpecification' => 'DifferentialFieldSpecification', 'DiffusionBranchTableController' => 'DiffusionController', 'DiffusionBranchTableView' => 'DiffusionView', 'DiffusionBrowseController' => 'DiffusionController', 'DiffusionBrowseFileController' => 'DiffusionController', 'DiffusionBrowseTableView' => 'DiffusionView', 'DiffusionChangeController' => 'DiffusionController', 'DiffusionCommentListView' => 'AphrontView', 'DiffusionCommentView' => 'AphrontView', 'DiffusionCommitBranchesController' => 'DiffusionController', 'DiffusionCommitChangeTableView' => 'DiffusionView', 'DiffusionCommitController' => 'DiffusionController', 'DiffusionCommitEditController' => 'DiffusionController', 'DiffusionCommitParentsQuery' => 'DiffusionQuery', 'DiffusionCommitQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DiffusionCommitTagsController' => 'DiffusionController', 'DiffusionCommitTagsQuery' => 'DiffusionQuery', 'DiffusionContainsQuery' => 'DiffusionQuery', 'DiffusionController' => 'PhabricatorController', 'DiffusionDiffController' => 'DiffusionController', 'DiffusionDiffQuery' => 'DiffusionQuery', 'DiffusionEmptyResultView' => 'DiffusionView', 'DiffusionExistsQuery' => 'DiffusionQuery', 'DiffusionExternalController' => 'DiffusionController', 'DiffusionFileContentQuery' => 'DiffusionQuery', 'DiffusionGitBranchQuery' => 'DiffusionBranchQuery', 'DiffusionGitBranchQueryTestCase' => 'PhabricatorTestCase', 'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery', 'DiffusionGitCommitParentsQuery' => 'DiffusionCommitParentsQuery', 'DiffusionGitCommitTagsQuery' => 'DiffusionCommitTagsQuery', 'DiffusionGitContainsQuery' => 'DiffusionContainsQuery', 'DiffusionGitDiffQuery' => 'DiffusionDiffQuery', 'DiffusionGitExistsQuery' => 'DiffusionExistsQuery', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery', 'DiffusionGitLastModifiedQuery' => 'DiffusionLastModifiedQuery', 'DiffusionGitMergedCommitsQuery' => 'DiffusionMergedCommitsQuery', 'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionGitRequest' => 'DiffusionRequest', 'DiffusionGitTagListQuery' => 'DiffusionTagListQuery', 'DiffusionHistoryController' => 'DiffusionController', 'DiffusionHistoryQuery' => 'DiffusionQuery', 'DiffusionHistoryTableView' => 'DiffusionView', 'DiffusionHomeController' => 'DiffusionController', 'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController', 'DiffusionInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController', 'DiffusionLastModifiedController' => 'DiffusionController', 'DiffusionLastModifiedQuery' => 'DiffusionQuery', 'DiffusionLintController' => 'DiffusionController', 'DiffusionLintDetailsController' => 'DiffusionController', 'DiffusionMercurialBranchQuery' => 'DiffusionBranchQuery', 'DiffusionMercurialBrowseQuery' => 'DiffusionBrowseQuery', 'DiffusionMercurialCommitParentsQuery' => 'DiffusionCommitParentsQuery', 'DiffusionMercurialCommitTagsQuery' => 'DiffusionCommitTagsQuery', 'DiffusionMercurialContainsQuery' => 'DiffusionContainsQuery', 'DiffusionMercurialDiffQuery' => 'DiffusionDiffQuery', 'DiffusionMercurialExistsQuery' => 'DiffusionExistsQuery', 'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionMercurialHistoryQuery' => 'DiffusionHistoryQuery', 'DiffusionMercurialLastModifiedQuery' => 'DiffusionLastModifiedQuery', 'DiffusionMercurialMergedCommitsQuery' => 'DiffusionMergedCommitsQuery', 'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionMercurialRequest' => 'DiffusionRequest', 'DiffusionMercurialTagListQuery' => 'DiffusionTagListQuery', 'DiffusionMergedCommitsQuery' => 'DiffusionQuery', 'DiffusionPathCompleteController' => 'DiffusionController', 'DiffusionPathQueryTestCase' => 'PhabricatorTestCase', 'DiffusionPathValidateController' => 'DiffusionController', 'DiffusionPeopleMenuEventListener' => 'PhutilEventListener', 'DiffusionRawDiffQuery' => 'DiffusionQuery', 'DiffusionRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'DiffusionRepositoryController' => 'DiffusionController', 'DiffusionSetupException' => 'AphrontUsageException', 'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery', 'DiffusionSvnCommitParentsQuery' => 'DiffusionCommitParentsQuery', 'DiffusionSvnCommitTagsQuery' => 'DiffusionCommitTagsQuery', 'DiffusionSvnContainsQuery' => 'DiffusionContainsQuery', 'DiffusionSvnDiffQuery' => 'DiffusionDiffQuery', 'DiffusionSvnExistsQuery' => 'DiffusionExistsQuery', 'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionSvnHistoryQuery' => 'DiffusionHistoryQuery', 'DiffusionSvnLastModifiedQuery' => 'DiffusionLastModifiedQuery', 'DiffusionSvnMergedCommitsQuery' => 'DiffusionMergedCommitsQuery', 'DiffusionSvnRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionSvnRequest' => 'DiffusionRequest', 'DiffusionSvnTagListQuery' => 'DiffusionTagListQuery', 'DiffusionSymbolController' => 'DiffusionController', 'DiffusionSymbolQuery' => 'PhabricatorOffsetPagedQuery', 'DiffusionTagListController' => 'DiffusionController', 'DiffusionTagListQuery' => 'DiffusionQuery', 'DiffusionTagListView' => 'DiffusionView', 'DiffusionURITestCase' => 'ArcanistPhutilTestCase', 'DiffusionView' => 'AphrontView', 'DivinerArticleAtomizer' => 'DivinerAtomizer', 'DivinerAtomCache' => 'DivinerDiskCache', 'DivinerAtomizeWorkflow' => 'DivinerWorkflow', 'DivinerDefaultRenderer' => 'DivinerRenderer', 'DivinerFileAtomizer' => 'DivinerAtomizer', 'DivinerGenerateWorkflow' => 'DivinerWorkflow', 'DivinerListController' => 'PhabricatorController', 'DivinerPublishCache' => 'DivinerDiskCache', 'DivinerRemarkupRuleSymbol' => 'PhutilRemarkupRule', 'DivinerStaticPublisher' => 'DivinerPublisher', 'DivinerWorkflow' => 'PhutilArgumentWorkflow', 'DrydockAllocatorWorker' => 'PhabricatorWorker', 'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface', 'DrydockCommandInterface' => 'DrydockInterface', 'DrydockController' => 'PhabricatorController', 'DrydockDAO' => 'PhabricatorLiskDAO', 'DrydockLease' => 'DrydockDAO', 'DrydockLeaseListController' => 'DrydockController', 'DrydockLeaseQuery' => 'PhabricatorOffsetPagedQuery', 'DrydockLeaseReleaseController' => 'DrydockController', 'DrydockLeaseStatus' => 'DrydockConstants', 'DrydockLeaseViewController' => 'DrydockController', 'DrydockLocalCommandInterface' => 'DrydockCommandInterface', 'DrydockLocalHostBlueprint' => 'DrydockBlueprint', 'DrydockLog' => 'DrydockDAO', 'DrydockLogController' => 'DrydockController', 'DrydockLogQuery' => 'PhabricatorOffsetPagedQuery', 'DrydockManagementCloseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementLeaseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementReleaseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementWaitForLeaseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementWorkflow' => 'PhutilArgumentWorkflow', 'DrydockResource' => 'DrydockDAO', 'DrydockResourceCloseController' => 'DrydockController', 'DrydockResourceListController' => 'DrydockController', 'DrydockResourceQuery' => 'PhabricatorOffsetPagedQuery', 'DrydockResourceStatus' => 'DrydockConstants', 'DrydockResourceViewController' => 'DrydockController', 'DrydockSSHCommandInterface' => 'DrydockCommandInterface', 'DrydockWebrootInterface' => 'DrydockInterface', 'DrydockWorkingCopyBlueprint' => 'DrydockBlueprint', 'FeedPublisherWorker' => 'PhabricatorWorker', 'HarbormasterDAO' => 'PhabricatorLiskDAO', 'HarbormasterObject' => 'HarbormasterDAO', 'HarbormasterRunnerWorker' => 'PhabricatorWorker', 'HarbormasterScratchTable' => 'HarbormasterDAO', 'HeraldAction' => 'HeraldDAO', 'HeraldApplyTranscript' => 'HeraldDAO', 'HeraldCommitAdapter' => 'HeraldObjectAdapter', 'HeraldCondition' => 'HeraldDAO', 'HeraldController' => 'PhabricatorController', 'HeraldDAO' => 'PhabricatorLiskDAO', 'HeraldDeleteController' => 'HeraldController', 'HeraldDifferentialRevisionAdapter' => 'HeraldObjectAdapter', 'HeraldDryRunAdapter' => 'HeraldObjectAdapter', 'HeraldEditLogQuery' => 'PhabricatorOffsetPagedQuery', 'HeraldHomeController' => 'HeraldController', 'HeraldInvalidConditionException' => 'Exception', 'HeraldInvalidFieldException' => 'Exception', 'HeraldNewController' => 'HeraldController', 'HeraldRecursiveConditionsException' => 'Exception', 'HeraldRule' => 'HeraldDAO', 'HeraldRuleController' => 'HeraldController', 'HeraldRuleEdit' => 'HeraldDAO', 'HeraldRuleEditHistoryController' => 'HeraldController', 'HeraldRuleEditHistoryView' => 'AphrontView', 'HeraldRuleListView' => 'AphrontView', 'HeraldRuleQuery' => 'PhabricatorOffsetPagedQuery', 'HeraldTestConsoleController' => 'HeraldController', 'HeraldTranscript' => 'HeraldDAO', 'HeraldTranscriptController' => 'HeraldController', 'HeraldTranscriptListController' => 'HeraldController', 'JavelinReactorExample' => 'PhabricatorUIExample', 'JavelinUIExample' => 'PhabricatorUIExample', 'JavelinViewExample' => 'PhabricatorUIExample', 'JavelinViewExampleServerView' => 'AphrontView', 'LiskChunkTestCase' => 'PhabricatorTestCase', 'LiskDAOTestCase' => 'PhabricatorTestCase', 'LiskEphemeralObjectException' => 'Exception', 'LiskFixtureTestCase' => 'PhabricatorTestCase', 'LiskIsolationTestCase' => 'PhabricatorTestCase', 'LiskIsolationTestDAO' => 'LiskDAO', 'LiskIsolationTestDAOException' => 'Exception', 'LiskMigrationIterator' => 'PhutilBufferedIterator', 'ManiphestAction' => 'ManiphestConstants', 'ManiphestAuxiliaryFieldDefaultSpecification' => 'ManiphestAuxiliaryFieldSpecification', 'ManiphestAuxiliaryFieldSpecification' => 'PhabricatorMarkupInterface', 'ManiphestAuxiliaryFieldTypeException' => 'Exception', 'ManiphestAuxiliaryFieldValidationException' => 'Exception', 'ManiphestBatchEditController' => 'ManiphestController', 'ManiphestController' => 'PhabricatorController', 'ManiphestDAO' => 'PhabricatorLiskDAO', 'ManiphestDefaultTaskExtensions' => 'ManiphestTaskExtensions', 'ManiphestEdgeEventListener' => 'PhutilEventListener', 'ManiphestExportController' => 'ManiphestController', 'ManiphestPeopleMenuEventListener' => 'PhutilEventListener', 'ManiphestRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'ManiphestReplyHandler' => 'PhabricatorMailReplyHandler', 'ManiphestReportController' => 'ManiphestController', 'ManiphestSavedQuery' => 'ManiphestDAO', 'ManiphestSavedQueryDeleteController' => 'ManiphestController', 'ManiphestSavedQueryEditController' => 'ManiphestController', 'ManiphestSavedQueryListController' => 'ManiphestController', 'ManiphestSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'ManiphestSubpriorityController' => 'ManiphestController', 'ManiphestTask' => array( 0 => 'ManiphestDAO', 1 => 'PhabricatorMarkupInterface', 2 => 'PhabricatorPolicyInterface', 3 => 'PhabricatorTokenReceiverInterface', ), 'ManiphestTaskAuxiliaryStorage' => 'ManiphestDAO', 'ManiphestTaskDescriptionChangeController' => 'ManiphestController', 'ManiphestTaskDescriptionPreviewController' => 'ManiphestController', 'ManiphestTaskDetailController' => 'ManiphestController', 'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskListController' => 'ManiphestController', 'ManiphestTaskListView' => 'ManiphestView', 'ManiphestTaskOwner' => 'ManiphestConstants', 'ManiphestTaskPriority' => 'ManiphestConstants', 'ManiphestTaskProject' => 'ManiphestDAO', 'ManiphestTaskProjectsView' => 'ManiphestView', 'ManiphestTaskQuery' => 'PhabricatorQuery', 'ManiphestTaskStatus' => 'ManiphestConstants', 'ManiphestTaskSubscriber' => 'ManiphestDAO', 'ManiphestTaskSummaryView' => 'ManiphestView', 'ManiphestTransaction' => array( 0 => 'ManiphestDAO', 1 => 'PhabricatorMarkupInterface', ), 'ManiphestTransactionDetailView' => 'ManiphestView', 'ManiphestTransactionEditor' => 'PhabricatorEditor', 'ManiphestTransactionListView' => 'ManiphestView', 'ManiphestTransactionPreviewController' => 'ManiphestController', 'ManiphestTransactionSaveController' => 'ManiphestController', 'ManiphestTransactionType' => 'ManiphestConstants', 'ManiphestView' => 'AphrontView', 'MetaMTANotificationType' => 'MetaMTAConstants', 'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler', 'PackageCreateMail' => 'PackageMail', 'PackageDeleteMail' => 'PackageMail', 'PackageMail' => 'PhabricatorMail', 'PackageModifyMail' => 'PackageMail', 'PasteEmbedView' => 'AphrontView', 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAWSConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorActionListExample' => 'PhabricatorUIExample', 'PhabricatorActionListView' => 'AphrontView', 'PhabricatorActionView' => 'AphrontView', 'PhabricatorAllCapsTranslation' => 'PhabricatorTranslation', 'PhabricatorAnchorView' => 'AphrontView', 'PhabricatorAphrontBarExample' => 'PhabricatorUIExample', 'PhabricatorApplicationApplications' => 'PhabricatorApplication', 'PhabricatorApplicationAudit' => 'PhabricatorApplication', 'PhabricatorApplicationAuth' => 'PhabricatorApplication', 'PhabricatorApplicationCalendar' => 'PhabricatorApplication', 'PhabricatorApplicationChatLog' => 'PhabricatorApplication', 'PhabricatorApplicationConduit' => 'PhabricatorApplication', 'PhabricatorApplicationConfig' => 'PhabricatorApplication', 'PhabricatorApplicationConfigOptions' => 'Phobject', 'PhabricatorApplicationConpherence' => 'PhabricatorApplication', 'PhabricatorApplicationCountdown' => 'PhabricatorApplication', 'PhabricatorApplicationDaemons' => 'PhabricatorApplication', 'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationDifferential' => 'PhabricatorApplication', 'PhabricatorApplicationDiffusion' => 'PhabricatorApplication', 'PhabricatorApplicationDiviner' => 'PhabricatorApplication', 'PhabricatorApplicationDrydock' => 'PhabricatorApplication', 'PhabricatorApplicationFact' => 'PhabricatorApplication', 'PhabricatorApplicationFeed' => 'PhabricatorApplication', 'PhabricatorApplicationFiles' => 'PhabricatorApplication', 'PhabricatorApplicationFlags' => 'PhabricatorApplication', 'PhabricatorApplicationHerald' => 'PhabricatorApplication', 'PhabricatorApplicationLaunchView' => 'AphrontView', 'PhabricatorApplicationMacro' => 'PhabricatorApplication', 'PhabricatorApplicationMailingLists' => 'PhabricatorApplication', 'PhabricatorApplicationManiphest' => 'PhabricatorApplication', 'PhabricatorApplicationMetaMTA' => 'PhabricatorApplication', 'PhabricatorApplicationOwners' => 'PhabricatorApplication', 'PhabricatorApplicationPHID' => 'PhabricatorApplication', 'PhabricatorApplicationPHPAST' => 'PhabricatorApplication', 'PhabricatorApplicationPaste' => 'PhabricatorApplication', 'PhabricatorApplicationPeople' => 'PhabricatorApplication', 'PhabricatorApplicationPhame' => 'PhabricatorApplication', 'PhabricatorApplicationPholio' => 'PhabricatorApplication', 'PhabricatorApplicationPhriction' => 'PhabricatorApplication', 'PhabricatorApplicationPonder' => 'PhabricatorApplication', 'PhabricatorApplicationProject' => 'PhabricatorApplication', + 'PhabricatorApplicationReleeph' => 'PhabricatorApplication', + 'PhabricatorApplicationReleephConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorApplicationRepositories' => 'PhabricatorApplication', 'PhabricatorApplicationSettings' => 'PhabricatorApplication', 'PhabricatorApplicationSlowvote' => 'PhabricatorApplication', 'PhabricatorApplicationStatusView' => 'AphrontView', 'PhabricatorApplicationSubscriptions' => 'PhabricatorApplication', 'PhabricatorApplicationTokens' => 'PhabricatorApplication', 'PhabricatorApplicationTransaction' => array( 0 => 'PhabricatorLiskDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorApplicationTransactionComment' => array( 0 => 'PhabricatorLiskDAO', 1 => 'PhabricatorMarkupInterface', 2 => 'PhabricatorPolicyInterface', ), 'PhabricatorApplicationTransactionCommentEditController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionCommentHistoryController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationTransactionCommentView' => 'AphrontView', 'PhabricatorApplicationTransactionController' => 'PhabricatorController', 'PhabricatorApplicationTransactionEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory', 'PhabricatorApplicationTransactionNoEffectException' => 'Exception', 'PhabricatorApplicationTransactionNoEffectResponse' => 'AphrontProxyResponse', 'PhabricatorApplicationTransactionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationTransactionResponse' => 'AphrontProxyResponse', 'PhabricatorApplicationTransactionTextDiffDetailView' => 'AphrontView', 'PhabricatorApplicationTransactionView' => 'AphrontView', 'PhabricatorApplicationTransactions' => 'PhabricatorApplication', 'PhabricatorApplicationUIExamples' => 'PhabricatorApplication', 'PhabricatorApplicationUninstallController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationsController' => 'PhabricatorController', 'PhabricatorApplicationsListController' => 'PhabricatorApplicationsController', 'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController', 'PhabricatorAuditComment' => array( 0 => 'PhabricatorAuditDAO', 1 => 'PhabricatorMarkupInterface', ), 'PhabricatorAuditCommentEditor' => 'PhabricatorEditor', 'PhabricatorAuditCommitListView' => 'AphrontView', 'PhabricatorAuditController' => 'PhabricatorController', 'PhabricatorAuditDAO' => 'PhabricatorLiskDAO', 'PhabricatorAuditInlineComment' => array( 0 => 'PhabricatorAuditDAO', 1 => 'PhabricatorInlineCommentInterface', ), 'PhabricatorAuditListController' => 'PhabricatorAuditController', 'PhabricatorAuditListView' => 'AphrontView', 'PhabricatorAuditPreviewController' => 'PhabricatorAuditController', 'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorBarePageExample' => 'PhabricatorUIExample', 'PhabricatorBarePageView' => 'AphrontPageView', 'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation', 'PhabricatorBot' => 'PhabricatorDaemon', 'PhabricatorBotBaseStreamingProtocolAdapter' => 'PhabricatorBaseProtocolAdapter', 'PhabricatorBotChannel' => 'PhabricatorBotTarget', 'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotDifferentialNotificationHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFeedNotificationHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFlowdockProtocolAdapter' => 'PhabricatorBotBaseStreamingProtocolAdapter', 'PhabricatorBotLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotMacroHandler' => 'PhabricatorBotHandler', 'PhabricatorBotObjectNameHandler' => 'PhabricatorBotHandler', 'PhabricatorBotSymbolHandler' => 'PhabricatorBotHandler', 'PhabricatorBotUser' => 'PhabricatorBotTarget', 'PhabricatorBotWhatsNewHandler' => 'PhabricatorBotHandler', 'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList', 'PhabricatorButtonsExample' => 'PhabricatorUIExample', 'PhabricatorCacheDAO' => 'PhabricatorLiskDAO', 'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController', 'PhabricatorCalendarController' => 'PhabricatorController', 'PhabricatorCalendarDAO' => 'PhabricatorLiskDAO', 'PhabricatorCalendarDeleteStatusController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEditStatusController' => 'PhabricatorCalendarController', 'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO', 'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase', 'PhabricatorCalendarViewStatusController' => 'PhabricatorCalendarController', 'PhabricatorCampfireProtocolAdapter' => 'PhabricatorBotBaseStreamingProtocolAdapter', 'PhabricatorChangesetResponse' => 'AphrontProxyResponse', 'PhabricatorChatLogChannel' => array( 0 => 'PhabricatorChatLogDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorChatLogChannelListController' => 'PhabricatorChatLogController', 'PhabricatorChatLogChannelLogController' => 'PhabricatorChatLogController', 'PhabricatorChatLogChannelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorChatLogController' => 'PhabricatorController', 'PhabricatorChatLogDAO' => 'PhabricatorLiskDAO', 'PhabricatorChatLogEvent' => array( 0 => 'PhabricatorChatLogDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorChatLogEventType' => 'PhabricatorChatLogConstants', 'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitController' => 'PhabricatorController', 'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', 'PhabricatorConduitListController' => 'PhabricatorConduitController', 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitTokenController' => 'PhabricatorConduitController', 'PhabricatorConfigAllController' => 'PhabricatorConfigController', 'PhabricatorConfigController' => 'PhabricatorController', 'PhabricatorConfigDatabaseSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigDefaultSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigDictionarySource' => 'PhabricatorConfigSource', 'PhabricatorConfigEditController' => 'PhabricatorConfigController', 'PhabricatorConfigEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorConfigEntry' => 'PhabricatorConfigEntryDAO', 'PhabricatorConfigEntryDAO' => 'PhabricatorLiskDAO', 'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigGroupController' => 'PhabricatorConfigController', 'PhabricatorConfigIgnoreController' => 'PhabricatorApplicationsController', 'PhabricatorConfigIssueListController' => 'PhabricatorConfigController', 'PhabricatorConfigIssueViewController' => 'PhabricatorConfigController', 'PhabricatorConfigListController' => 'PhabricatorConfigController', 'PhabricatorConfigLocalSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigManagementDeleteWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementGetWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementListWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorConfigOption' => array( 0 => 'Phobject', 1 => 'PhabricatorMarkupInterface', ), 'PhabricatorConfigProxySource' => 'PhabricatorConfigSource', 'PhabricatorConfigResponse' => 'AphrontHTMLResponse', 'PhabricatorConfigStackSource' => 'PhabricatorConfigSource', 'PhabricatorConfigTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorConfigValidationException' => 'Exception', 'PhabricatorContentSourceView' => 'AphrontView', 'PhabricatorController' => 'AphrontController', 'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorCountdownController' => 'PhabricatorController', 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', 'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController', 'PhabricatorCountdownEditController' => 'PhabricatorCountdownController', 'PhabricatorCountdownListController' => 'PhabricatorCountdownController', 'PhabricatorCountdownRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorCountdownViewController' => 'PhabricatorCountdownController', 'PhabricatorCountedToggleButtonsExample' => 'PhabricatorUIExample', 'PhabricatorCrumbView' => 'AphrontView', 'PhabricatorCrumbsView' => 'AphrontView', 'PhabricatorCursorPagedPolicyAwareQuery' => 'PhabricatorPolicyAwareQuery', 'PhabricatorDaemon' => 'PhutilDaemon', 'PhabricatorDaemonCombinedLogController' => 'PhabricatorDaemonController', 'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController', 'PhabricatorDaemonController' => 'PhabricatorController', 'PhabricatorDaemonDAO' => 'PhabricatorLiskDAO', 'PhabricatorDaemonLog' => 'PhabricatorDaemonDAO', 'PhabricatorDaemonLogEvent' => 'PhabricatorDaemonDAO', 'PhabricatorDaemonLogEventsView' => 'AphrontView', 'PhabricatorDaemonLogListController' => 'PhabricatorDaemonController', 'PhabricatorDaemonLogListView' => 'AphrontView', 'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController', 'PhabricatorDebugController' => 'PhabricatorController', 'PhabricatorDefaultFileStorageEngineSelector' => 'PhabricatorFileStorageEngineSelector', 'PhabricatorDefaultSearchEngineSelector' => 'PhabricatorSearchEngineSelector', 'PhabricatorDeveloperConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDifferentialConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDiffusionConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDirectoryController' => 'PhabricatorController', 'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController', 'PhabricatorDisabledUserController' => 'PhabricatorAuthController', 'PhabricatorDisqusConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDraft' => 'PhabricatorDraftDAO', 'PhabricatorDraftDAO' => 'PhabricatorLiskDAO', 'PhabricatorEdgeConfig' => 'PhabricatorEdgeConstants', 'PhabricatorEdgeCycleException' => 'Exception', 'PhabricatorEdgeEditor' => 'PhabricatorEditor', 'PhabricatorEdgeGraph' => 'AbstractDirectedGraph', 'PhabricatorEdgeQuery' => 'PhabricatorQuery', 'PhabricatorEdgeTestCase' => 'PhabricatorTestCase', 'PhabricatorEditor' => 'Phobject', 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 'PhabricatorEmailTokenController' => 'PhabricatorAuthController', 'PhabricatorEmailVerificationController' => 'PhabricatorPeopleController', 'PhabricatorEmptyQueryException' => 'Exception', 'PhabricatorEnglishTranslation' => 'PhabricatorBaseEnglishTranslation', 'PhabricatorEnvTestCase' => 'PhabricatorTestCase', 'PhabricatorErrorExample' => 'PhabricatorUIExample', 'PhabricatorEvent' => 'PhutilEvent', 'PhabricatorEventType' => 'PhutilEventType', 'PhabricatorExampleEventListener' => 'PhutilEventListener', 'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFacebookConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFactAggregate' => 'PhabricatorFactDAO', 'PhabricatorFactChartController' => 'PhabricatorFactController', 'PhabricatorFactController' => 'PhabricatorController', 'PhabricatorFactCountEngine' => 'PhabricatorFactEngine', 'PhabricatorFactCursor' => 'PhabricatorFactDAO', 'PhabricatorFactDAO' => 'PhabricatorLiskDAO', 'PhabricatorFactDaemon' => 'PhabricatorDaemon', 'PhabricatorFactHomeController' => 'PhabricatorFactController', 'PhabricatorFactLastUpdatedEngine' => 'PhabricatorFactEngine', 'PhabricatorFactManagementAnalyzeWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementCursorsWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementDestroyWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementListWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementStatusWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorFactRaw' => 'PhabricatorFactDAO', 'PhabricatorFactSimpleSpec' => 'PhabricatorFactSpec', 'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator', 'PhabricatorFeedConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFeedController' => 'PhabricatorController', 'PhabricatorFeedDAO' => 'PhabricatorLiskDAO', 'PhabricatorFeedMainController' => 'PhabricatorFeedController', 'PhabricatorFeedPublicStreamController' => 'PhabricatorFeedController', 'PhabricatorFeedQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFeedStory' => 'PhabricatorPolicyInterface', 'PhabricatorFeedStoryAggregate' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryAudit' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryCommit' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryDifferential' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryDifferentialAggregate' => 'PhabricatorFeedStoryAggregate', 'PhabricatorFeedStoryManiphest' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryManiphestAggregate' => 'PhabricatorFeedStoryAggregate', 'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryPhriction' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryProject' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryStatus' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryTypeConstants' => 'PhabricatorFeedConstants', 'PhabricatorFeedStoryView' => 'PhabricatorFeedView', 'PhabricatorFeedView' => 'AphrontView', 'PhabricatorFile' => array( 0 => 'PhabricatorFileDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileDataController' => 'PhabricatorFileController', 'PhabricatorFileDeleteController' => 'PhabricatorFileController', 'PhabricatorFileDropUploadController' => 'PhabricatorFileController', 'PhabricatorFileImageMacro' => array( 0 => 'PhabricatorFileDAO', 1 => 'PhabricatorSubscribableInterface', 2 => 'PhabricatorApplicationTransactionInterface', ), 'PhabricatorFileInfoController' => 'PhabricatorFileController', 'PhabricatorFileLinkListView' => 'AphrontView', 'PhabricatorFileLinkView' => 'AphrontView', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFileShortcutController' => 'PhabricatorFileController', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileStorageConfigurationException' => 'Exception', 'PhabricatorFileTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTransformController' => 'PhabricatorFileController', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileUploadException' => 'Exception', 'PhabricatorFilesConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFilesManagementEnginesWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementMetadataWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementMigrateWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorFlag' => 'PhabricatorFlagDAO', 'PhabricatorFlagColor' => 'PhabricatorFlagConstants', 'PhabricatorFlagController' => 'PhabricatorController', 'PhabricatorFlagDAO' => 'PhabricatorLiskDAO', 'PhabricatorFlagDeleteController' => 'PhabricatorFlagController', 'PhabricatorFlagEditController' => 'PhabricatorFlagController', 'PhabricatorFlagListController' => 'PhabricatorFlagController', 'PhabricatorFlagListView' => 'AphrontView', 'PhabricatorFlagsUIEventListener' => 'PhutilEventListener', 'PhabricatorFormExample' => 'PhabricatorUIExample', 'PhabricatorGarbageCollectorConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon', 'PhabricatorGestureExample' => 'PhabricatorUIExample', 'PhabricatorGitHubConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorGlobalLock' => 'PhutilLock', 'PhabricatorGlobalUploadTargetView' => 'AphrontView', 'PhabricatorGoogleConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorHashTestCase' => 'PhabricatorTestCase', 'PhabricatorHeaderView' => 'AphrontView', 'PhabricatorHelpController' => 'PhabricatorController', 'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController', 'PhabricatorIRCBot' => 'PhabricatorDaemon', 'PhabricatorIRCProtocolAdapter' => 'PhabricatorBaseProtocolAdapter', 'PhabricatorIRCProtocolHandler' => 'PhabricatorBotHandler', 'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase', 'PhabricatorInlineCommentController' => 'PhabricatorController', 'PhabricatorInlineCommentInterface' => 'PhabricatorMarkupInterface', 'PhabricatorInlineCommentPreviewController' => 'PhabricatorController', 'PhabricatorInlineSummaryView' => 'AphrontView', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', 'PhabricatorLDAPConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorLDAPLoginController' => 'PhabricatorAuthController', 'PhabricatorLDAPRegistrationController' => 'PhabricatorAuthController', 'PhabricatorLDAPUnknownUserException' => 'Exception', 'PhabricatorLDAPUnlinkController' => 'PhabricatorAuthController', 'PhabricatorLintEngine' => 'PhutilLintEngine', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase', 'PhabricatorLoginController' => 'PhabricatorAuthController', 'PhabricatorLoginValidateController' => 'PhabricatorAuthController', 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorMacroCommentController' => 'PhabricatorMacroController', 'PhabricatorMacroConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMacroController' => 'PhabricatorController', 'PhabricatorMacroDisableController' => 'PhabricatorMacroController', 'PhabricatorMacroEditController' => 'PhabricatorMacroController', 'PhabricatorMacroEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorMacroListController' => 'PhabricatorMacroController', 'PhabricatorMacroMemeController' => 'PhabricatorMacroController', 'PhabricatorMacroMemeDialogController' => 'PhabricatorMacroController', 'PhabricatorMacroReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorMacroTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorMacroViewController' => 'PhabricatorMacroController', 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailingListsController' => 'PhabricatorController', 'PhabricatorMailingListsEditController' => 'PhabricatorMailingListsController', 'PhabricatorMailingListsListController' => 'PhabricatorMailingListsController', 'PhabricatorMainMenuGroupView' => 'AphrontView', 'PhabricatorMainMenuIconView' => 'AphrontView', 'PhabricatorMainMenuSearchView' => 'AphrontView', 'PhabricatorMainMenuView' => 'AphrontView', 'PhabricatorManiphestConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMarkupCache' => 'PhabricatorCacheDAO', 'PhabricatorMenuItemView' => 'AphrontTagView', 'PhabricatorMenuView' => 'AphrontTagView', 'PhabricatorMenuViewTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailBodyTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAReceivedListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAWorker' => 'PhabricatorWorker', 'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController', 'PhabricatorMySQLConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorNoteExample' => 'PhabricatorUIExample', 'PhabricatorNotificationClearController' => 'PhabricatorNotificationController', 'PhabricatorNotificationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorNotificationController' => 'PhabricatorController', 'PhabricatorNotificationIndividualController' => 'PhabricatorNotificationController', 'PhabricatorNotificationListController' => 'PhabricatorNotificationController', 'PhabricatorNotificationPanelController' => 'PhabricatorNotificationController', 'PhabricatorNotificationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorNotificationStatusController' => 'PhabricatorNotificationController', 'PhabricatorOAuthClientAuthorization' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthClientAuthorizationBaseController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthClientAuthorizationDeleteController' => 'PhabricatorOAuthClientAuthorizationBaseController', 'PhabricatorOAuthClientAuthorizationEditController' => 'PhabricatorOAuthClientAuthorizationBaseController', 'PhabricatorOAuthClientAuthorizationListController' => 'PhabricatorOAuthClientAuthorizationBaseController', 'PhabricatorOAuthClientAuthorizationQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorOAuthClientBaseController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthClientDeleteController' => 'PhabricatorOAuthClientBaseController', 'PhabricatorOAuthClientEditController' => 'PhabricatorOAuthClientBaseController', 'PhabricatorOAuthClientListController' => 'PhabricatorOAuthClientBaseController', 'PhabricatorOAuthClientViewController' => 'PhabricatorOAuthClientBaseController', 'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController', 'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController', 'PhabricatorOAuthFailureView' => 'AphrontView', 'PhabricatorOAuthLoginController' => 'PhabricatorAuthController', 'PhabricatorOAuthProviderDisqus' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthProviderException' => 'Exception', 'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthProviderGitHub' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthProviderGoogle' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthProviderPhabricator' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController', 'PhabricatorOAuthResponse' => 'AphrontResponse', 'PhabricatorOAuthServerAccessToken' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthServerAuthController' => 'PhabricatorAuthController', 'PhabricatorOAuthServerAuthorizationCode' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthServerClient' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthServerClientQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorOAuthServerController' => 'PhabricatorController', 'PhabricatorOAuthServerDAO' => 'PhabricatorLiskDAO', 'PhabricatorOAuthServerTestCase' => 'PhabricatorTestCase', 'PhabricatorOAuthServerTestController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthServerTokenController' => 'PhabricatorAuthController', 'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController', 'PhabricatorObjectHandleStatus' => 'PhabricatorObjectHandleConstants', 'PhabricatorObjectItemListExample' => 'PhabricatorUIExample', 'PhabricatorObjectItemListView' => 'AphrontView', 'PhabricatorObjectItemView' => 'AphrontView', 'PhabricatorObjectListView' => 'AphrontView', 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', 'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorOwnersController' => 'PhabricatorController', 'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO', 'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController', 'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController', 'PhabricatorOwnersEditController' => 'PhabricatorOwnersController', 'PhabricatorOwnersListController' => 'PhabricatorOwnersController', 'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO', 'PhabricatorOwnersPackage' => array( 0 => 'PhabricatorOwnersDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorOwnersPackageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorOwnersPackageTestCase' => 'PhabricatorTestCase', 'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO', 'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPHIDConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPHIDController' => 'PhabricatorController', 'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController', 'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPaste' => array( 0 => 'PhabricatorPasteDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorPasteController' => 'PhabricatorController', 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 'PhabricatorPasteEditController' => 'PhabricatorPasteController', 'PhabricatorPasteListController' => 'PhabricatorPasteController', 'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPasteRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PhabricatorPasteViewController' => 'PhabricatorPasteController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleLdapController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorPeopleQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorPhabricatorOAuthConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPhameConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPholioConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPhrictionConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPinboardItemView' => 'AphrontView', 'PhabricatorPinboardView' => 'AphrontView', 'PhabricatorPolicies' => 'PhabricatorPolicyConstants', 'PhabricatorPolicyAwareQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorPolicyAwareTestQuery' => 'PhabricatorPolicyAwareQuery', 'PhabricatorPolicyCapability' => 'PhabricatorPolicyConstants', 'PhabricatorPolicyConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPolicyException' => 'Exception', 'PhabricatorPolicyQuery' => 'PhabricatorQuery', 'PhabricatorPolicyTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyTestObject' => 'PhabricatorPolicyInterface', 'PhabricatorPolicyType' => 'PhabricatorPolicyConstants', 'PhabricatorProfileHeaderView' => 'AphrontView', 'PhabricatorProject' => array( 0 => 'PhabricatorProjectDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorProjectController' => 'PhabricatorController', 'PhabricatorProjectCreateController' => 'PhabricatorProjectController', 'PhabricatorProjectDAO' => 'PhabricatorLiskDAO', 'PhabricatorProjectEditor' => 'PhabricatorEditor', 'PhabricatorProjectEditorTestCase' => 'PhabricatorTestCase', 'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController', 'PhabricatorProjectNameCollisionException' => 'Exception', 'PhabricatorProjectProfile' => 'PhabricatorProjectDAO', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', 'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController', 'PhabricatorProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProjectTransaction' => 'PhabricatorProjectDAO', 'PhabricatorProjectTransactionType' => 'PhabricatorProjectConstants', 'PhabricatorProjectUpdateController' => 'PhabricatorProjectController', 'PhabricatorPropertyListExample' => 'PhabricatorUIExample', 'PhabricatorPropertyListView' => 'AphrontView', 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRedirectController' => 'PhabricatorController', 'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController', 'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl', 'PhabricatorRemarkupRuleEmbedFile' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleMeme' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleObject' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule', 'PhabricatorRepository' => array( 0 => 'PhabricatorRepositoryDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryArcanistProject' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryArcanistProjectDeleteController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryAuditRequest' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryBranch' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommit' => array( 0 => 'PhabricatorRepositoryDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitOwnersWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker', 'PhabricatorRepositoryCommitSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorRepositoryConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRepositoryController' => 'PhabricatorController', 'PhabricatorRepositoryCreateController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorRepositoryDeleteController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryEditController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryManagementDeleteWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementPullWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryPullLocalDaemon' => 'PhabricatorDaemon', 'PhabricatorRepositoryPullLocalDaemonTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositorySymbol' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryTestCase' => 'PhabricatorTestCase', 'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorSSHWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorSearchAttachController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchBaseController' => 'PhabricatorController', 'PhabricatorSearchConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchDAO' => 'PhabricatorLiskDAO', 'PhabricatorSearchDocument' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO', 'PhabricatorSearchEngineElastic' => 'PhabricatorSearchEngine', 'PhabricatorSearchEngineMySQL' => 'PhabricatorSearchEngine', 'PhabricatorSearchManagementIndexWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorSearchQuery' => 'PhabricatorSearchDAO', 'PhabricatorSearchResultView' => 'AphrontView', 'PhabricatorSearchSelectController' => 'PhabricatorSearchBaseController', 'PhabricatorSecurityConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSendGridConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSettingsAdjustController' => 'PhabricatorController', 'PhabricatorSettingsMainController' => 'PhabricatorController', 'PhabricatorSettingsPanelAccount' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelConduit' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelDiffPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelDisplayPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelEmailAddresses' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelEmailPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelHomePreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelLDAP' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelOAuth' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelPassword' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelProfile' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelSSHKeys' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelSearchPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSetupCheckAPC' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckBaseURI' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckDatabase' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckExtensions' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckFacebook' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckGD' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckImagemagick' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckMail' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckMySQL' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckPHPConfig' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckPath' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckPygment' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckStorage' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckTimezone' => 'PhabricatorSetupCheck', 'PhabricatorSetupIssueExample' => 'PhabricatorUIExample', 'PhabricatorSetupIssueView' => 'AphrontView', 'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvoteComment' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvoteController' => 'PhabricatorController', 'PhabricatorSlowvoteCreateController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO', 'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvotePoll' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController', 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', 'PhabricatorSortTableExample' => 'PhabricatorUIExample', 'PhabricatorSourceCodeView' => 'AphrontView', 'PhabricatorStandardPageView' => 'PhabricatorBarePageView', 'PhabricatorStatusController' => 'PhabricatorController', 'PhabricatorStorageManagementDatabasesWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDestroyWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDumpWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementStatusWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementUpgradeWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorSubscribersQuery' => 'PhabricatorQuery', 'PhabricatorSubscriptionsEditController' => 'PhabricatorController', 'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor', 'PhabricatorSubscriptionsUIEventListener' => 'PhutilEventListener', 'PhabricatorSymbolNameLinter' => 'ArcanistXHPASTLintNamingHook', 'PhabricatorSyntaxHighlightingConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorTagExample' => 'PhabricatorUIExample', 'PhabricatorTagView' => 'AphrontView', 'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon', 'PhabricatorTestCase' => 'ArcanistPhutilTestCase', 'PhabricatorTestStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorTestWorker' => 'PhabricatorWorker', 'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO', 'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO', 'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO', 'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO', 'PhabricatorTimelineEventView' => 'AphrontView', 'PhabricatorTimelineExample' => 'PhabricatorUIExample', 'PhabricatorTimelineIterator' => 'Iterator', 'PhabricatorTimelineView' => 'AphrontView', 'PhabricatorTimer' => 'PhabricatorCountdownDAO', 'PhabricatorToken' => array( 0 => 'PhabricatorTokenDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorTokenController' => 'PhabricatorController', 'PhabricatorTokenCount' => 'PhabricatorTokenDAO', 'PhabricatorTokenCountQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorTokenDAO' => 'PhabricatorLiskDAO', 'PhabricatorTokenGiveController' => 'PhabricatorTokenController', 'PhabricatorTokenGiven' => array( 0 => 'PhabricatorTokenDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorTokenGivenController' => 'PhabricatorTokenController', 'PhabricatorTokenGivenEditor' => 'PhabricatorEditor', 'PhabricatorTokenGivenFeedStory' => 'PhabricatorFeedStory', 'PhabricatorTokenGivenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorTokenUIEventListener' => 'PhutilEventListener', 'PhabricatorTransactionView' => 'AphrontView', 'PhabricatorTransformedFile' => 'PhabricatorFileDAO', 'PhabricatorTranslationsConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorTrivialTestCase' => 'PhabricatorTestCase', 'PhabricatorTwoColumnExample' => 'PhabricatorUIExample', 'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 'PhabricatorUIExampleRenderController' => 'PhabricatorController', 'PhabricatorUIListFilterExample' => 'PhabricatorUIExample', 'PhabricatorUINotificationExample' => 'PhabricatorUIExample', 'PhabricatorUIPagerExample' => 'PhabricatorUIExample', 'PhabricatorUITooltipExample' => 'PhabricatorUIExample', 'PhabricatorUnitsTestCase' => 'PhabricatorTestCase', 'PhabricatorUser' => array( 0 => 'PhabricatorUserDAO', 1 => 'PhutilPerson', ), 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', 'PhabricatorUserEditor' => 'PhabricatorEditor', 'PhabricatorUserEmail' => 'PhabricatorUserDAO', 'PhabricatorUserLDAPInfo' => 'PhabricatorUserDAO', 'PhabricatorUserLog' => 'PhabricatorUserDAO', 'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO', 'PhabricatorUserPreferences' => 'PhabricatorUserDAO', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserSSHKey' => 'PhabricatorUserDAO', 'PhabricatorUserSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorUserStatus' => 'PhabricatorUserDAO', 'PhabricatorUserStatusInvalidEpochException' => 'Exception', 'PhabricatorUserStatusOverlapException' => 'Exception', 'PhabricatorUserTestCase' => 'PhabricatorTestCase', 'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerArchiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO', 'PhabricatorWorkerLeaseQuery' => 'PhabricatorQuery', 'PhabricatorWorkerPermanentFailureException' => 'Exception', 'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController', 'PhabricatorWorkerTaskUpdateController' => 'PhabricatorDaemonController', 'PhabricatorWorkerTestCase' => 'PhabricatorTestCase', 'PhabricatorXHPASTViewController' => 'PhabricatorController', 'PhabricatorXHPASTViewDAO' => 'PhabricatorLiskDAO', 'PhabricatorXHPASTViewFrameController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewFramesetController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewInputController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHPASTViewPanelController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewParseTree' => 'PhabricatorXHPASTViewDAO', 'PhabricatorXHPASTViewRunController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewStreamController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHPASTViewTreeController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHProfController' => 'PhabricatorController', 'PhabricatorXHProfDAO' => 'PhabricatorLiskDAO', 'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController', 'PhabricatorXHProfProfileSymbolView' => 'PhabricatorXHProfProfileView', 'PhabricatorXHProfProfileTopLevelView' => 'PhabricatorXHProfProfileView', 'PhabricatorXHProfProfileView' => 'AphrontView', 'PhabricatorXHProfSample' => 'PhabricatorXHProfDAO', 'PhabricatorXHProfSampleListController' => 'PhabricatorXHProfController', 'PhabricatorXHProfSampleListView' => 'AphrontView', 'PhameBasicBlogSkin' => 'PhameBlogSkin', 'PhameBasicTemplateBlogSkin' => 'PhameBasicBlogSkin', 'PhameBlog' => array( 0 => 'PhameDAO', 1 => 'PhabricatorPolicyInterface', 2 => 'PhabricatorMarkupInterface', ), 'PhameBlogDeleteController' => 'PhameController', 'PhameBlogEditController' => 'PhameController', 'PhameBlogFeedController' => 'PhameController', 'PhameBlogListController' => 'PhameController', 'PhameBlogLiveController' => 'PhameController', 'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhameBlogSkin' => 'PhabricatorController', 'PhameBlogViewController' => 'PhameController', 'PhameController' => 'PhabricatorController', 'PhameDAO' => 'PhabricatorLiskDAO', 'PhamePost' => array( 0 => 'PhameDAO', 1 => 'PhabricatorPolicyInterface', 2 => 'PhabricatorMarkupInterface', ), 'PhamePostDeleteController' => 'PhameController', 'PhamePostEditController' => 'PhameController', 'PhamePostFramedController' => 'PhameController', 'PhamePostListController' => 'PhameController', 'PhamePostNewController' => 'PhameController', 'PhamePostNotLiveController' => 'PhameController', 'PhamePostPreviewController' => 'PhameController', 'PhamePostPublishController' => 'PhameController', 'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhamePostUnpublishController' => 'PhameController', 'PhamePostView' => 'AphrontView', 'PhamePostViewController' => 'PhameController', 'PhameResourceController' => 'CelerityResourceController', 'PholioController' => 'PhabricatorController', 'PholioDAO' => 'PhabricatorLiskDAO', 'PholioImage' => array( 0 => 'PholioDAO', 1 => 'PhabricatorMarkupInterface', ), 'PholioInlineCommentEditView' => 'AphrontView', 'PholioInlineCommentSaveView' => 'AphrontView', 'PholioInlineCommentView' => 'AphrontView', 'PholioInlineController' => 'PholioController', 'PholioInlineDeleteController' => 'PholioController', 'PholioInlineEditController' => 'PholioController', 'PholioInlineSaveController' => 'PholioController', 'PholioInlineViewController' => 'PholioController', 'PholioMock' => array( 0 => 'PholioDAO', 1 => 'PhabricatorMarkupInterface', 2 => 'PhabricatorPolicyInterface', 3 => 'PhabricatorSubscribableInterface', 4 => 'PhabricatorTokenReceiverInterface', 5 => 'PhabricatorApplicationTransactionInterface', ), 'PholioMockCommentController' => 'PholioController', 'PholioMockEditController' => 'PholioController', 'PholioMockEditor' => 'PhabricatorApplicationTransactionEditor', 'PholioMockEmbedView' => 'AphrontView', 'PholioMockImagesView' => 'AphrontView', 'PholioMockListController' => 'PholioController', 'PholioMockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PholioMockViewController' => 'PholioController', 'PholioRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PholioReplyHandler' => 'PhabricatorMailReplyHandler', 'PholioSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PholioTransaction' => 'PhabricatorApplicationTransaction', 'PholioTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PholioTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PholioTransactionType' => 'PholioConstants', 'PholioTransactionView' => 'PhabricatorApplicationTransactionView', 'PhortuneMonthYearExpiryControl' => 'AphrontFormControl', 'PhortuneStripeBaseController' => 'PhabricatorController', 'PhortuneStripePaymentFormView' => 'AphrontView', 'PhortuneStripeTestPaymentFormController' => 'PhortuneStripeBaseController', 'PhrictionActionConstants' => 'PhrictionConstants', 'PhrictionChangeType' => 'PhrictionConstants', 'PhrictionContent' => array( 0 => 'PhrictionDAO', 1 => 'PhabricatorMarkupInterface', ), 'PhrictionController' => 'PhabricatorController', 'PhrictionDAO' => 'PhabricatorLiskDAO', 'PhrictionDeleteController' => 'PhrictionController', 'PhrictionDiffController' => 'PhrictionController', 'PhrictionDocument' => array( 0 => 'PhrictionDAO', 1 => 'PhabricatorPolicyInterface', ), 'PhrictionDocumentController' => 'PhrictionController', 'PhrictionDocumentEditor' => 'PhabricatorEditor', 'PhrictionDocumentPreviewController' => 'PhrictionController', 'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhrictionDocumentStatus' => 'PhrictionConstants', 'PhrictionDocumentTestCase' => 'PhabricatorTestCase', 'PhrictionEditController' => 'PhrictionController', 'PhrictionHistoryController' => 'PhrictionController', 'PhrictionListController' => 'PhrictionController', 'PhrictionMoveController' => 'PhrictionController', 'PhrictionNewController' => 'PhrictionController', 'PhrictionRemarkupRule' => 'PhutilRemarkupRule', 'PhrictionSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PonderAddAnswerView' => 'AphrontView', 'PonderAddCommentView' => 'AphrontView', 'PonderAnswer' => array( 0 => 'PonderDAO', 1 => 'PhabricatorMarkupInterface', 2 => 'PonderVotableInterface', ), 'PonderAnswerEditor' => 'PhabricatorEditor', 'PonderAnswerListView' => 'AphrontView', 'PonderAnswerPreviewController' => 'PonderController', 'PonderAnswerQuery' => 'PhabricatorOffsetPagedQuery', 'PonderAnswerSaveController' => 'PonderController', 'PonderAnswerViewController' => 'PonderController', 'PonderAnsweredMail' => 'PonderMail', 'PonderComment' => array( 0 => 'PonderDAO', 1 => 'PhabricatorMarkupInterface', ), 'PonderCommentEditor' => 'PhabricatorEditor', 'PonderCommentListView' => 'AphrontView', 'PonderCommentMail' => 'PonderMail', 'PonderCommentQuery' => 'PhabricatorQuery', 'PonderCommentSaveController' => 'PonderController', 'PonderController' => 'PhabricatorController', 'PonderDAO' => 'PhabricatorLiskDAO', 'PonderFeedController' => 'PonderController', 'PonderMail' => 'PhabricatorMail', 'PonderMentionMail' => 'PonderMail', 'PonderPostBodyView' => 'AphrontView', 'PonderQuestion' => array( 0 => 'PonderDAO', 1 => 'PhabricatorMarkupInterface', 2 => 'PonderVotableInterface', 3 => 'PhabricatorSubscribableInterface', 4 => 'PhabricatorPolicyInterface', ), 'PonderQuestionAskController' => 'PonderController', 'PonderQuestionDetailView' => 'AphrontView', 'PonderQuestionEditor' => 'PhabricatorEditor', 'PonderQuestionPreviewController' => 'PonderController', 'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PonderQuestionSummaryView' => 'AphrontView', 'PonderQuestionViewController' => 'PonderController', 'PonderRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PonderReplyHandler' => 'PhabricatorMailReplyHandler', 'PonderSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PonderUserProfileView' => 'AphrontView', 'PonderVotableView' => 'AphrontView', 'PonderVoteEditor' => 'PhabricatorEditor', 'PonderVoteSaveController' => 'PonderController', 'QueryFormattingTestCase' => 'PhabricatorTestCase', + 'ReleephActiveProjectListView' => 'AphrontView', + 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephBranch' => 'ReleephDAO', + 'ReleephBranchAccessController' => 'ReleephController', + 'ReleephBranchBoxView' => 'AphrontView', + 'ReleephBranchCommitFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephBranchCreateController' => 'ReleephController', + 'ReleephBranchEditController' => 'ReleephController', + 'ReleephBranchEditor' => 'PhabricatorEditor', + 'ReleephBranchNamePreviewController' => 'PhabricatorController', + 'ReleephBranchPreviewView' => 'AphrontFormControl', + 'ReleephBranchViewController' => 'ReleephController', + 'ReleephCommitFinderException' => 'Exception', + 'ReleephCommitMessageFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephController' => 'PhabricatorController', + 'ReleephDAO' => 'PhabricatorLiskDAO', + 'ReleephDefaultFieldSelector' => 'ReleephFieldSelector', + 'ReleephDefaultUserView' => 'ReleephUserView', + 'ReleephDiffChurnFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephDiffMessageFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephDiffSizeFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephEvent' => 'ReleephDAO', + 'ReleephFieldParseException' => 'Exception', + 'ReleephFieldSpecificationIncompleteException' => 'Exception', + 'ReleephInactiveProjectListView' => 'AphrontView', + 'ReleephIntentFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephLevelFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephObjectHandleLoader' => 'ObjectHandleLoader', + 'ReleephOriginalCommitFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephProject' => 'ReleephDAO', + 'ReleephProjectActionController' => 'ReleephController', + 'ReleephProjectCreateController' => 'ReleephController', + 'ReleephProjectEditController' => 'ReleephController', + 'ReleephProjectListController' => 'PhabricatorController', + 'ReleephProjectView' => 'AphrontView', + 'ReleephProjectViewController' => 'ReleephController', + 'ReleephReasonFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephRequest' => 'ReleephDAO', + 'ReleephRequestActionController' => 'ReleephController', + 'ReleephRequestCreateController' => 'ReleephController', + 'ReleephRequestDifferentialCreateController' => 'ReleephController', + 'ReleephRequestEditController' => 'ReleephController', + 'ReleephRequestEditor' => 'PhabricatorEditor', + 'ReleephRequestEvent' => 'ReleephDAO', + 'ReleephRequestEventListView' => 'AphrontView', + 'ReleephRequestException' => 'Exception', + 'ReleephRequestHeaderListView' => 'AphrontView', + 'ReleephRequestHeaderView' => 'AphrontView', + 'ReleephRequestIntentsView' => 'AphrontView', + 'ReleephRequestStatusView' => 'AphrontView', + 'ReleephRequestTypeaheadControl' => 'AphrontFormControl', + 'ReleephRequestTypeaheadController' => 'PhabricatorTypeaheadDatasourceController', + 'ReleephRequestViewController' => 'ReleephController', + 'ReleephRequestorFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephRevisionFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephRiskFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephSeverityFieldSpecification' => 'ReleephLevelFieldSpecification', + 'ReleephStatusFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephSummaryFieldSpecification' => 'ReleephFieldSpecification', + 'ReleephUserView' => 'AphrontView', ), )); diff --git a/src/applications/releeph/ReleephObjectHandleLoader.php b/src/applications/releeph/ReleephObjectHandleLoader.php new file mode 100644 index 000000000..553ead7a5 --- /dev/null +++ b/src/applications/releeph/ReleephObjectHandleLoader.php @@ -0,0 +1,92 @@ +<?php + +final class ReleephObjectHandleLoader extends ObjectHandleLoader { + + /** + * The intention for phid.external-loaders is for each new 4-char PHID type + * to point to a different external loader for that type. + * + * For brevity, we instead just have this one class that can load any type of + * Releeph PHID. + */ + + public function loadHandles(array $phids) { + $types = array(); + + foreach ($phids as $phid) { + $type = phid_get_type($phid); + $types[$type][] = $phid; + } + + $handles = array(); + + foreach ($types as $type => $phids) { + switch ($type) { + case ReleephPHIDConstants::PHID_TYPE_RERQ: + $object = new ReleephRequest(); + + $instances = $object->loadAllWhere('phid in (%Ls)', $phids); + $instances = mpull($instances, null, 'getPHID'); + + foreach ($phids as $phid) { + $instance = $instances[$phid]; + $handle = new PhabricatorObjectHandle(); + $handle->setPHID($phid); + $handle->setType($type); + $handle->setURI('/RQ'.$instance->getID()); + + $name = 'RQ'.$instance->getID(); + $handle->setName($name); + $handle->setFullName($name.': '.$instance->getSummaryForDisplay()); + $handle->setComplete(true); + + $handles[$phid] = $handle; + } + break; + + case ReleephPHIDConstants::PHID_TYPE_REBR: + $object = new ReleephBranch(); + + $branches = $object->loadAllWhere('phid IN (%Ls)', $phids); + $branches = mpull($branches, null, 'getPHID'); + + foreach ($phids as $phid) { + $branch = $branches[$phid]; + $handle = new PhabricatorObjectHandle(); + $handle->setPHID($phid); + $handle->setType($type); + $handle->setURI($branch->getURI()); + $handle->setName($branch->getBasename()); + $handle->setFullName($branch->getName()); + $handle->setComplete(true); + $handles[$phid] = $handle; + } + break; + + case ReleephPHIDConstants::PHID_TYPE_REPR: + $object = new ReleephProject(); + + $instances = $object->loadAllWhere('phid IN (%Ls)', $phids); + $instances = mpull($instances, null, 'getPHID'); + + foreach ($phids as $phid) { + $instance = $instances[$phid]; + $handle = new PhabricatorObjectHandle(); + $handle->setPHID($phid); + $handle->setType($type); + $handle->setURI($instance->getURI()); + $handle->setName($instance->getName()); // no fullName for proejcts + $handle->setComplete(true); + $handles[$phid] = $handle; + } + break; + + default: + throw new Exception('unknown type '.$type); + } + } + + return $handles; + } + +} diff --git a/src/applications/releeph/ReleephPHIDConstants.php b/src/applications/releeph/ReleephPHIDConstants.php new file mode 100644 index 000000000..6265da6c8 --- /dev/null +++ b/src/applications/releeph/ReleephPHIDConstants.php @@ -0,0 +1,9 @@ +<?php + +final class ReleephPHIDConstants { + + // Releeph + const PHID_TYPE_REPR = 'REPR'; + const PHID_TYPE_REBR = 'REBR'; + const PHID_TYPE_RERQ = 'RERQ'; +} diff --git a/src/applications/releeph/application/PhabricatorApplicationReleeph.php b/src/applications/releeph/application/PhabricatorApplicationReleeph.php new file mode 100644 index 000000000..4512ba0d6 --- /dev/null +++ b/src/applications/releeph/application/PhabricatorApplicationReleeph.php @@ -0,0 +1,86 @@ +<?php + +final class PhabricatorApplicationReleeph extends PhabricatorApplication { + + public function getName() { + return 'Releeph'; + } + + public function getShortDescription() { + return 'Release Branches'; + } + + public function getBaseURI() { + return '/releeph/'; + } + + public function getAutospriteName() { + return 'releeph'; + } + + public function getApplicationGroup() { + return self::GROUP_ORGANIZATION; + } + + public function isInstalled() { + if (PhabricatorEnv::getEnvConfig('releeph.installed')) { + return parent::isInstalled(); + } + return false; + } + + public function getRoutes() { + return array( + '/RQ(?P<requestID>[1-9]\d*)' => 'ReleephRequestViewController', + '/releeph/' => array( + '' => 'ReleephProjectListController', + 'project/' => array( + '' => 'ReleephProjectListController', + 'inactive/' => 'ReleephProjectListController', + 'create/' => 'ReleephProjectCreateController', + '(?P<projectID>[1-9]\d*)/' => array( + '' => 'ReleephProjectViewController', + 'closedbranches/' => 'ReleephProjectViewController', + 'edit/' => 'ReleephProjectEditController', + 'cutbranch/' => 'ReleephBranchCreateController', + 'action/(?P<action>.+)/' => 'ReleephProjectActionController', + ), + ), + 'branch/' => array( + 'edit/(?P<branchID>[1-9]\d*)/' => + 'ReleephBranchEditController', + '(?P<action>close|re-open)/(?P<branchID>[1-9]\d*)/' => + 'ReleephBranchAccessController', + 'preview/' => 'ReleephBranchNamePreviewController', + + // Left in, just in case the by-name stuff fails! + '(?P<branchID>[^/]+)/' => + 'ReleephBranchViewController', + ), + 'request/' => array( + '(?P<requestID>[1-9]\d*)/' => 'ReleephRequestViewController', + 'create/' => 'ReleephRequestCreateController', + 'differentialcreate/' => array( + 'D(?P<diffRevID>[1-9]\d*)' => + 'ReleephRequestDifferentialCreateController', + ), + 'edit/(?P<requestID>[1-9]\d*)/' => + 'ReleephRequestEditController', + 'action/(?P<action>.+)/(?P<requestID>[1-9]\d*)/' => + 'ReleephRequestActionController', + 'typeahead/' => + 'ReleephRequestTypeaheadController', + ), + + // Branch navigation made pretty, as it's the most common: + '(?P<projectName>[^/]+)/(?P<branchName>[^/]+)/' => array( + '' => 'ReleephBranchViewController', + 'edit/' => 'ReleephBranchEditController', + 'request/' => 'ReleephRequestCreateController', + '(?P<action>close|re-open)/' => 'ReleephBranchAccessController', + ), + ) + ); + } + +} diff --git a/src/applications/releeph/commitfinder/ReleephCommitFinder.php b/src/applications/releeph/commitfinder/ReleephCommitFinder.php new file mode 100644 index 000000000..321294441 --- /dev/null +++ b/src/applications/releeph/commitfinder/ReleephCommitFinder.php @@ -0,0 +1,74 @@ +<?php + +final class ReleephCommitFinder { + + private $releephProject; + + public function setReleephProject(ReleephProject $rp) { + $this->releephProject = $rp; + return $this; + } + + public function fromPartial($partial_string) { + // Look for diffs + $matches = array(); + if (preg_match('/^D([1-9]\d*)$/', $partial_string, $matches)) { + $diff_id = $matches[1]; + $diff_rev = id(new DifferentialRevision())->load($diff_id); + if (!$diff_rev) { + throw new ReleephCommitFinderException( + "{$partial_string} does not refer to an existing diff."); + } + $commit_phids = $diff_rev->loadCommitPHIDs(); + + if (!$commit_phids) { + throw new ReleephCommitFinderException( + "{$partial_string} has no commits associated with it yet."); + } + + $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere( + 'phid IN (%Ls) ORDER BY epoch ASC', + $commit_phids); + return head($commits); + } + + // Look for a raw commit number, or r<callsign><commit-number>. + $repository = $this->releephProject->loadPhabricatorRepository(); + $dr_data = null; + $matches = array(); + if (preg_match('/^r(?P<callsign>[A-Z]+)(?P<commit>\w+)$/', + $partial_string, $matches)) { + $callsign = $matches['callsign']; + if ($callsign != $repository->getCallsign()) { + throw new ReleephCommitFinderException(sprintf( + "%s is in a different repository to this Releeph project (%s).", + $partial_string, + $repository->getCallsign())); + } else { + $dr_data = $matches; + } + } else { + $dr_data = array( + 'callsign' => $repository->getCallsign(), + 'commit' => $partial_string + ); + } + + try { + $dr = DiffusionRequest::newFromDictionary($dr_data); + } catch (Exception $ex) { + $message = "No commit matches {$partial_string}: ".$ex->getMessage(); + throw new ReleephCommitFinderException($message); + } + + $phabricator_repository_commit = $dr->loadCommit(); + + if (!$phabricator_repository_commit) { + throw new ReleephCommitFinderException( + "The commit {$partial_string} doesn't exist in this repository."); + } + + return $phabricator_repository_commit; + } + +} diff --git a/src/applications/releeph/commitfinder/ReleephCommitFinderException.php b/src/applications/releeph/commitfinder/ReleephCommitFinderException.php new file mode 100644 index 000000000..8250de592 --- /dev/null +++ b/src/applications/releeph/commitfinder/ReleephCommitFinderException.php @@ -0,0 +1,3 @@ +<?php + +final class ReleephCommitFinderException extends Exception {} diff --git a/src/applications/releeph/conduit/ConduitAPI_releeph_Method.php b/src/applications/releeph/conduit/ConduitAPI_releeph_Method.php new file mode 100644 index 000000000..7d5d9aa08 --- /dev/null +++ b/src/applications/releeph/conduit/ConduitAPI_releeph_Method.php @@ -0,0 +1,9 @@ +<?php + +abstract class ConduitAPI_releeph_Method extends ConduitAPIMethod { + + public function getApplication() { + return PhabricatorApplication::getByClass('PhabricatorApplicationReleeph'); + } + +} diff --git a/src/applications/releeph/conduit/ConduitAPI_releeph_getbranches_Method.php b/src/applications/releeph/conduit/ConduitAPI_releeph_getbranches_Method.php new file mode 100644 index 000000000..d7a76e842 --- /dev/null +++ b/src/applications/releeph/conduit/ConduitAPI_releeph_getbranches_Method.php @@ -0,0 +1,62 @@ +<?php + +final class ConduitAPI_releeph_getbranches_Method + extends ConduitAPI_releeph_Method { + + public function getMethodDescription() { + return "Return information about all active Releeph branches."; + } + + public function defineParamTypes() { + return array( + ); + } + + public function defineReturnType() { + return 'nonempty list<dict<string, wild>>'; + } + + public function defineErrorTypes() { + return array( + ); + } + + protected function execute(ConduitAPIRequest $request) { + $results = array(); + + $projects = id(new ReleephProject())->loadAllWhere('isActive = 1'); + + foreach ($projects as $project) { + $repository = $project->loadOneRelative( + id(new PhabricatorRepository()), + 'id', + 'getRepositoryID'); + + $branches = $project->loadRelatives( + id(new ReleephBranch()), + 'releephProjectID', + 'getID', + 'isActive = 1'); + + foreach ($branches as $branch) { + $full_branch_name = $branch->getName(); + + $cut_point_commit = $branch->loadOneRelative( + id(new PhabricatorRepositoryCommit()), + 'phid', + 'getCutPointCommitPHID'); + + $results[] = array( + 'project' => $project->getName(), + 'repository' => $repository->getCallsign(), + 'branch' => $branch->getBasename(), + 'fullBranchName' => $full_branch_name, + 'symbolicName' => $branch->getSymbolicName(), + 'cutPoint' => $branch->getCutPointCommitIdentifier(), + ); + } + } + + return $results; + } +} diff --git a/src/applications/releeph/conduit/ConduitAPI_releeph_projectinfo_Method.php b/src/applications/releeph/conduit/ConduitAPI_releeph_projectinfo_Method.php new file mode 100644 index 000000000..950e62953 --- /dev/null +++ b/src/applications/releeph/conduit/ConduitAPI_releeph_projectinfo_Method.php @@ -0,0 +1,96 @@ +<?php + +final class ConduitAPI_releeph_projectinfo_Method + extends ConduitAPI_releeph_Method { + + public function getMethodDescription() { + return + "Fetch information about all Releeph projects ". + "for a given Arcanist project."; + } + + public function defineParamTypes() { + return array( + 'arcProjectName' => 'optional string', + ); + } + + public function defineReturnType() { + return 'dict<string, wild>'; + } + + public function defineErrorTypes() { + return array( + "ERR_UNKNOWN_ARC" => + "The given Arcanist project name doesn't exist in the ". + "installation of Phabricator you are accessing.", + ); + } + + protected function execute(ConduitAPIRequest $request) { + $arc_project_name = $request->getValue('arcProjectName'); + if ($arc_project_name) { + $arc_project = id(new PhabricatorRepositoryArcanistProject()) + ->loadOneWhere('name = %s', $arc_project_name); + if (!$arc_project) { + throw id(new ConduitException("ERR_UNKNOWN_ARC")) + ->setErrorDescription( + "Unknown Arcanist project '{$arc_project_name}': ". + "are you using the correct Conduit URI?"); + } + + $releeph_projects = id(new ReleephProject()) + ->loadAllWhere('arcanistProjectID = %d', $arc_project->getID()); + } else { + $releeph_projects = id(new ReleephProject())->loadAll(); + } + + $releeph_projects = mfilter($releeph_projects, 'getIsActive'); + + $result = array(); + foreach ($releeph_projects as $releeph_project) { + $selector = $releeph_project->getReleephFieldSelector(); + $fields = $selector->getFieldSpecifications(); + + $fields_info = array(); + foreach ($fields as $field) { + $field->setReleephProject($releeph_project); + if ($field->isEditable()) { + $key = $field->getKeyForConduit(); + $fields_info[$key] = array( + 'class' => get_class($field), + 'name' => $field->getName(), + 'key' => $key, + 'arcHelp' => $field->renderHelpForArcanist(), + ); + } + } + + $releeph_branches = mfilter( + id(new ReleephBranch()) + ->loadAllWhere('releephProjectID = %d', $releeph_project->getID()), + 'getIsActive'); + + $releeph_branches_struct = array(); + foreach ($releeph_branches as $branch) { + $releeph_branches_struct[] = array( + 'branchName' => $branch->getName(), + 'projectName' => $releeph_project->getName(), + 'projectPHID' => $releeph_project->getPHID(), + 'branchPHID' => $branch->getPHID(), + ); + } + + $result[] = array( + 'projectName' => $releeph_project->getName(), + 'projectPHID' => $releeph_project->getPHID(), + 'branches' => $releeph_branches_struct, + 'fields' => $fields_info, + ); + } + + return $result; + } + + +} diff --git a/src/applications/releeph/conduit/ConduitAPI_releeph_request_Method.php b/src/applications/releeph/conduit/ConduitAPI_releeph_request_Method.php new file mode 100644 index 000000000..68b2a3010 --- /dev/null +++ b/src/applications/releeph/conduit/ConduitAPI_releeph_request_Method.php @@ -0,0 +1,130 @@ +<?php + +final class ConduitAPI_releeph_request_Method + extends ConduitAPI_releeph_Method { + + public function getMethodDescription() { + return "Request a commit or diff to be picked to a branch."; + } + + public function defineParamTypes() { + return array( + 'branchPHID' => 'required string', + 'things' => 'required string', + 'fields' => 'dict<string, string>', + ); + } + + public function defineReturnType() { + return 'dict<string, wild>'; + } + + public function defineErrorTypes() { + return array( + "ERR_BRANCH" => 'Unknown Releeph branch.', + "ERR_FIELD_PARSE" => 'Unable to parse a Releeph field.', + ); + } + + protected function execute(ConduitAPIRequest $request) { + $branch_phid = $request->getValue('branchPHID'); + $releeph_branch = id(new ReleephBranch()) + ->loadOneWhere('phid = %s', $branch_phid); + + if (!$releeph_branch) { + throw id(new ConduitException("ERR_BRANCH"))->setErrorDescription( + "No ReleephBranch found with PHID {$branch_phid}!"); + } + + $releeph_project = $releeph_branch->loadReleephProject(); + + // Find the requested commit identifiers + $requested_commits = array(); + $things = $request->getValue('things'); + $finder = id(new ReleephCommitFinder()) + ->setReleephProject($releeph_project); + foreach ($things as $thing) { + try { + $requested_commits[$thing] = $finder->fromPartial($thing); + } catch (ReleephCommitFinderException $ex) { + throw id(new ConduitException('ERR_NO_MATCHES')) + ->setErrorDescription($ex->getMessage()); + } + } + + // Find any existing requests that clash on the commit id, for this branch + $existing_releeph_requests = id(new ReleephRequest())->loadAllWhere( + 'requestCommitPHID IN (%Ls) AND branchID = %d', + mpull($requested_commits, 'getPHID'), + $releeph_branch->getID()); + $existing_releeph_requests = mpull( + $existing_releeph_requests, + null, + 'getRequestCommitPHID'); + + $selector = $releeph_project->getReleephFieldSelector(); + $fields = $selector->getFieldSpecifications(); + foreach ($fields as $field) { + $field + ->setReleephProject($releeph_project) + ->setReleephBranch($releeph_branch); + } + + $results = array(); + foreach ($requested_commits as $thing => $commit) { + $phid = $commit->getPHID(); + $handles = id(new PhabricatorObjectHandleData(array($phid))) + ->setViewer($request->getUser()) + ->loadHandles(); + $name = id($handles[$phid])->getName(); + + $releeph_request = null; + + $existing_releeph_request = idx($existing_releeph_requests, $phid); + if ($existing_releeph_request) { + $releeph_request = $existing_releeph_request; + } else { + $releeph_request = new ReleephRequest(); + foreach ($fields as $field) { + if (!$field->isEditable()) { + continue; + } + $field->setReleephRequest($releeph_request); + try { + $field->setValueFromConduitAPIRequest($request); + } catch (ReleephFieldParseException $ex) { + throw id(new ConduitException('ERR_FIELD_PARSE')) + ->setErrorDescription($ex->getMessage()); + } + } + id(new ReleephRequestEditor($releeph_request)) + ->setActor($request->getUser()) + ->create($commit, $releeph_branch); + } + + $releeph_branch->populateReleephRequestHandles( + $request->getUser(), + array($releeph_request)); + $rq_handles = $releeph_request->getHandles(); + $requestor_phid = $releeph_request->getRequestUserPHID(); + $requestor = $rq_handles[$requestor_phid]->getName(); + + $url = PhabricatorEnv::getProductionURI('/RQ'.$releeph_request->getID()); + + $results[$thing] = array( + 'thing' => $thing, + 'branch' => $releeph_branch->getDisplayNameWithDetail(), + 'commitName' => $name, + 'commitID' => $commit->getCommitIdentifier(), + 'url' => $url, + 'requestID' => $releeph_request->getID(), + 'requestor' => $requestor, + 'requestTime' => $releeph_request->getDateCreated(), + 'existing' => $existing_releeph_request !== null, + ); + } + + return $results; + } + +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_canpush_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_canpush_Method.php new file mode 100644 index 000000000..d37bf8529 --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_canpush_Method.php @@ -0,0 +1,39 @@ +<?php + +final class ConduitAPI_releephwork_canpush_Method + extends ConduitAPI_releeph_Method { + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return "Return whether the conduit user is allowed to push."; + } + + public function defineParamTypes() { + return array( + 'projectPHID' => 'required string', + ); + } + + public function defineReturnType() { + return 'bool'; + } + + public function defineErrorTypes() { + return array(); + } + + protected function execute(ConduitAPIRequest $request) { + $releeph_project = id(new ReleephProject()) + ->loadOneWhere('phid = %s', $request->getValue('projectPHID')); + + if (!$releeph_project->getPushers()) { + return true; + } else { + $user = $request->getUser(); + return $releeph_project->isPusher($user); + } + } +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getauthorinfo_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getauthorinfo_Method.php new file mode 100644 index 000000000..62b594c78 --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getauthorinfo_Method.php @@ -0,0 +1,43 @@ +<?php + +final class ConduitAPI_releephwork_getauthorinfo_Method + extends ConduitAPI_releeph_Method { + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return "Return a string to use as the VCS author."; + } + + public function defineParamTypes() { + return array( + 'userPHID' => 'required string', + 'vcsType' => 'required string', + ); + } + + public function defineReturnType() { + return 'nonempty string'; + } + + public function defineErrorTypes() { + return array(); + } + + protected function execute(ConduitAPIRequest $request) { + $user = id(new PhabricatorUser()) + ->loadOneWhere('phid = %s', $request->getValue('userPHID')); + + $email = $user->loadPrimaryEmailAddress(); + if (is_numeric($email)) { + $email = $user->getUserName().'@fb.com'; + } + + return sprintf( + '%s <%s>', + $user->getRealName(), + $email); + } +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranch_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranch_Method.php new file mode 100644 index 000000000..9b9f57e40 --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranch_Method.php @@ -0,0 +1,52 @@ +<?php + +final class ConduitAPI_releephwork_getbranch_Method + extends ConduitAPI_releeph_Method { + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return "Return information to help checkout / cut a Releeph branch."; + } + + public function defineParamTypes() { + return array( + 'branchPHID' => 'required string', + ); + } + + public function defineReturnType() { + return 'dict<string, wild>'; + } + + public function defineErrorTypes() { + return array(); + } + + protected function execute(ConduitAPIRequest $request) { + $branch = id(new ReleephBranch()) + ->loadOneWhere('phid = %s', $request->getValue('branchPHID')); + + $cut_phid = $branch->getCutPointCommitPHID(); + $phids = array($cut_phid); + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($request->getUser()) + ->loadHandles(); + + $project = $branch->loadReleephProject(); + $repo = $project->loadPhabricatorRepository(); + + return array( + 'branchName' => $branch->getName(), + 'branchPHID' => $branch->getPHID(), + 'vcsType' => $repo->getVersionControlSystem(), + 'cutCommitID' => $branch->getCutPointCommitIdentifier(), + 'cutCommitName' => $handles[$cut_phid]->getName(), + 'creatorPHID' => $branch->getCreatedByUserPHID(), + 'trunk' => $project->getTrunkBranch(), + ); + } + +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php new file mode 100644 index 000000000..5549591fc --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php @@ -0,0 +1,94 @@ +<?php + +final class ConduitAPI_releephwork_getbranchcommitmessage_Method + extends ConduitAPI_releeph_Method { + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return "Get a commit message for committing a Releeph branch."; + } + + public function defineParamTypes() { + return array( + 'branchPHID' => 'required string', + ); + } + + public function defineReturnType() { + return 'nonempty string'; + } + + public function defineErrorTypes() { + return array(); + } + + protected function execute(ConduitAPIRequest $request) { + $branch = id(new ReleephBranch()) + ->loadOneWhere('phid = %s', $request->getValue('branchPHID')); + + $project = $branch->loadReleephProject(); + + $creator_phid = $branch->getCreatedByUserPHID(); + $cut_phid = $branch->getCutPointCommitPHID(); + + $phids = array( + $branch->getPHID(), + $project->getPHID(), + $creator_phid, + $cut_phid, + ); + + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($request->getUser()) + ->loadHandles(); + + $h_branch = $handles[$branch->getPHID()]; + $h_project = $handles[$project->getPHID()]; + + // Not as customizable as a ReleephRequest's commit message. It doesn't + // really need to be. + $commit_message = array(); + $commit_message[] = $h_branch->getFullName(); + $commit_message[] = $h_branch->getURI(); + + $commit_message[] = "Cut Point: ".$handles[$cut_phid]->getName(); + + $cut_point_pr_commit = id(new PhabricatorRepositoryCommit()) + ->loadOneWhere('phid = %s', $cut_phid); + $cut_point_commit_date = strftime( + '%Y-%m-%d %H:%M:%S%z', + $cut_point_pr_commit->getEpoch()); + $commit_message[] = "Cut Point Date: {$cut_point_commit_date}"; + + $commit_message[] = "Created By: ".$handles[$creator_phid]->getName(); + + $project_uri = $project->getURI(); + $commit_message[] = "Project: ".$h_project->getName()." ".$project_uri; + + /** + * Required for 090-limit_new_branch_creations.sh in + * admin/scripts/git/hosting/hooks/update.d (in the E repo): + * + * http://fburl.com/2372545 + * + * The commit message must have a line saying: + * + * @new-branch: <branch-name> + * + */ + $repo = $project->loadPhabricatorRepository(); + switch ($repo->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $commit_message[] = sprintf( + '@new-branch: %s', + $branch->getName()); + break; + } + + return implode("\n\n", $commit_message); + } + +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php new file mode 100644 index 000000000..324136957 --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php @@ -0,0 +1,90 @@ +<?php + +final class ConduitAPI_releephwork_getcommitmessage_Method + extends ConduitAPI_releeph_Method { + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return + "Get commit message components for building ". + "a ReleephRequest commit message."; + } + + public function defineParamTypes() { + return array( + 'requestPHID' => 'required string', + 'action' => 'required enum<"pick", "revert">', + ); + } + + public function defineReturnType() { + return 'dict<string, string>'; + } + + public function defineErrorTypes() { + return array(); + } + + protected function execute(ConduitAPIRequest $request) { + $releeph_request = id(new ReleephRequest()) + ->loadOneWhere('phid = %s', $request->getValue('requestPHID')); + + $action = $request->getValue('action'); + + $title = $releeph_request->getSummaryForDisplay(); + + $commit_message = array(); + + $project = $releeph_request->loadReleephProject(); + $branch = $releeph_request->loadReleephBranch(); + + $selector = $project->getReleephFieldSelector(); + $fields = $selector->getFieldSpecifications(); + $fields = $selector->sortFieldsForCommitMessage($fields); + + foreach ($fields as $field) { + $field + ->setUser($request->getUser()) + ->setReleephProject($project) + ->setReleephBranch($branch) + ->setReleephRequest($releeph_request); + + $label = null; + $value = null; + + switch ($action) { + case 'pick': + if ($field->shouldAppearOnCommitMessage()) { + $label = $field->renderLabelForCommitMessage(); + $value = $field->renderValueForCommitMessage(); + } + break; + + case 'revert': + if ($field->shouldAppearOnRevertMessage()) { + $label = $field->renderLabelForRevertMessage(); + $value = $field->renderValueForRevertMessage(); + } + break; + } + + if ($label && $value) { + if (strpos($value, "\n") !== false || + substr($value, 0, 2) === ' ') { + $commit_message[] = "{$label}:\n{$value}"; + } else { + $commit_message[] = "{$label}: {$value}"; + } + } + } + + return array( + 'title' => $title, + 'body' => implode("\n\n", $commit_message), + ); + } + +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getorigcommitmessage_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getorigcommitmessage_Method.php new file mode 100644 index 000000000..4c6efe55e --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getorigcommitmessage_Method.php @@ -0,0 +1,35 @@ +<?php + +final class ConduitAPI_releephwork_getorigcommitmessage_Method + extends ConduitAPI_releeph_Method { + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return "Return the original commit message for the given commit."; + } + + public function defineParamTypes() { + return array( + 'commitPHID' => 'required string', + ); + } + + public function defineReturnType() { + return 'nonempty string'; + } + + public function defineErrorTypes() { + return array(); + } + + protected function execute(ConduitAPIRequest $request) { + $commit = id(new PhabricatorRepositoryCommit()) + ->loadOneWhere('phid = %s', $request->getValue('commitPHID')); + $commit_data = $commit->loadCommitData(); + $commit_message = $commit_data->getCommitMessage(); + return trim($commit_message); + } +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php new file mode 100644 index 000000000..c17dbbdcb --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php @@ -0,0 +1,208 @@ +<?php + +final class ConduitAPI_releephwork_nextrequest_Method + extends ConduitAPI_releeph_Method { + + private $project; + private $branch; + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return + "Return info required to cut a branch, ". + "and pick and revert ReleephRequests"; + } + + public function defineParamTypes() { + return array( + 'branchPHID' => 'required int', + 'seen' => 'required list<string, bool>', + ); + } + + public function defineReturnType() { + return ''; + } + + public function defineErrorTypes() { + return array( + 'ERR-NOT-PUSHER' => + 'You are not listed as a pusher for thie Releeph project!', + ); + } + + protected function execute(ConduitAPIRequest $request) { + $seen = $request->getValue('seen'); + + $branch = id(new ReleephBranch()) + ->loadOneWhere('phid = %s', $request->getValue('branchPHID')); + + $project = $branch->loadReleephProject(); + + $needs_pick = array(); + $needs_revert = array(); + + $releeph_requests = $branch->loadReleephRequests($request->getUser()); + + foreach ($releeph_requests as $candidate) { + $phid = $candidate->getPHID(); + if (idx($seen, $phid)) { + continue; + } + + $should = $candidate->shouldBeInBranch(); + $in = $candidate->getInBranch(); + if ($should && !$in) { + $needs_pick[] = $candidate; + } + if (!$should && $in) { + $needs_revert[] = $candidate; + } + } + + /** + * Sort both needs_pick and needs_revert in ascending commit order, as + * discovered by Phabricator (using the `id` column to perform that + * ordering). + * + * This is easy for $needs_pick as the ordinal is stored. It is hard for + * reverts, as we have to look that information up. + */ + $needs_pick = msort($needs_pick, 'getRequestCommitOrdinal'); + $needs_revert = $this->sortReverts($needs_revert); + + /** + * Do reverts first in reverse order, then the picks in original-commit + * order. + * + * This seems like the correct thing to do, but there may be a better + * algorithm for the releephwork.nextrequest Conduit call that orders + * things better. + * + * We could also button-mash our way through everything that failed (at the + * end of the run) to try failed things again. + */ + $releeph_request = null; + $action = null; + if ($needs_revert) { + $releeph_request = last($needs_revert); + $action = 'revert'; + $commit_id = $releeph_request->getCommitIdentifier(); + $commit_phid = $releeph_request->getCommitPHID(); + } elseif ($needs_pick) { + $releeph_request = head($needs_pick); + $action = 'pick'; + $commit_id = $releeph_request->getRequestCommitIdentifier(); + $commit_phid = $releeph_request->getRequestCommitPHID(); + } else { + // Return early if there's nothing to do! + return array(); + } + + // Build the response + $phids = array(); + $phids[] = $commit_phid; + + $diff_phid = null; + $diff_rev_id = null; + $diff_rev = $releeph_request->loadDifferentialRevision(); + if ($diff_rev) { + $diff_phid = $diff_rev->getPHID(); + $phids[] = $diff_phid; + $diff_rev_id = $diff_rev->getID(); + } + + $phids[] = $releeph_request->getPHID(); + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($request->getUser()) + ->loadHandles(); + + $diff_name = null; + if ($diff_rev) { + $diff_name = $handles[$diff_phid]->getName(); + } + + // Calculate the new-author information (if any) + $new_author = null; + $new_author_phid = null; + switch ($project->getDetail('commitWithAuthor')) { + case ReleephProject::COMMIT_AUTHOR_NONE: + break; + + case ReleephProject::COMMIT_AUTHOR_FROM_DIFF: + if ($diff_rev) { + $new_author_phid = $diff_rev->getAuthorPHID(); + } else { + $pr_commit = $releeph_request->loadPhabricatorRepositoryCommit(); + if ($pr_commit) { + $new_author_phid = $pr_commit->getAuthorPHID(); + } + } + break; + + case ReleephProject::COMMIT_AUTHOR_REQUESTOR: + $new_author_phid = $releeph_request->getRequestUserPHID(); + break; + } + + return array( + 'requestID' => $releeph_request->getID(), + 'requestPHID' => $releeph_request->getPHID(), + 'requestName' => $handles[$releeph_request->getPHID()]->getName(), + 'requestorPHID' => $releeph_request->getRequestUserPHID(), + 'action' => $action, + 'diffRevID' => $diff_rev_id, + 'diffName' => $diff_name, + 'commitIdentifier' => $commit_id, + 'commitPHID' => $commit_phid, + 'commitName' => $handles[$commit_phid]->getName(), + 'needsRevert' => mpull($needs_revert, 'getID'), + 'needsPick' => mpull($needs_pick, 'getID'), + 'newAuthorPHID' => $new_author_phid, + ); + } + + /** + * Sort an array of ReleephRequests, that have been picked into a branch, in + * the order in which they were picked to the branch. + */ + private function sortReverts(array $releeph_requests) { + if (!$releeph_requests) { + return array(); + } + + // ReleephRequests, keyed by <branch-commit-id> + $releeph_requests = mpull($releeph_requests, null, 'getCommitIdentifier'); + + $commits = id(new PhabricatorRepositoryCommit()) + ->loadAllWhere( + 'commitIdentifier IN (%Ls)', + mpull($releeph_requests, 'getCommitIdentifier')); + + // A map of <branch-commit-id> => <branch-commit-ordinal> + $surrogate = mpull($commits, 'getID', 'getCommitIdentifier'); + + $unparsed = array(); + $result = array(); + + foreach ($releeph_requests as $commit_id => $releeph_request) { + $ordinal = idx($surrogate, $commit_id); + if ($ordinal) { + $result[$ordinal] = $releeph_request; + } else { + $unparsed[] = $releeph_request; + } + } + + // Sort $result in ascending order + ksort($result); + + // Unparsed commits we'll just have to guess, based on time + $unparsed = msort($unparsed, 'getDateModified'); + + return array_merge($result, $unparsed); + } +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_record_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_record_Method.php new file mode 100644 index 000000000..0b8bd3a1a --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_record_Method.php @@ -0,0 +1,42 @@ +<?php + +final class ConduitAPI_releephwork_record_Method + extends ConduitAPI_releeph_Method { + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return "Wrapper to ReleephRequestEditor->recordSuccessfulCommit()."; + } + + public function defineParamTypes() { + return array( + 'requestPHID' => 'required string', + 'action' => 'required enum<"pick", "revert">', + 'commitIdentifier' => 'required string', + ); + } + + public function defineReturnType() { + return 'void'; + } + + public function defineErrorTypes() { + return array(); + } + + protected function execute(ConduitAPIRequest $request) { + $action = $request->getValue('action'); + $new_commit_id = $request->getValue('commitIdentifier'); + + $releeph_request = id(new ReleephRequest()) + ->loadOneWhere('phid = %s', $request->getValue('requestPHID')); + + id(new ReleephRequestEditor($releeph_request)) + ->setActor($request->getUser()) + ->recordSuccessfulCommit($action, $new_commit_id); + } + +} diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_recordpickstatus_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_recordpickstatus_Method.php new file mode 100644 index 000000000..93fbcee06 --- /dev/null +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_recordpickstatus_Method.php @@ -0,0 +1,63 @@ +<?php + +final class ConduitAPI_releephwork_recordpickstatus_Method + extends ConduitAPI_releeph_Method { + + public function getMethodStatus() { + return self::METHOD_STATUS_UNSTABLE; + } + + public function getMethodDescription() { + return "Wrapper to ReleephRequestEditor->changePickStatus()."; + } + + public function defineParamTypes() { + return array( + 'requestPHID' => 'required string', + 'action' => 'required enum<"pick", "revert">', + 'ok' => 'required bool', + 'dryRun' => 'optional bool', + 'details' => 'optional dict<string, wild>', + ); + } + + public function defineReturnType() { + return ''; + } + + public function defineErrorTypes() { + return array(); + } + + protected function execute(ConduitAPIRequest $request) { + $action = $request->getValue('action'); + $ok = $request->getValue('ok'); + $dry_run = $request->getValue('dryRun'); + $details = $request->getValue('details', array()); + + switch ($request->getValue('action')) { + case 'pick': + $pick_status = $ok + ? ReleephRequest::PICK_OK + : ReleephRequest::PICK_FAILED; + break; + + case 'revert': + $pick_status = $ok + ? ReleephRequest::REVERT_OK + : ReleephRequest::REVERT_FAILED; + break; + + default: + throw new Exception("Unknown action {$action}!"); + } + + $releeph_request = id(new ReleephRequest()) + ->loadOneWhere('phid = %s', $request->getValue('requestPHID')); + + id(new ReleephRequestEditor($releeph_request)) + ->setActor($request->getUser()) + ->changePickStatus($pick_status, $dry_run, $details); + } + +} diff --git a/src/applications/releeph/config/PhabricatorApplicationReleephConfigOptions.php b/src/applications/releeph/config/PhabricatorApplicationReleephConfigOptions.php new file mode 100644 index 000000000..75cc32247 --- /dev/null +++ b/src/applications/releeph/config/PhabricatorApplicationReleephConfigOptions.php @@ -0,0 +1,64 @@ +<?php + +final class PhabricatorApplicationReleephConfigOptions + extends PhabricatorApplicationConfigOptions { + + public function getName() { + return pht("Releeph"); + } + + public function getDescription() { + return pht("Options for configuring Releeph, the release branch tool."); + } + + public function getOptions() { + return array( + $this->newOption('releeph.installed', 'bool', false) + ->setSummary(pht('Enable the Releeph application.')) + ->setDescription( + pht( + "Releeph, a tool for managing release branches, will eventually ". + "fit in to the Phabricator suite as a general purpose tool. ". + "However Releeph is currently unstable in multiple ways that may ". + "not migrate properly for you: the code is still in alpha stage ". + "of design, the storage format is likely to change in unexpected ". + "ways, and the workflows presented are very specific to a core ". + "set of alpha testers at Facebook. For the time being you are ". + "strongly discouraged from relying on Releeph being at all ". + "stable.")), + $this->newOption( + 'releeph.field-selector', + 'class', + 'ReleephDefaultFieldSelector') + ->setBaseClass('ReleephFieldSelector') + ->setSummary(pht('Field selector class')) + ->setDescription( + pht( + "Control which fields are available when making a new Releeph ". + "request, and which are then shown in the Releeph UI.")), + $this->newOption( + 'releeph.user-view', + 'class', + 'ReleephDefaultUserView') + ->setBaseClass('ReleephUserView') + ->setSummary(pht('Extra markup when rendering usernames')) + ->setDescription( + pht( + "A wrapper to render Phabricator users in Releeph, with custom ". + "markup. For example, Facebook extends this to render additional ". + "information about requestors, to each Releeph project's ". + "pushers.")), + $this->newOption( + 'releeph.default-branch-template', + 'string', + 'releases/%P/%p-%Y%m%d-%v') + ->setDescription( + pht( + "The default branch template for new branches in unconfigured ". + "Releeph projects. This is also configurable on a per-project ". + "basis.")), + ); + } + + +} diff --git a/src/applications/releeph/controller/ReleephController.php b/src/applications/releeph/controller/ReleephController.php new file mode 100644 index 000000000..22a821453 --- /dev/null +++ b/src/applications/releeph/controller/ReleephController.php @@ -0,0 +1,122 @@ +<?php + +abstract class ReleephController extends PhabricatorController { + + private $releephProject; + private $releephBranch; + private $releephRequest; + + /** + * ReleephController will take care of loading any Releeph* objects + * referenced in the URL. + */ + public function willProcessRequest(array $data) { + // Project + $project = null; + $project_id = idx($data, 'projectID'); + $project_name = idx($data, 'projectName'); + if ($project_id) { + $project = id(new ReleephProject())->load($project_id); + if (!$project) { + throw new Exception( + "ReleephProject with id '{$project_id}' not found!"); + } + } elseif ($project_name) { + $project = id(new ReleephProject()) + ->loadOneWhere('name = %s', $project_name); + if (!$project) { + throw new Exception( + "ReleephProject with name '{$project_name}' not found!"); + } + } + + // Branch + $branch = null; + $branch_id = idx($data, 'branchID'); + $branch_name = idx($data, 'branchName'); + if ($branch_id) { + $branch = id(new ReleephBranch())->load($branch_id); + if (!$branch) { + throw new Exception("Branch with id '{$branch_id}' not found!"); + } + } elseif ($branch_name) { + if (!$project) { + throw new Exception( + "You cannot refer to a branch by name without also referring ". + "to a ReleephProject (branch names are only unique in projects)."); + } + $branch = id(new ReleephBranch())->loadOneWhere( + 'basename = %s AND releephProjectID = %d', + $branch_name, + $project->getID()); + if (!$branch) { + throw new Exception( + "ReleephBranch with basename '{$branch_name}' not found ". + "in project '{$project->getName()}'!"); + } + } + + // Request + $request = null; + $request_id = idx($data, 'requestID'); + if ($request_id) { + $request = id(new ReleephRequest())->load($request_id); + if (!$request) { + throw new Exception( + "ReleephRequest with id '{$request_id}' not found!"); + } + } + + // Fill in the gaps + if ($request && !$branch) { + $branch = $request->loadReleephBranch(); + } + + if ($branch && !$project) { + $project = $branch->loadReleephProject(); + } + + // Set! + $this->releephProject = $project; + $this->releephBranch = $branch; + $this->releephRequest = $request; + } + + protected function getReleephProject() { + if (!$this->releephProject) { + throw new Exception( + 'This controller did not load a ReleephProject from the URL $data.'); + } + return $this->releephProject; + } + + protected function getReleephBranch() { + if (!$this->releephBranch) { + throw new Exception( + 'This controller did not load a ReleephBranch from the URL $data.'); + } + return $this->releephBranch; + } + + protected function getReleephRequest() { + if (!$this->releephRequest) { + throw new Exception( + 'This controller did not load a ReleephRequest from the URL $data.'); + } + return $this->releephRequest; + } + + public function buildStandardPageResponse($view, array $data) { + $page = $this->buildStandardPageView(); + + $page->setApplicationName('Releeph'); + $page->setBaseURI('/releeph/'); + $page->setTitle(idx($data, 'title')); + $page->setGlyph("\xD3\x82"); + $page->appendChild($view); + + $response = new AphrontWebpageResponse(); + return $response->setContent($page->render()); + } + +} diff --git a/src/applications/releeph/controller/branch/ReleephBranchAccessController.php b/src/applications/releeph/controller/branch/ReleephBranchAccessController.php new file mode 100644 index 000000000..bcaf86e96 --- /dev/null +++ b/src/applications/releeph/controller/branch/ReleephBranchAccessController.php @@ -0,0 +1,61 @@ +<?php + +final class ReleephBranchAccessController extends ReleephController { + + private $action; + + public function willProcessRequest(array $data) { + $this->action = $data['action']; + parent::willProcessRequest($data); + } + + public function processRequest() { + $rph_branch = $this->getReleephBranch(); + $request = $this->getRequest(); + + $active_uri = '/releeph/project/'.$rph_branch->getReleephProjectID().'/'; + $inactive_uri = $active_uri.'inactive/'; + + switch ($this->action) { + case 'close': + $is_active = false; + $origin_uri = $active_uri; + break; + + case 're-open': + $is_active = true; + $origin_uri = $inactive_uri; + break; + + default: + throw new Exception("Unknown action '{$this->action}'!"); + break; + } + + if ($request->isDialogFormPost()) { + id(new ReleephBranchEditor()) + ->setActor($request->getUser()) + ->setReleephBranch($rph_branch) + ->changeBranchAccess($is_active ? 1 : 0); + return id(new AphrontRedirectResponse()) + ->setURI($origin_uri); + } + + $button_text = ucfirst($this->action).' Branch'; + $message = hsprintf( + '<p>Really %s the branch <i>%s</i>?</p>', + $this->action, + $rph_branch->getBasename()); + + + $dialog = new AphrontDialogView(); + $dialog + ->setUser($request->getUser()) + ->setTitle('Confirm') + ->appendChild($message) + ->addSubmitButton($button_text) + ->addCancelButton($origin_uri); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } +} diff --git a/src/applications/releeph/controller/branch/ReleephBranchCreateController.php b/src/applications/releeph/controller/branch/ReleephBranchCreateController.php new file mode 100644 index 000000000..6031c0388 --- /dev/null +++ b/src/applications/releeph/controller/branch/ReleephBranchCreateController.php @@ -0,0 +1,105 @@ +<?php + +final class ReleephBranchCreateController extends ReleephController { + + public function processRequest() { + $releeph_project = $this->getReleephProject(); + + $request = $this->getRequest(); + + $cut_point = $request->getStr('cutPoint'); + $symbolic_name = $request->getStr('symbolicName'); + + if (!$cut_point) { + $repository = $releeph_project->loadPhabricatorRepository(); + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + break; + + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $cut_point = $releeph_project->getTrunkBranch(); + break; + } + } + + $e_cut = true; + $errors = array(); + + $branch_date_control = id(new AphrontFormDateControl()) + ->setUser($request->getUser()) + ->setName('templateDate') + ->setLabel('Date') + ->setCaption('The date used for filling out the branch template.') + ->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY); + $branch_date = $branch_date_control->readValueFromRequest($request); + + if ($request->isFormPost()) { + $cut_commit = null; + if (!$cut_point) { + $e_cut = 'Required'; + $errors[] = 'You must give a branch cut point'; + } else { + try { + $finder = id(new ReleephCommitFinder()) + ->setReleephProject($releeph_project); + $cut_commit = $finder->fromPartial($cut_point); + } catch (Exception $e) { + $e_cut = 'Invalid'; + $errors[] = $e->getMessage(); + } + } + + if (!$errors) { + $branch = id(new ReleephBranchEditor()) + ->setReleephProject($releeph_project) + ->setActor($request->getUser()) + ->newBranchFromCommit( + $cut_commit, + $branch_date, + $symbolic_name); + + return id(new AphrontRedirectResponse()) + ->setURI($branch->getURI()); + } + } + + $error_view = array(); + if ($errors) { + $error_view = new AphrontErrorView(); + $error_view->setErrors($errors); + $error_view->setTitle('Form Errors'); + } + + $form = id(new AphrontFormView()) + ->setUser($request->getUser()) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Symbolic name') + ->setName('symbolicName') + ->setValue($symbolic_name) + ->setCaption('Mutable alternate name, for easy reference, '. + '(e.g. "LATEST")')) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Cut point') + ->setName('cutPoint') + ->setValue($cut_point) + ->setError($e_cut) + ->setCaption( + 'A commit ID for your repo type, or a Diffusion ID like "rE123"')) + ->appendChild($branch_date_control) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Cut Branch') + ->addCancelButton($releeph_project->getURI())); + + $panel = id(new AphrontPanelView()) + ->appendChild($form) + ->setHeader('Cut Branch') + ->setWidth(AphrontPanelView::WIDTH_FORM); + + return $this->buildStandardPageResponse( + array($error_view, $panel), + array('title' => 'Cut new branch')); + } +} diff --git a/src/applications/releeph/controller/branch/ReleephBranchEditController.php b/src/applications/releeph/controller/branch/ReleephBranchEditController.php new file mode 100644 index 000000000..5501ee3e0 --- /dev/null +++ b/src/applications/releeph/controller/branch/ReleephBranchEditController.php @@ -0,0 +1,136 @@ +<?php + +final class ReleephBranchEditController extends ReleephController { + + public function processRequest() { + $request = $this->getRequest(); + $releeph_branch = $this->getReleephBranch(); + $branch_name = $request->getStr( + 'branchName', + $releeph_branch->getName()); + $symbolic_name = $request->getStr( + 'symbolicName', + $releeph_branch->getSymbolicName()); + + $e_existing_with_same_branch_name = false; + $errors = array(); + + if ($request->isFormPost()) { + $existing_with_same_branch_name = + id(new ReleephBranch()) + ->loadOneWhere( + 'id != %d AND releephProjectID = %d AND name = %s', + $releeph_branch->getID(), + $releeph_branch->getReleephProjectID(), + $branch_name); + + if ($existing_with_same_branch_name) { + $errors[] = sprintf( + "The branch name %s is currently taken. Please use another name. ", + $branch_name); + $e_existing_with_same_branch_name = 'Error'; + } + + if (!$errors) { + $existing_with_same_symbolic_name = + id(new ReleephBranch()) + ->loadOneWhere( + 'id != %d AND releephProjectID = %d AND symbolicName = %s', + $releeph_branch->getID(), + $releeph_branch->getReleephProjectID(), + $symbolic_name); + + $releeph_branch->openTransaction(); + $releeph_branch + ->setName($branch_name) + ->setBasename(last(explode('/', $branch_name))) + ->setSymbolicName($symbolic_name); + + if ($existing_with_same_symbolic_name) { + $existing_with_same_symbolic_name + ->setSymbolicName(null) + ->save(); + } + + $releeph_branch->save(); + $releeph_branch->saveTransaction(); + + return id(new AphrontRedirectResponse()) + ->setURI('/releeph/project/'.$releeph_branch->getReleephProjectID()); + } + } + + $phids = array(); + + $phids[] = $creator_phid = $releeph_branch->getCreatedByUserPHID(); + $phids[] = $cut_commit_phid = $releeph_branch->getCutPointCommitPHID(); + + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($request->getUser()) + ->loadHandles(); + + $form = id(new AphrontFormView()) + ->setUser($request->getUser()) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Branch name') + ->setValue($branch_name)) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setLabel('Cut point') + ->setValue($handles[$cut_commit_phid]->renderLink())) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setLabel('Created by') + ->setValue($handles[$creator_phid]->renderLink())) + ->appendChild( + id(new AphrontFormTextControl) + ->setLabel('Symbolic Name') + ->setName('symbolicName') + ->setValue($symbolic_name) + ->setCaption('Mutable alternate name, for easy reference, '. + '(e.g. "LATEST")')) + ->appendChild(hsprintf( + '<br>' . + 'In dire situations where the branch name is wrong, ' . + 'you can edit it in the database by changing the field below. ' . + 'If you do this, it is very important that you change your ' . + 'branch\'s name in the VCS to reflect the new name in Releeph, ' . + 'otherwise a catastrophe of previously unheard-of magnitude ' . + 'will befall your project.')) + ->appendChild( + id(new AphrontFormTextControl) + ->setLabel('New branch name') + ->setName('branchName') + ->setValue($branch_name) + ->setError($e_existing_with_same_branch_name)) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($releeph_branch->getURI()) + ->setValue('Save')); + + $error_view = null; + if ($errors) { + $error_view = id(new AphrontErrorView()) + ->setSeverity(AphrontErrorView::SEVERITY_ERROR) + ->setErrors($errors) + ->setTitle('Errors'); + } + + $title = hsprintf( + 'Edit branch %s', + $releeph_branch->getDisplayNameWithDetail()); + + $panel = id(new AphrontPanelView()) + ->setHeader($title) + ->appendChild($form) + ->setWidth(AphrontPanelView::WIDTH_FORM); + + return $this->buildStandardPageResponse( + array( + $error_view, + $panel, + ), + array('title' => $title)); + } +} diff --git a/src/applications/releeph/controller/branch/ReleephBranchNamePreviewController.php b/src/applications/releeph/controller/branch/ReleephBranchNamePreviewController.php new file mode 100644 index 000000000..5606542bf --- /dev/null +++ b/src/applications/releeph/controller/branch/ReleephBranchNamePreviewController.php @@ -0,0 +1,46 @@ +<?php + +final class ReleephBranchNamePreviewController + extends PhabricatorController { + + public function processRequest() { + $request = $this->getRequest(); + + $is_symbolic = $request->getBool('isSymbolic'); + $template = $request->getStr('template'); + + if (!$is_symbolic && !$template) { + $template = ReleephBranchTemplate::getDefaultTemplate(); + } + + $arc_project_id = $request->getInt('arcProjectID'); + $fake_commit_handle = + ReleephBranchTemplate::getFakeCommitHandleFor($arc_project_id); + + list($name, $errors) = id(new ReleephBranchTemplate()) + ->setCommitHandle($fake_commit_handle) + ->setReleephProjectName($request->getStr('projectName')) + ->setSymbolic($is_symbolic) + ->interpolate($template); + + $markup = ''; + + if ($name) { + $markup = phutil_tag( + 'div', + array('class' => 'name'), + $name); + } + + if ($errors) { + $markup .= phutil_tag( + 'div', + array('class' => 'error'), + head($errors)); + } + + return id(new AphrontAjaxResponse()) + ->setContent(array('markup' => $markup)); + } + +} diff --git a/src/applications/releeph/controller/branch/ReleephBranchViewController.php b/src/applications/releeph/controller/branch/ReleephBranchViewController.php new file mode 100644 index 000000000..f01f14987 --- /dev/null +++ b/src/applications/releeph/controller/branch/ReleephBranchViewController.php @@ -0,0 +1,94 @@ +<?php + +final class ReleephBranchViewController extends ReleephController { + + public function processRequest() { + $request = $this->getRequest(); + + $releeph_branch = $this->getReleephBranch(); + $releeph_project = $this->getReleephProject(); + $all_releeph_requests = $releeph_branch->loadReleephRequests( + $request->getUser()); + + $selector = $releeph_project->getReleephFieldSelector(); + $fields = $selector->arrangeFieldsForSelectForm( + $selector->getFieldSpecifications()); + + $form = id(new AphrontFormView()) + ->setMethod('GET') + ->setUser($request->getUser()); + + $filtered_releeph_requests = $all_releeph_requests; + foreach ($fields as $field) { + $all_releeph_requests_without_this_field = $all_releeph_requests; + foreach ($fields as $other_field) { + if ($other_field != $field) { + $other_field->selectReleephRequestsHook( + $request, + $all_releeph_requests_without_this_field); + + } + } + + $field->appendSelectControlsHook( + $form, + $request, + $all_releeph_requests, + $all_releeph_requests_without_this_field); + + $field->selectReleephRequestsHook( + $request, + $filtered_releeph_requests); + } + + $form->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Filter')); + + $list = id(new ReleephRequestHeaderListView()) + ->setOriginType('branch') + ->setUser($request->getUser()) + ->setAphrontRequest($this->getRequest()) + ->setReleephProject($releeph_project) + ->setReleephBranch($releeph_branch) + ->setReleephRequests($filtered_releeph_requests); + + $filter = id(new AphrontListFilterView()) + ->appendChild($form); + + $crumbs = $this->buildApplicationCrumbs() + ->addCrumb( + id(new PhabricatorCrumbView()) + ->setName($releeph_project->getName()) + ->setHref($releeph_project->getURI())) + ->addCrumb( + id(new PhabricatorCrumbView()) + ->setName($releeph_branch->getDisplayNameWithDetail()) + ->setHref($releeph_branch->getURI())); + + // Don't show the request button for inactive (closed) branches + if ($releeph_branch->isActive()) { + $create_uri = $releeph_branch->getURI('request/'); + $crumbs->addAction( + id(new PhabricatorMenuItemView()) + ->setHref($create_uri) + ->setName('Request Pick') + ->setIcon('create')); + } + + return $this->buildStandardPageResponse( + array( + $crumbs, + $filter, + $list + ), + array( + 'title' => + $releeph_project->getName(). + ' - '. + $releeph_branch->getDisplayName(). + ' requests' + )); + } + +} diff --git a/src/applications/releeph/controller/project/ReleephProjectActionController.php b/src/applications/releeph/controller/project/ReleephProjectActionController.php new file mode 100644 index 000000000..4e91107ea --- /dev/null +++ b/src/applications/releeph/controller/project/ReleephProjectActionController.php @@ -0,0 +1,63 @@ +<?php + +final class ReleephProjectActionController extends ReleephController { + + private $action; + + public function willProcessRequest(array $data) { + parent::willProcessRequest($data); + $this->action = $data['action']; + } + + public function processRequest() { + $request = $this->getRequest(); + + $action = $this->action; + $rph_project = $this->getReleephProject(); + + switch ($action) { + case 'deactivate': + if ($request->isDialogFormPost()) { + $rph_project->deactivate($request->getUser())->save(); + return id(new AphrontRedirectResponse())->setURI('/releeph'); + } + + $dialog = id(new AphrontDialogView()) + ->setUser($request->getUser()) + ->setTitle('Really deactivate Releeph Project?') + ->appendChild(hsprintf( + '<p>Really deactivate the Releeph project <i>%s</i>?', + $rph_project->getName())) + ->appendChild(hsprintf( + '<p style="margin-top:1em">It will still exist, but '. + 'will be hidden from the list of active projects.</p>')) + ->addSubmitButton('Deactivate Releeph Project') + ->addCancelButton($request->getRequestURI()); + + return id(new AphrontDialogResponse())->setDialog($dialog); + + case 'activate': + $rph_project->setIsActive(1)->save(); + return id(new AphrontRedirectResponse())->setURI('/releeph'); + + case 'delete': + if ($request->isDialogFormPost()) { + $rph_project->delete(); + return id(new AphrontRedirectResponse()) + ->setURI('/releeph/project/inactive'); + } + + $dialog = id(new AphrontDialogView()) + ->setUser($request->getUser()) + ->setTitle('Really delete Releeph Project?') + ->appendChild(hsprintf( + '<p>Really delete the "%s" Releeph project? '. + 'This cannot be undone!</p>', + $rph_project->getName())) + ->addSubmitButton('Delete Releeph Project') + ->addCancelButton($request->getRequestURI()); + return id(new AphrontDialogResponse())->setDialog($dialog); + + } + } +} diff --git a/src/applications/releeph/controller/project/ReleephProjectCreateController.php b/src/applications/releeph/controller/project/ReleephProjectCreateController.php new file mode 100644 index 000000000..2dbfb72c5 --- /dev/null +++ b/src/applications/releeph/controller/project/ReleephProjectCreateController.php @@ -0,0 +1,149 @@ +<?php + +final class ReleephProjectCreateController extends ReleephController { + + public function processRequest() { + $request = $this->getRequest(); + $name = trim($request->getStr('name')); + $trunk_branch = trim($request->getStr('trunkBranch')); + $arc_pr_id = $request->getInt('arcPrID'); + + + // Only allow arc projects with repositories. Sort and re-key by ID. + $arc_projects = id(new PhabricatorRepositoryArcanistProject())->loadAll(); + $arc_projects = mpull( + msort( + mfilter($arc_projects, 'getRepositoryID'), + 'getName'), + null, + 'getID'); + + $e_name = true; + $e_trunk_branch = true; + $errors = array(); + + if ($request->isFormPost()) { + if (!$name) { + $e_name = 'Required'; + $errors[] = + 'Your releeph project should have a simple descriptive name.'; + } + + if (!$trunk_branch) { + $e_trunk_branch = 'Required'; + $errors[] = + 'You must specify which branch you will be picking from.'; + } + + $all_names = mpull(id(new ReleephProject())->loadAll(), 'getName'); + + if (in_array($name, $all_names)) { + $errors[] = "Releeph project name {$name} is already taken"; + } + + $arc_project = $arc_projects[$arc_pr_id]; + $pr_repository = $arc_project->loadRepository(); + + if (!$errors) { + $releeph_project = id(new ReleephProject()) + ->setName($name) + ->setTrunkBranch($trunk_branch) + ->setRepositoryID($pr_repository->getID()) + ->setRepositoryPHID($pr_repository->getPHID()) + ->setArcanistProjectID($arc_project->getID()) + ->setCreatedByUserPHID($request->getUser()->getPHID()) + ->setIsActive(1) + ->save(); + + return id(new AphrontRedirectResponse())->setURI('/releeph/'); + } + } + + $error_view = null; + if ($errors) { + $error_view = new AphrontErrorView(); + $error_view->setErrors($errors); + $error_view->setTitle('Form Errors'); + } + + // Make our own optgroup select control + $arc_project_choices = array(); + $pr_repositories = mpull( + msort( + array_filter( + // Some arc-projects don't have repositories + mpull($arc_projects, 'loadRepository')), + 'getName'), + null, + 'getID'); + + foreach ($pr_repositories as $pr_repo_id => $pr_repository) { + $options = array(); + foreach ($arc_projects as $arc_project) { + if ($arc_project->getRepositoryID() == $pr_repo_id) { + $options[$arc_project->getID()] = $arc_project->getName(); + } + } + $arc_project_choices[$pr_repository->getName()] = $options; + } + + $project_name_input = id(new AphrontFormTextControl()) + ->setLabel('Name') + ->setDisableAutocomplete(true) + ->setName('name') + ->setValue($name) + ->setError($e_name) + ->setCaption('A name like "Thrift" but not "Thrift releases".'); + + $arc_project_input = id(new AphrontFormSelectControl()) + ->setLabel('Arc Project') + ->setName('arcPrID') + ->setValue($arc_pr_id) + ->setCaption(hsprintf( + "If your Arc project isn't listed, associate it with a repository %s", + phutil_tag( + 'a', + array( + 'href' => '/repository/', + 'target' => '_blank', + ), + 'here'))) + ->setOptions($arc_project_choices); + + $branch_name_preview = id(new ReleephBranchPreviewView()) + ->setLabel('Example Branch') + ->addControl('projectName', $project_name_input) + ->addControl('arcProjectID', $arc_project_input) + ->addStatic('template', '') + ->addStatic('isSymbolic', false); + + $form = id(new AphrontFormView()) + ->setUser($request->getUser()) + ->appendChild($project_name_input) + ->appendChild($arc_project_input) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Trunk') + ->setName('trunkBranch') + ->setValue($trunk_branch) + ->setError($e_trunk_branch) + ->setCaption('The development branch, '. + 'from which requests will be picked.')) + ->appendChild($branch_name_preview) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton('/releeph/project/') + ->setValue('Create')); + + $panel = id(new AphrontPanelView()) + ->setHeader('Create Releeph Project') + ->appendChild($form) + ->setWidth(AphrontPanelView::WIDTH_FORM); + + return $this->buildStandardPageResponse( + array($error_view, $panel), + array( + 'title' => 'Create new Releeph Project' + )); + } +} diff --git a/src/applications/releeph/controller/project/ReleephProjectEditController.php b/src/applications/releeph/controller/project/ReleephProjectEditController.php new file mode 100644 index 000000000..1dcb128e6 --- /dev/null +++ b/src/applications/releeph/controller/project/ReleephProjectEditController.php @@ -0,0 +1,388 @@ +<?php + +final class ReleephProjectEditController extends ReleephController { + + public function processRequest() { + $request = $this->getRequest(); + + $e_name = true; + $e_trunk_branch = true; + $e_branch_template = false; + $errors = array(); + + $project_name = $request->getStr('name', + $this->getReleephProject()->getName()); + + $phabricator_project_id = $request->getInt('projectID', + $this->getReleephProject()->getProjectID()); + $trunk_branch = $request->getStr('trunkBranch', + $this->getReleephProject()->getTrunkBranch()); + $branch_template = $request->getStr('branchTemplate'); + if ($branch_template === null) { + $branch_template = + $this->getReleephProject()->getDetail('branchTemplate'); + } + $pick_failure_instructions = $request->getStr('pickFailureInstructions', + $this->getReleephProject()->getDetail('pick_failure_instructions')); + $commit_author = $request->getStr('commitWithAuthor', + $this->getReleephProject()->getDetail('commitWithAuthor')); + $test_paths = $request->getStr('testPaths'); + if ($test_paths !== null) { + $test_paths = array_filter(explode("\n", $test_paths)); + } else { + $test_paths = $this->getReleephProject()->getDetail('testPaths', array()); + } + + $field_selector = $request->getStr('fieldSelector', + get_class($this->getReleephProject()->getReleephFieldSelector())); + + $release_counter = $request->getInt( + 'releaseCounter', + $this->getReleephProject()->getCurrentReleaseNumber()); + + $arc_project_id = $this->getReleephProject()->getArcanistProjectID(); + + if ($request->isFormPost()) { + $pusher_phids = $request->getArr('pushers'); + + if (!$project_name) { + $e_name = 'Required'; + $errors[] = + 'Your releeph project should have a simple descriptive name'; + } + + if (!$trunk_branch) { + $e_trunk_branch = 'Required'; + $errors[] = + 'You must specify which branch you will be picking from.'; + } + + if ($release_counter && !is_int($release_counter)) { + $errors[] = "Release counter must be a positive integer!"; + } + + $other_releeph_projects = id(new ReleephProject()) + ->loadAllWhere('id <> %d', $this->getReleephProject()->getID()); + $other_releeph_project_names = mpull($other_releeph_projects, + 'getName', 'getID'); + + if (in_array($project_name, $other_releeph_project_names)) { + $errors[] = "Releeph project name {$project_name} is already taken"; + } + + foreach ($test_paths as $test_path) { + $result = @preg_match($test_path, ''); + $is_a_valid_regexp = $result !== false; + if (!$is_a_valid_regexp) { + $errors[] = 'Please provide a valid regular expression: '. + "{$test_path} is not valid"; + } + } + + $project = $this->getReleephProject() + ->setProjectID($phabricator_project_id) + ->setTrunkBranch($trunk_branch) + ->setDetail('pushers', $pusher_phids) + ->setDetail('pick_failure_instructions', $pick_failure_instructions) + ->setDetail('field_selector', $field_selector) + ->setDetail('branchTemplate', $branch_template) + ->setDetail('commitWithAuthor', $commit_author) + ->setDetail('testPaths', $test_paths); + + if ($release_counter) { + $project->setDetail('releaseCounter', $release_counter); + } + + $fake_commit_handle = + ReleephBranchTemplate::getFakeCommitHandleFor($arc_project_id); + + if ($branch_template) { + list($branch_name, $template_errors) = id(new ReleephBranchTemplate()) + ->setCommitHandle($fake_commit_handle) + ->setReleephProjectName($project_name) + ->interpolate($branch_template); + + if ($template_errors) { + $e_branch_template = 'Invalid!'; + foreach ($template_errors as $template_error) { + $errors[] = "Template error: {$template_error}"; + } + } + } + + if (!$errors) { + $project->save(); + + return id(new AphrontRedirectResponse()) + ->setURI('/releeph/project/'); + } + } + + $error_view = null; + if ($errors) { + $error_view = new AphrontErrorView(); + $error_view->setErrors($errors); + $error_view->setTitle('Form Errors'); + } + + $projects = mpull( + id(new PhabricatorProject())->loadAll(), + 'getName', + 'getID'); + + $projects[0] = '-'; // no project associated, that's ok + + $pusher_phids = $request->getArr( + 'pushers', + $this->getReleephProject()->getDetail('pushers', array())); + + $handles = id(new PhabricatorObjectHandleData($pusher_phids)) + ->setViewer($request->getUser()) + ->loadHandles(); + + $pusher_tokens = array(); + foreach ($pusher_phids as $phid) { + $pusher_tokens[$phid] = $handles[$phid]->getFullName(); + } + + $basic_inset = id(new AphrontFormInsetView()) + ->setTitle('Basics') + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Name') + ->setName('name') + ->setValue($project_name) + ->setError($e_name) + ->setCaption('A name like "Thrift" but not "Thrift releases".')) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Repository') + ->setValue( + $this + ->getReleephProject() + ->loadPhabricatorRepository() + ->getName())) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Arc Project') + ->setValue( + $this->getReleephProject()->loadArcanistProject()->getName())) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Releeph Project PHID') + ->setValue( + $this->getReleephProject()->getPHID())) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel('Phabricator Project') + ->setValue($phabricator_project_id) + ->setName('projectID') + ->setOptions($projects)) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Trunk') + ->setValue($trunk_branch) + ->setName('trunkBranch') + ->setError($e_trunk_branch)) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Release counter') + ->setValue($release_counter) + ->setName('releaseCounter') + ->setCaption( + "Used by the command line branch cutter's %N field")) + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setLabel('Pick Instructions') + ->setValue($pick_failure_instructions) + ->setName('pickFailureInstructions') + ->setCaption( + "Instructions for pick failures, which will be used " . + "in emails generated by failed picks")) + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setLabel('Tests paths') + ->setValue(implode("\n", $test_paths)) + ->setName('testPaths') + ->setCaption( + 'List of strings that all test files contain in their path '. + 'in this project. One string per line. '. + 'Examples: \'__tests__\', \'/javatests/\'...')); + + $pushers_inset = id(new AphrontFormInsetView()) + ->setTitle('Pushers') + ->appendChild( + 'Pushers are allowed to approve Releeph requests to be committed. '. + 'to this project\'s branches. If you leave this blank then anyone '. + 'is allowed to approve requests.') + ->appendChild( + id(new AphrontFormTokenizerControl()) + ->setLabel('Pushers') + ->setName('pushers') + ->setDatasource('/typeahead/common/users/') + ->setValue($pusher_tokens)); + + $field_selector_options = array(); + $field_selector_symbols = id(new PhutilSymbolLoader()) + ->setType('class') + ->setConcreteOnly(true) + ->setAncestorClass('ReleephFieldSelector') + ->selectAndLoadSymbols(); + foreach ($field_selector_symbols as $symbol) { + $selector_name = $symbol['name']; + $field_selector_options[$selector_name] = $selector_name; + } + + $field_selector_blurb = hsprintf( + "If you you have additional information to render about Releeph ". + "requests, or want to re-arrange the UI, implement a ". + "<tt>ReleephFieldSelector</tt> and select it here."); + + $fields_inset = id(new AphrontFormInsetView()) + ->setTitle('Fields') + ->appendChild($field_selector_blurb) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel('Selector') + ->setName('fieldSelector') + ->setValue($field_selector) + ->setOptions($field_selector_options)); + + $commit_author_inset = $this->buildCommitAuthorInset($commit_author); + + // Build the Template inset + $markup_engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine(); + + // From DifferentialUnitFieldSpecification... + $markup_engine->setConfig('viewer', $request->getUser()); + + $help_markup = phutil_tag( + 'div', + array( + 'class' => 'phabricator-remarkup', + ), + phutil_safe_html( + $markup_engine->markupText(ReleephBranchTemplate::getHelpRemarkup()))); + + $branch_template_input = id(new AphrontFormTextControl()) + ->setName('branchTemplate') + ->setValue($branch_template) + ->setLabel('Template') + ->setError($e_branch_template) + ->setCaption( + "Leave this blank to use your installation's default."); + + $branch_template_preview = id(new ReleephBranchPreviewView()) + ->setLabel('Preview') + ->addControl('template', $branch_template_input) + ->addStatic('arcProjectID', $arc_project_id) + ->addStatic('isSymbolic', false) + ->addStatic('projectName', $this->getReleephProject()->getName()); + + $template_inset = id(new AphrontFormInsetView()) + ->setTitle('Branch Cutting') + ->appendChild( + 'Provide a pattern for creating new branches.') + ->appendChild($branch_template_input) + ->appendChild($branch_template_preview) + ->appendChild($help_markup); + + // Build the form + $form = id(new AphrontFormView()) + ->setUser($request->getUser()) + ->appendChild($basic_inset) + ->appendChild($pushers_inset) + ->appendChild($fields_inset) + ->appendChild($commit_author_inset) + ->appendChild($template_inset); + + $form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton('/releeph/project/') + ->setValue('Save')); + + $panel = id(new AphrontPanelView()) + ->setHeader('Edit Releeph Project') + ->appendChild($form) + ->setWidth(AphrontPanelView::WIDTH_FORM); + + return $this->buildStandardPageResponse( + array($error_view, $panel), + array('title' => 'Edit Releeph Project')); + } + + private function buildCommitAuthorInset($current) { + $vcs_type = $this->getReleephProject() + ->loadPhabricatorRepository() + ->getVersionControlSystem(); + + switch ($vcs_type) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + break; + + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + return; + break; + } + + $vcs_name = PhabricatorRepositoryType::getNameForRepositoryType($vcs_type); + + $help_markup = hsprintf(<<<EOTEXT +When your project's release engineers run <tt>arc releeph</tt>, they will be +listed as the <strong>committer</strong> of the code committed to release +branches. + +%s allows you to specify a separate author when committing code. Some +tools use the author of a commit (rather than the committer) when they need to +notify someone about a build or test failure. + +Releeph can use one of the following to set the <strong>author</strong> of the +commits it makes: +EOTEXT + , $vcs_name); + + $trunk = $this->getReleephProject()->getTrunkBranch(); + + $options = array( + array( + 'value' => ReleephProject::COMMIT_AUTHOR_FROM_DIFF, + 'label' => 'Original Author', + 'caption' => + "The author of the original commit in {$trunk}.", + ), + array( + 'value' => ReleephProject::COMMIT_AUTHOR_REQUESTOR, + 'label' => 'Requestor', + 'caption' => + "The person who requested that this code go into the release.", + ), + array( + 'value' => ReleephProject::COMMIT_AUTHOR_NONE, + 'label' => "None", + 'caption' => + "Only record the default committer information.", + ), + ); + + if (!$current) { + $current = ReleephProject::COMMIT_AUTHOR_FROM_DIFF; + } + + $control = id(new AphrontFormRadioButtonControl()) + ->setLabel('Author') + ->setName('commitWithAuthor') + ->setValue($current); + + foreach ($options as $dict) { + $control->addButton($dict['value'], $dict['label'], $dict['caption']); + } + + return id(new AphrontFormInsetView()) + ->setTitle('Authors') + ->appendChild($help_markup) + ->appendChild($control); + } + +} diff --git a/src/applications/releeph/controller/project/ReleephProjectListController.php b/src/applications/releeph/controller/project/ReleephProjectListController.php new file mode 100644 index 000000000..e00709d08 --- /dev/null +++ b/src/applications/releeph/controller/project/ReleephProjectListController.php @@ -0,0 +1,70 @@ +<?php + +final class ReleephProjectListController extends PhabricatorController { + + public function processRequest() { + $path = $this->getRequest()->getRequestURI()->getPath(); + $is_active = strpos($path, 'inactive/') === false; + + $releeph_projects = mfilter( + id(new ReleephProject())->loadAll(), + 'getIsActive', + !$is_active); + $releeph_projects = msort($releeph_projects, 'getName'); + + $releeph_projects_set = new LiskDAOSet(); + foreach ($releeph_projects as $releeph_project) { + $releeph_projects_set->addToSet($releeph_project); + } + + $panel = new AphrontPanelView(); + + if ($is_active) { + $view_inactive_link = phutil_tag( + 'a', + array( + 'href' => '/releeph/project/inactive/', + ), + 'View inactive projects'); + $panel + ->setHeader(hsprintf( + 'Active Releeph Projects · %s', $view_inactive_link)) + ->appendChild( + id(new ReleephActiveProjectListView()) + ->setUser($this->getRequest()->getUser()) + ->setReleephProjects($releeph_projects)); + } else { + $view_active_link = phutil_tag( + 'a', + array( + 'href' => '/releeph/project/' + ), + 'View active projects'); + $panel + ->setHeader(hsprintf( + 'Inactive Releeph Projects · %s', $view_active_link)) + ->appendChild( + id(new ReleephInactiveProjectListView()) + ->setUser($this->getRequest()->getUser()) + ->setReleephProjects($releeph_projects)); + } + + if ($is_active) { + $create_new_project_button = phutil_tag( + 'a', + array( + 'href' => '/releeph/project/create/', + 'class' => 'green button', + ), + 'Create New Project'); + $panel->addButton($create_new_project_button); + } + + return $this->buildStandardPageResponse( + $panel, + array( + 'title' => 'List Releeph Projects' + )); + } + +} diff --git a/src/applications/releeph/controller/project/ReleephProjectViewController.php b/src/applications/releeph/controller/project/ReleephProjectViewController.php new file mode 100644 index 000000000..270682246 --- /dev/null +++ b/src/applications/releeph/controller/project/ReleephProjectViewController.php @@ -0,0 +1,45 @@ +<?php + +final class ReleephProjectViewController extends ReleephController { + + public function processRequest() { + // Load all branches + $releeph_project = $this->getReleephProject(); + $releeph_branches = id(new ReleephBranch()) + ->loadAllWhere('releephProjectID = %d', + $releeph_project->getID()); + + $path = $this->getRequest()->getRequestURI()->getPath(); + $is_open_branches = strpos($path, 'closedbranches/') === false; + + $view = id(new ReleephProjectView()) + ->setShowOpenBranches($is_open_branches) + ->setUser($this->getRequest()->getUser()) + ->setReleephProject($releeph_project) + ->setBranches($releeph_branches); + + $crumbs = $this->buildApplicationCrumbs() + ->addCrumb( + id(new PhabricatorCrumbView()) + ->setName($releeph_project->getName()) + ->setHref($releeph_project->getURI())); + + if ($releeph_project->getIsActive()) { + $crumbs->addAction( + id(new PhabricatorMenuItemView()) + ->setHref($releeph_project->getURI('cutbranch')) + ->setName('Cut New Branch') + ->setIcon('create')); + } + + return $this->buildStandardPageResponse( + array( + $crumbs, + $view, + ), + array( + 'title' => $releeph_project->getName().' Releeph Project' + )); + } + +} diff --git a/src/applications/releeph/controller/request/ReleephRequestActionController.php b/src/applications/releeph/controller/request/ReleephRequestActionController.php new file mode 100644 index 000000000..f7229cda2 --- /dev/null +++ b/src/applications/releeph/controller/request/ReleephRequestActionController.php @@ -0,0 +1,71 @@ +<?php + +final class ReleephRequestActionController extends ReleephController { + + private $action; + + public function willProcessRequest(array $data) { + parent::willProcessRequest($data); + $this->action = $data['action']; + } + + public function processRequest() { + $request = $this->getRequest(); + + $releeph_branch = $this->getReleephBranch(); + $releeph_request = $this->getReleephRequest(); + + $releeph_branch->populateReleephRequestHandles( + $request->getUser(), array($releeph_request)); + + $action = $this->action; + + $user = $request->getUser(); + + $origin_uri = $releeph_request->loadReleephBranch()->getURI(); + + $editor = id(new ReleephRequestEditor($releeph_request)) + ->setActor($user); + + switch ($action) { + case 'want': + case 'pass': + static $action_map = array( + 'want' => ReleephRequest::INTENT_WANT, + 'pass' => ReleephRequest::INTENT_PASS); + $intent = $action_map[$action]; + $editor->changeUserIntent($user, $intent); + break; + + case 'mark-manually-picked': + $editor->markManuallyActioned('pick'); + break; + + case 'mark-manually-reverted': + $editor->markManuallyActioned('revert'); + break; + + default: + throw new Exception("unknown or unimplemented action {$action}"); + } + + // If we're adding a new user to userIntents, we'll have to re-populate + // request handles to load that user's data. + // + // This is cheap enough to do every time. + $this->getReleephBranch()->populateReleephRequestHandles( + $user, array($releeph_request)); + + $list = id(new ReleephRequestHeaderListView()) + ->setReleephProject($this->getReleephProject()) + ->setReleephBranch($this->getReleephBranch()) + ->setReleephRequests(array($releeph_request)) + ->setUser($request->getUser()) + ->setAphrontRequest($this->getRequest()) + ->setOriginType('request'); + + return id(new AphrontAjaxResponse())->setContent(array( + 'markup' => head($list->renderInner()) + )); + } +} diff --git a/src/applications/releeph/controller/request/ReleephRequestCreateController.php b/src/applications/releeph/controller/request/ReleephRequestCreateController.php new file mode 100644 index 000000000..21415fc54 --- /dev/null +++ b/src/applications/releeph/controller/request/ReleephRequestCreateController.php @@ -0,0 +1,165 @@ +<?php + +final class ReleephRequestCreateController extends ReleephController { + + const MAX_SUMMARY_LENGTH = 70; + + public function processRequest() { + $request = $this->getRequest(); + + // We arrived via /releeph/request/create/?branchID=$id + $releeph_branch_id = $request->getInt('branchID'); + if ($releeph_branch_id) { + $releeph_branch = id(new ReleephBranch())->load($releeph_branch_id); + } else { + // We arrived via /releeph/$project/$branch/request. + // + // If this throws an Exception, then somethind weird happened. + $releeph_branch = $this->getReleephBranch(); + } + + $releeph_project = $releeph_branch->loadReleephProject(); + $repo = $releeph_project->loadPhabricatorRepository(); + + $request_identifier = $request->getStr('requestIdentifierRaw'); + $e_request_identifier = true; + + $releeph_request = new ReleephRequest(); + + $errors = array(); + + $selector = $releeph_project->getReleephFieldSelector(); + $fields = $selector->getFieldSpecifications(); + foreach ($fields as $field) { + $field + ->setReleephProject($releeph_project) + ->setReleephBranch($releeph_branch) + ->setReleephRequest($releeph_request); + } + + if ($request->isFormPost()) { + foreach ($fields as $field) { + if ($field->isEditable()) { + try { + $field->setValueFromAphrontRequest($request); + } catch (ReleephFieldParseException $ex) { + $errors[] = $ex->getMessage(); + } + } + } + + $pr_commit = null; + $finder = id(new ReleephCommitFinder()) + ->setReleephProject($releeph_project); + try { + $pr_commit = $finder->fromPartial($request_identifier); + } catch (Exception $e) { + $e_request_identifier = 'Invalid'; + $errors[] = + "Request {$request_identifier} is probably not a valid commit"; + $errors[] = $e->getMessage(); + } + + $pr_commit_data = null; + if (!$errors) { + $pr_commit_data = $pr_commit->loadCommitData(); + if (!$pr_commit_data) { + $e_request_identifier = 'Not parsed yet'; + $errors[] = "The requested commit hasn't been parsed yet."; + } + } + + if (!$errors) { + $existing = id(new ReleephRequest()) + ->loadOneWhere('requestCommitPHID = %s AND branchID = %d', + $pr_commit->getPHID(), $releeph_branch->getID()); + + if ($existing) { + return id(new AphrontRedirectResponse()) + ->setURI('/releeph/request/edit/'.$existing->getID(). + '?existing=1'); + } + + id(new ReleephRequestEditor($releeph_request)) + ->setActor($request->getUser()) + ->create($pr_commit, $releeph_branch); + + return id(new AphrontRedirectResponse()) + ->setURI($releeph_branch->getURI()); + } + } + + $error_view = null; + if ($errors) { + $error_view = new AphrontErrorView(); + $error_view->setErrors($errors); + $error_view->setTitle('Form Errors'); + } + + // For the typeahead + $branch_cut_point = id(new PhabricatorRepositoryCommit()) + ->loadOneWhere( + 'phid = %s', + $releeph_branch->getCutPointCommitPHID()); + + // Build the form + $form = id(new AphrontFormView()) + ->setUser($request->getUser()); + + $origin = null; + $diff_rev_id = $request->getStr('D'); + if ($diff_rev_id) { + $diff_rev = id(new DifferentialRevision())->load($diff_rev_id); + $origin = '/D'.$diff_rev->getID(); + $title = sprintf( + 'D%d: %s', + $diff_rev_id, + $diff_rev->getTitle()); + $form + ->addHiddenInput('requestIdentifierRaw', 'D'.$diff_rev_id) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Diff') + ->setValue($title)); + } else { + $origin = $releeph_branch->getURI(); + $form->appendChild( + id(new ReleephRequestTypeaheadControl()) + ->setName('requestIdentifierRaw') + ->setLabel('Commit ID') + ->setRepo($repo) + ->setValue($request_identifier) + ->setError($e_request_identifier) + ->setStartTime($branch_cut_point->getEpoch()) + ->setCaption( + 'Start typing to autocomplete on commit title, '. + 'or give a Phabricator commit identifier like rFOO1234')); + } + + // Fields + foreach ($fields as $field) { + if ($field->isEditable()) { + $control = $field->renderEditControl($request); + $form->appendChild($control); + } + } + + $form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($origin) + ->setValue('Request')); + + $panel = id(new AphrontPanelView()) + ->setHeader( + 'Request for '. + $releeph_branch->getDisplayNameWithDetail()) + ->setWidth(AphrontPanelView::WIDTH_FORM) + ->appendChild($form); + + return $this->buildStandardPageResponse( + array($error_view, $panel), + array('title' => 'Request pick')); + } + +} diff --git a/src/applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php b/src/applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php new file mode 100644 index 000000000..9da50fa84 --- /dev/null +++ b/src/applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php @@ -0,0 +1,99 @@ +<?php + +final class ReleephRequestDifferentialCreateController + extends ReleephController { + + private $revision; + + public function willProcessRequest($data) { + $diff_rev_id = $data['diffRevID']; + $diff_rev = id(new DifferentialRevision())->load($diff_rev_id); + if (!$diff_rev) { + throw new Exception(sprintf('D%d not found!', $diff_rev_id)); + } + $this->revision = $diff_rev; + } + + public function processRequest() { + $request = $this->getRequest(); + $user = $request->getUser(); + + $arc_project = id(new PhabricatorRepositoryArcanistProject()) + ->loadOneWhere('phid = %s', $this->revision->getArcanistProjectPHID()); + + $projects = id(new ReleephProject())->loadAllWhere( + 'arcanistProjectID = %d AND isActive = 1', + $arc_project->getID()); + if (!$projects) { + throw new ReleephRequestException(sprintf( + "D%d belongs to the '%s' Arcanist project, ". + "which is not part of any Releeph project!", + $this->revision->getID(), + $arc_project->getName())); + } + + $branches = id(new ReleephBranch())->loadAllWhere( + 'releephProjectID IN (%Ld) AND isActive = 1', + mpull($projects, 'getID')); + if (!$branches) { + throw new ReleephRequestException(sprintf( + "D%d could be in the Releeph project(s) %s, ". + "but this project / none of these projects have open branches.", + $this->revision->getID(), + implode(', ', mpull($projects, 'getName')))); + } + + if (count($branches) === 1) { + return id(new AphrontRedirectResponse()) + ->setURI($this->buildReleephRequestURI(head($branches))); + } + + $projects = msort( + mpull($projects, null, 'getID'), + 'getName'); + + $branch_groups = mgroup($branches, 'getReleephProjectID'); + + require_celerity_resource('releeph-request-differential-create-dialog'); + $dialog = id(new AphrontDialogView()) + ->setUser($user) + ->setTitle('Choose Releeph Branch') + ->setClass('releeph-request-differential-create-dialog') + ->addCancelButton('/D'.$request->getStr('D')); + + $dialog->appendChild( + "This differential revision changes code that is associated ". + "with multiple Releeph branches. ". + "Please select the branch where you would like this code to be picked."); + + foreach ($branch_groups as $project_id => $branches) { + $project = idx($projects, $project_id); + $dialog->appendChild( + phutil_tag( + 'h1', + array(), + $project->getName())); + $branches = msort($branches, 'getBasename'); + foreach ($branches as $branch) { + $uri = $this->buildReleephRequestURI($branch); + $dialog->appendChild( + phutil_tag( + 'a', + array( + 'href' => $uri, + ), + $branch->getDisplayNameWithDetail())); + } + } + + return id(new AphrontDialogResponse) + ->setDialog($dialog); + } + + private function buildReleephRequestURI(ReleephBranch $branch) { + return id(new PhutilURI('/releeph/request/create/')) + ->setQueryParam('branchID', $branch->getID()) + ->setQueryParam('D', $this->revision->getID()); + } + +} diff --git a/src/applications/releeph/controller/request/ReleephRequestEditController.php b/src/applications/releeph/controller/request/ReleephRequestEditController.php new file mode 100644 index 000000000..eefe3bf60 --- /dev/null +++ b/src/applications/releeph/controller/request/ReleephRequestEditController.php @@ -0,0 +1,132 @@ +<?php + +final class ReleephRequestEditController extends ReleephController { + + public function processRequest() { + $request = $this->getRequest(); + + $releeph_branch = $this->getReleephBranch(); + $releeph_request = $this->getReleephRequest(); + + $releeph_branch->populateReleephRequestHandles( + $request->getUser(), array($releeph_request)); + + $phids = array(); + $phids[] = $releeph_request->getRequestCommitPHID(); + $phids[] = $releeph_request->getRequestUserPHID(); + $phids[] = $releeph_request->getCommittedByUserPHID(); + + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($request->getUser()) + ->loadHandles(); + + $age_string = phabricator_format_relative_time( + time() - $releeph_request->getDateCreated()); + + // Warn the user if we see this + $notice_view = null; + if ($request->getInt('existing')) { + $notice_messages = array( + 'You are editing an existing pick request!', + hsprintf( + "Requested %s ago by %s", + $age_string, + $handles[$releeph_request->getRequestUserPHID()]->renderLink()) + ); + $notice_view = id(new AphrontErrorView()) + ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) + ->setErrors($notice_messages); + } + + // <aidehua> epriestley: Is it common to pass around a referer URL to + // return from whence one came? [...] + // <epriestley> If you only have two places, maybe consider some parameter + // rather than the full URL. + switch ($request->getStr('origin')) { + case 'request': + $origin_uri = '/RQ'.$releeph_request->getID(); + break; + + case 'branch': + default: + $origin_uri = $releeph_request->loadReleephBranch()->getURI(); + break; + } + + $errors = array(); + + $selector = $this->getReleephProject()->getReleephFieldSelector(); + $fields = $selector->getFieldSpecifications(); + foreach ($fields as $field) { + $field + ->setReleephProject($this->getReleephProject()) + ->setReleephBranch($this->getReleephBranch()) + ->setReleephRequest($this->getReleephRequest()); + } + + if ($request->isFormPost()) { + foreach ($fields as $field) { + if ($field->isEditable()) { + try { + $field->setValueFromAphrontRequest($request); + } catch (ReleephFieldParseException $ex) { + $errors[] = $ex->getMessage(); + } + } + } + + if (!$errors) { + $releeph_request->save(); + return id(new AphrontRedirectResponse())->setURI($origin_uri); + } + } + + /** + * Build the rest of the page + */ + $error_view = null; + if ($errors) { + $error_view = new AphrontErrorView(); + $error_view->setErrors($errors); + $error_view->setTitle('Form Errors'); + } + + $form = id(new AphrontFormView()) + ->setUser($request->getUser()) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setLabel('Original Commit') + ->setValue( + $handles[$releeph_request->getRequestCommitPHID()]->renderLink())) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setLabel('Requestor') + ->setValue(hsprintf( + '%s %s ago', + $handles[$releeph_request->getRequestUserPHID()]->renderLink(), + $age_string))); + + // Fields + foreach ($fields as $field) { + if ($field->isEditable()) { + $control = $field->renderEditControl($request); + $form->appendChild($control); + } + } + + $form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($origin_uri, 'Cancel') + ->setValue('Save')); + + $panel = id(new AphrontPanelView()) + ->setHeader('Edit Pick Request') + ->setWidth(AphrontPanelView::WIDTH_FORM) + ->appendChild($form); + + return $this->buildStandardPageResponse( + array($notice_view, $error_view, $panel), + array('title', 'Edit Pick Request')); + } +} diff --git a/src/applications/releeph/controller/request/ReleephRequestTypeaheadController.php b/src/applications/releeph/controller/request/ReleephRequestTypeaheadController.php new file mode 100644 index 000000000..c86060c4b --- /dev/null +++ b/src/applications/releeph/controller/request/ReleephRequestTypeaheadController.php @@ -0,0 +1,92 @@ +<?php + +final class ReleephRequestTypeaheadController + extends PhabricatorTypeaheadDatasourceController { + + public function processRequest() { + $request = $this->getRequest(); + + $query = $request->getStr('q'); + $repo_id = $request->getInt('repo'); + $since = $request->getInt('since'); + $limit = $request->getInt('limit'); + + $now = time(); + $data = array(); + + // Dummy instances used for getting connections, table names, etc. + $pr_commit = new PhabricatorRepositoryCommit(); + $pr_commit_data = new PhabricatorRepositoryCommitData(); + + $conn = $pr_commit->establishConnection('r'); + + $rows = queryfx_all( + $conn, + 'SELECT + rc.phid as commitPHID, + rc.authorPHID, + rcd.authorName, + SUBSTRING(rcd.commitMessage, 1, 100) AS shortMessage, + rc.commitIdentifier, + rc.epoch + FROM %T rc + INNER JOIN %T rcd ON rcd.commitID = rc.id + WHERE repositoryID = %d + AND rc.epoch >= %d + AND ( + rcd.commitMessage LIKE %~ + OR + rc.commitIdentifier LIKE %~ + ) + ORDER BY rc.epoch DESC + LIMIT %d', + $pr_commit->getTableName(), + $pr_commit_data->getTableName(), + $repo_id, + $since, + $query, + $query, + $limit); + + foreach ($rows as $row) { + $full_commit_id = $row['commitIdentifier']; + $short_commit_id = substr($full_commit_id, 0, 12); + $first_line = $this->getFirstLine($row['shortMessage']); + $data[] = array( + $full_commit_id, + $short_commit_id, + $row['authorName'], + phabricator_format_relative_time($now - $row['epoch']), + $first_line, + ); + } + + return id(new AphrontAjaxResponse()) + ->setContent($data); + } + + /** + * Split either at the first new line, or a bunch of dashes. + * + * Really just a legacy from old Releeph Daemon commit messages where I used + * to say: + * + * Commit of FOO for BAR + * ------------ + * This does X Y Z + * + */ + private function getFirstLine($commit_message_fragment) { + static $separators = array('-------', "\n"); + $string = ltrim($commit_message_fragment); + $first_line = $string; + foreach ($separators as $separator) { + if ($pos = strpos($string, $separator)) { + $first_line = substr($string, 0, $pos); + break; + } + } + return $first_line; + } + +} diff --git a/src/applications/releeph/controller/request/ReleephRequestViewController.php b/src/applications/releeph/controller/request/ReleephRequestViewController.php new file mode 100644 index 000000000..f0cd2661f --- /dev/null +++ b/src/applications/releeph/controller/request/ReleephRequestViewController.php @@ -0,0 +1,99 @@ +<?php + +final class ReleephRequestViewController extends ReleephController { + + public function processRequest() { + $request = $this->getRequest(); + + $uri_path = $request->getRequestURI()->getPath(); + $legacy_prefix = '/releeph/request/'; + if (strncmp($uri_path, $legacy_prefix, strlen($legacy_prefix)) === 0) { + return id(new AphrontRedirectResponse()) + ->setURI('/RQ'.$this->getReleephRequest()->getID()); + } + + $releeph_request = $this->getReleephRequest(); + $releeph_branch = $this->getReleephBranch(); + $releeph_project = $this->getReleephProject(); + + $releeph_branch->populateReleephRequestHandles( + $request->getUser(), array($releeph_request)); + + $rq_view = + id(new ReleephRequestHeaderListView()) + ->setReleephProject($releeph_project) + ->setReleephBranch($releeph_branch) + ->setReleephRequests(array($releeph_request)) + ->setUser($request->getUser()) + ->setAphrontRequest($this->getRequest()) + ->setReloadOnStateChange(true) + ->setOriginType('request'); + + $events = $releeph_request->loadEvents(); + $phids = array_mergev(mpull($events, 'extractPHIDs')); + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($request->getUser()) + ->loadHandles(); + + $rq_event_list_view = + id(new ReleephRequestEventListView()) + ->setUser($request->getUser()) + ->setEvents($events) + ->setHandles($handles); + + // Handle comment submit + $origin_uri = '/RQ'.$releeph_request->getID(); + if ($request->isFormPost()) { + id(new ReleephRequestEditor($releeph_request)) + ->setActor($request->getUser()) + ->addComment($request->getStr('comment')); + return id(new AphrontRedirectResponse())->setURI($origin_uri); + } + + $form = id(new AphrontFormView()) + ->setUser($request->getUser()) + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setName('comment')) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($origin_uri, 'Cancel') + ->setValue("Submit")); + + $rq_comment_form = id(new AphrontPanelView()) + ->setHeader('Add a comment') + ->setWidth(AphrontPanelView::WIDTH_FULL) + ->appendChild($form); + + $title = hsprintf("RQ%d: %s", + $releeph_request->getID(), + $releeph_request->getSummaryForDisplay()); + + $crumbs = $this->buildApplicationCrumbs() + ->addCrumb( + id(new PhabricatorCrumbView()) + ->setName($releeph_project->getName()) + ->setHref($releeph_project->getURI())) + ->addCrumb( + id(new PhabricatorCrumbView()) + ->setName($releeph_branch->getDisplayNameWithDetail()) + ->setHref($releeph_branch->getURI())) + ->addCrumb( + id(new PhabricatorCrumbView()) + ->setName('RQ'.$releeph_request->getID()) + ->setHref('/RQ'.$releeph_request->getID())); + + return $this->buildStandardPageResponse( + array( + $crumbs, + array( + $rq_view, + $rq_event_list_view, + $rq_comment_form + ) + ), + array( + 'title' => $title + )); + } +} diff --git a/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php b/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php new file mode 100644 index 000000000..840241747 --- /dev/null +++ b/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php @@ -0,0 +1,348 @@ +<?php + +/** + * This DifferentialFieldSpecification exists for two reason: + * + * 1: To parse "Releeph: picks RQ<nn>" headers in commits created by + * arc-releeph so that RQs committed by arc-releeph have real + * PhabricatorRepositoryCommits associated with them (instaed of just the SHA + * of the commit, as seen by the pusher). + * + * 2: If requestors want to commit directly to their release branch, they can + * use this header to (i) indicate on a differential revision that this + * differential revision is for the release branch, and (ii) when they land + * their diff on to the release branch manually, the ReleephRequest is + * automatically updated (instead of having to use the "Mark Manually Picked" + * button.) + * + */ +final class DifferentialReleephRequestFieldSpecification + extends DifferentialFieldSpecification { + + const ACTION_PICKS = 'picks'; + const ACTION_REVERTS = 'reverts'; + + private $releephAction; + private $releephPHIDs = array(); + + public function getStorageKey() { + return 'releeph:actions'; + } + + public function getValueForStorage() { + return json_encode(array( + 'releephAction' => $this->releephAction, + 'releephPHIDs' => $this->releephPHIDs, + )); + } + + public function setValueFromStorage($json) { + if ($json) { + $dict = json_decode($json, true); + $this->releephAction = idx($dict, 'releephAction'); + $this->releephPHIDs = idx($dict, 'releephPHIDs'); + } + return $this; + } + + public function shouldAppearOnRevisionView() { + return true; + } + + public function renderLabelForRevisionView() { + return 'Releeph'; + } + + public function getRequiredHandlePHIDs() { + return mpull($this->loadReleephRequests(), 'getPHID'); + } + + public function renderValueForRevisionView() { + static $tense = array( + self::ACTION_PICKS => array( + 'future' => 'Will pick', + 'past' => 'Picked', + ), + self::ACTION_REVERTS => array( + 'future' => 'Will revert', + 'past' => 'Reverted', + ), + ); + + $releeph_requests = $this->loadReleephRequests(); + if (!$releeph_requests) { + return null; + } + + $status = $this->getRevision()->getStatus(); + if ($status == ArcanistDifferentialRevisionStatus::CLOSED) { + $verb = $tense[$this->releephAction]['past']; + } else { + $verb = $tense[$this->releephAction]['future']; + } + + $parts = hsprintf('%s...', $verb); + foreach ($releeph_requests as $releeph_request) { + $parts->appendHTML(phutil_tag('br')); + $parts->appendHTML( + $this->getHandle($releeph_request->getPHID())->renderLink()); + } + + return $parts; + } + + public function shouldAppearOnCommitMessage() { + return true; + } + + public function getCommitMessageKey() { + return 'releephActions'; + } + + public function setValueFromParsedCommitMessage($dict) { + $this->releephAction = $dict['releephAction']; + $this->releephPHIDs = $dict['releephPHIDs']; + return $this; + } + + public function renderValueForCommitMessage($is_edit) { + $releeph_requests = $this->loadReleephRequests(); + if (!$releeph_requests) { + return null; + } + + $parts = array($this->releephAction); + foreach ($releeph_requests as $releeph_request) { + $parts[] = 'RQ'.$releeph_request->getID(); + } + + return implode(' ', $parts); + } + + /** + * Releeph fields should look like: + * + * Releeph: picks RQ1 RQ2, RQ3 + * Releeph: reverts RQ1 + */ + public function parseValueFromCommitMessage($value) { + /** + * Releeph commit messages look like this (but with more blank lines, + * omitted here): + * + * Make CaptainHaddock more reasonable + * Releeph: picks RQ1 + * Requested By: edward + * Approved By: edward (requestor) + * Request Reason: x + * Summary: Make the Haddock implementation more reasonable. + * Test Plan: none + * Reviewers: user1 + * + * Some of these fields are recognized by Differential (e.g. "Requested + * By"). They are folded up into the "Releeph" field, parsed by this + * class. As such $value includes more than just the first-line: + * + * "picks RQ1\n\nRequested By: edward\n\nApproved By: edward (requestor)" + * + * To hack around this, just consider the first line of $value when + * determining what Releeph actions the parsed commit is performing. + */ + $first_line = head(array_filter(explode("\n", $value))); + + $tokens = preg_split('/\s*,?\s+/', $first_line); + $raw_action = array_shift($tokens); + $action = strtolower($raw_action); + + if (!$action) { + return null; + } + + switch ($action) { + case self::ACTION_REVERTS: + case self::ACTION_PICKS: + break; + + default: + throw new DifferentialFieldParseException( + "Commit message contains unknown Releeph action '{$raw_action}'!"); + break; + } + + $releeph_requests = array(); + foreach ($tokens as $token) { + $match = array(); + if (!preg_match('/^(?:RQ)?(\d+)$/i', $token, $match)) { + $label = $this->renderLabelForCommitMessage(); + throw new DifferentialFieldParseException( + "Commit message contains unparseable ". + "Releeph request token '{$token}'!"); + } + + $id = (int) $match[1]; + $releeph_request = id(new ReleephRequest())->load($id); + + if (!$releeph_request) { + throw new DifferentialFieldParseException( + "Commit message references non existent releeph request: {$value}!"); + } + + $releeph_requests[] = $releeph_request; + } + + if (count($releeph_requests) > 1) { + $rqs_seen = array(); + $groups = array(); + foreach ($releeph_requests as $releeph_request) { + $releeph_branch = $releeph_request->loadReleephBranch(); + $branch_name = $releeph_branch->getName(); + $rq_id = 'RQ'.$releeph_request->getID(); + + if (idx($rqs_seen, $rq_id)) { + throw new DifferentialFieldParseException( + "Commit message refers to {$rq_id} multiple times!"); + } + $rqs_seen[$rq_id] = true; + + if (!isset($groups[$branch_name])) { + $groups[$branch_name] = array(); + } + $groups[$branch_name][] = $rq_id; + } + + if (count($groups) > 1) { + $lists = array(); + foreach ($groups as $branch_name => $rq_ids) { + $lists[] = implode(', ', $rq_ids).' in '.$branch_name; + } + throw new DifferentialFieldParseException( + "Commit message references multiple Releeph requests, ". + "but the requests are in different branches: ". + implode('; ', $lists)); + } + } + + $phids = mpull($releeph_requests, 'getPHID'); + + $data = array( + 'releephAction' => $action, + 'releephPHIDs' => $phids, + ); + return $data; + } + + public function renderLabelForCommitMessage() { + return 'Releeph'; + } + + public function shouldAppearOnCommitMessageTemplate() { + return false; + } + + public function didParseCommit(PhabricatorRepository $repo, + PhabricatorRepositoryCommit $commit, + PhabricatorRepositoryCommitData $data) { + + $releeph_requests = $this->loadReleephRequests(); + + if (!$releeph_requests) { + return; + } + + $releeph_branch = head($releeph_requests)->loadReleephBranch(); + if (!$this->isCommitOnBranch($repo, $commit, $releeph_branch)) { + return; + } + + foreach ($releeph_requests as $releeph_request) { + if ($this->releephAction === self::ACTION_PICKS) { + $action = 'pick'; + } else { + $action = 'revert'; + } + + $actor_phid = coalesce( + $data->getCommitDetail('committerPHID'), + $data->getCommitDetail('authorPHID')); + + $actor = id(new PhabricatorUser()) + ->loadOneWhere('phid = %s', $actor_phid); + + id(new ReleephRequestEditor($releeph_request)) + ->setActor($actor) + ->discoverCommit($action, $commit, $data); + } + } + + private function loadReleephRequests() { + if (!$this->releephPHIDs) { + return array(); + } else { + return id(new ReleephRequest()) + ->loadAllWhere('phid IN (%Ls)', $this->releephPHIDs); + } + } + + private function isCommitOnBranch(PhabricatorRepository $repo, + PhabricatorRepositoryCommit $commit, + ReleephBranch $releeph_branch) { + + switch ($repo->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + list($output) = $repo->execxLocalCommand( + 'branch --all --no-color --contains %s', + $commit->getCommitIdentifier()); + + $remote_prefix = 'remotes/origin/'; + $branches = array(); + foreach (array_filter(explode("\n", $output)) as $line) { + $tokens = explode(' ', $line); + $ref = last($tokens); + if (strncmp($ref, $remote_prefix, strlen($remote_prefix)) === 0) { + $branch = substr($ref, strlen($remote_prefix)); + $branches[$branch] = $branch; + } + } + + return idx($branches, $releeph_branch->getName()); + break; + + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $change_query = DiffusionPathChangeQuery::newFromDiffusionRequest( + DiffusionRequest::newFromDictionary(array( + 'repository' => $repo, + 'commit' => $commit->getCommitIdentifier(), + ))); + $path_changes = $change_query->loadChanges(); + $commit_paths = mpull($path_changes, 'getPath'); + + $branch_path = $releeph_branch->getName(); + + $in_branch = array(); + $ex_branch = array(); + foreach ($commit_paths as $path) { + if (strncmp($path, $branch_path, strlen($branch_path)) === 0) { + $in_branch[] = $path; + } else { + $ex_branch[] = $path; + } + } + + if ($in_branch && $ex_branch) { + $error = sprintf( + "CONFUSION: commit %s in %s contains %d path change(s) that were ". + "part of a Releeph branch, but also has %d path change(s) not ". + "part of a Releeph branch!", + $commit->getCommitIdentifier(), + $repo->getCallsign(), + count($in_branch), + count($ex_branch)); + phlog($error); + } + + return !empty($in_branch); + break; + } + } + +} diff --git a/src/applications/releeph/differential/ReleephDifferentialRevisionDetailRenderer.php b/src/applications/releeph/differential/ReleephDifferentialRevisionDetailRenderer.php new file mode 100644 index 000000000..fbff6983f --- /dev/null +++ b/src/applications/releeph/differential/ReleephDifferentialRevisionDetailRenderer.php @@ -0,0 +1,39 @@ +<?php + +final class ReleephDifferentialRevisionDetailRenderer { + + public static function generateActionLink(DifferentialRevision $revision, + DifferentialDiff $diff) { + + $arc_project = $diff->loadArcanistProject(); // 93us + if (!$arc_project) { + return; + } + + $releeph_projects = id(new ReleephProject())->loadAllWhere( + 'arcanistProjectID = %d AND isActive = 1', + $arc_project->getID()); + + if (!$releeph_projects) { + return; + } + + $releeph_branches = id(new ReleephBranch())->loadAllWhere( + 'releephProjectID IN (%Ld) AND isActive = 1', + mpull($releeph_projects, 'getID')); + + if (!$releeph_branches) { + return; + } + + $uri = new PhutilURI( + '/releeph/request/differentialcreate/D'.$revision->getID()); + return array( + 'name' => 'Releeph Request', + 'sigil' => 'workflow', + 'href' => $uri, + 'icon' => 'fork', + ); + } + +} diff --git a/src/applications/releeph/editor/ReleephBranchEditor.php b/src/applications/releeph/editor/ReleephBranchEditor.php new file mode 100644 index 000000000..d3f679502 --- /dev/null +++ b/src/applications/releeph/editor/ReleephBranchEditor.php @@ -0,0 +1,106 @@ +<?php + +final class ReleephBranchEditor extends PhabricatorEditor { + + private $releephProject; + private $releephBranch; + + public function setReleephProject(ReleephProject $rp) { + $this->releephProject = $rp; + return $this; + } + + public function setReleephBranch(ReleephBranch $branch) { + $this->releephBranch = $branch; + return $this; + } + + public function newBranchFromCommit(PhabricatorRepositoryCommit $cut_point, + $branch_date, + $symbolic_name = null) { + + $template = $this->releephProject->getDetail('branchTemplate'); + if (!$template) { + $template = ReleephBranchTemplate::getRequiredDefaultTemplate(); + } + + $cut_point_handle = head( + id(new PhabricatorObjectHandleData(array($cut_point->getPHID()))) + // We'll assume that whoever found the $cut_point has passed privacy + // checks. + ->setViewer($this->requireActor()) + ->loadHandles()); + + list($name, $errors) = id(new ReleephBranchTemplate()) + ->setCommitHandle($cut_point_handle) + ->setBranchDate($branch_date) + ->setReleephProjectName($this->releephProject->getName()) + ->interpolate($template); + + $basename = last(explode('/', $name)); + + $table = id(new ReleephBranch()); + $transaction = $table->openTransaction(); + $branch = id(new ReleephBranch()) + ->setName($name) + ->setBasename($basename) + ->setReleephProjectID($this->releephProject->getID()) + ->setCreatedByUserPHID($this->requireActor()->getPHID()) + ->setCutPointCommitIdentifier($cut_point->getCommitIdentifier()) + ->setCutPointCommitPHID($cut_point->getPHID()) + ->setIsActive(1) + ->setDetail('branchDate', $branch_date) + ->save(); + + /** + * Steal the symbolic name from any other branch that has it (in this + * project). + */ + if ($symbolic_name) { + $others = id(new ReleephBranch())->loadAllWhere( + 'releephProjectID = %d', + $this->releephProject->getID()); + foreach ($others as $other) { + if ($other->getSymbolicName() == $symbolic_name) { + $other + ->setSymbolicName(null) + ->save(); + } + } + $branch + ->setSymbolicName($symbolic_name) + ->save(); + } + + id(new ReleephEvent()) + ->setType(ReleephEvent::TYPE_BRANCH_CREATE) + ->setActorPHID($this->requireActor()->getPHID()) + ->setReleephProjectID($this->releephProject->getID()) + ->setReleephBranchID($branch->getID()) + ->save(); + + $table->saveTransaction(); + return $branch; + } + + // aka "close" and "reopen" + public function changeBranchAccess($is_active) { + $branch = $this->releephBranch; + $branch->openTransaction(); + + $branch + ->setIsActive((int)$is_active) + ->save(); + + id(new ReleephEvent()) + ->setType(ReleephEvent::TYPE_BRANCH_ACCESS) + ->setActorPHID($this->requireActor()->getPHID()) + ->setReleephProjectID($branch->getReleephProjectID()) + ->setReleephBranchID($branch->getID()) + ->setDetail('isActive', $is_active) + ->save(); + + $branch->saveTransaction(); + } + +} diff --git a/src/applications/releeph/editor/ReleephRequestEditor.php b/src/applications/releeph/editor/ReleephRequestEditor.php new file mode 100644 index 000000000..8cb0945e2 --- /dev/null +++ b/src/applications/releeph/editor/ReleephRequestEditor.php @@ -0,0 +1,408 @@ +<?php + +/** + * Provide methods for the common ways of creating and mutating a + * ReleephRequest, sending email when something interesting happens. + * + * This class generates ReleephRequestEvents, and each type of event + * (ReleephRequestEvent::TYPE_*) corresponds to one of the editor methods. + * + * The editor methods (except for create() use newEvent() and commit() to save + * some code duplication. + */ +final class ReleephRequestEditor extends PhabricatorEditor { + + private $releephRequest; + private $event; + private $silentUpdate; + + public function __construct(ReleephRequest $rq) { + $this->releephRequest = $rq; + } + + public function setSilentUpdate($silent) { + $this->silentUpdate = $silent; + return $this; + } + + +/* -( ReleephRequest edit methods )---------------------------------------- */ + + /** + * Request a PhabricatorRepositoryCommit to be committed to the given + * ReleephBranch. + */ + public function create(PhabricatorRepositoryCommit $commit, + ReleephBranch $branch) { + + // We can't use newEvent() / commit() abstractions, so do what those + // helpers do manually. + $requestor = $this->requireActor(); + + $rq = $this->releephRequest; + $rq->openTransaction(); + + $rq + ->setBranchID($branch->getID()) + ->setRequestCommitIdentifier($commit->getCommitIdentifier()) + ->setRequestCommitPHID($commit->getPHID()) + ->setRequestCommitOrdinal($commit->getID()) + ->setInBranch(0) + ->setRequestUserPHID($requestor->getPHID()) + ->setUserIntent($requestor, ReleephRequest::INTENT_WANT) + ->save(); + + $event = id(new ReleephRequestEvent()) + ->setType(ReleephRequestEvent::TYPE_CREATE) + ->setActorPHID($requestor->getPHID()) + ->setStatusBefore(null) + ->setStatusAfter($rq->getStatus()) + ->setReleephRequestID($rq->getID()) + ->setDetail('commitPHID', $commit->getPHID()) + ->save(); + + $rq->saveTransaction(); + + // Mail + if (!$this->silentUpdate) { + $project = $this->releephRequest->loadReleephProject(); + $mail = id(new ReleephRequestMail()) + ->setReleephRequest($this->releephRequest) + ->setReleephProject($project) + ->setEvents(array($event)) + ->setSenderAndRecipientPHID($requestor->getPHID()) + ->addTos(ReleephRequestMail::ENT_ALL_PUSHERS) + ->addCCs(ReleephRequestMail::ENT_REQUESTOR) + ->send(); + } + } + + /** + * Record whether the PhabricatorUser wants or passes on this request. + */ + public function changeUserIntent(PhabricatorUser $user, $intent) { + $project = $this->releephRequest->loadReleephProject(); + $is_pusher = $project->isPusher($user); + + $event = $this->newEvent() + ->setType(ReleephRequestEvent::TYPE_USER_INTENT) + ->setDetail('userPHID', $user->getPHID()) + ->setDetail('wasPusher', $is_pusher) + ->setDetail('newIntent', $intent); + + $this->releephRequest + ->setUserIntent($user, $intent); + + $this->commit(); + + // Mail if this is 'interesting' + if (!$this->silentUpdate && + $event->getStatusBefore() != $event->getStatusAfter()) { + + $project = $this->releephRequest->loadReleephProject(); + $mail = id(new ReleephRequestMail()) + ->setReleephRequest($this->releephRequest) + ->setReleephProject($project) + ->setEvents(array($event)) + ->setSenderAndRecipientPHID($this->requireActor()->getPHID()) + ->addTos(ReleephRequestMail::ENT_REQUESTOR) + ->addCCs(ReleephRequestMail::ENT_INTERESTED_PUSHERS) + ->send(); + } + } + + /** + * Record the results of someone trying to pick or revert a request in their + * local repository, to give advance warning that something doesn't pick or + * revert cleanly. + */ + public function changePickStatus($pick_status, $dry_run, $details) { + $event = $this->newEvent() + ->setType(ReleephRequestEvent::TYPE_PICK_STATUS) + ->setDetail('newPickStatus', $pick_status) + ->setDetail('commitDetails', $details); + $this->releephRequest->setPickStatus($pick_status); + $this->commit(); + + // Failures should generate an email + if (!$this->silentUpdate && + !$dry_run && + ($pick_status == ReleephRequest::PICK_FAILED || + $pick_status == ReleephRequest::REVERT_FAILED)) { + + $project = $this->releephRequest->loadReleephProject(); + $mail = id(new ReleephRequestMail()) + ->setReleephRequest($this->releephRequest) + ->setReleephProject($project) + ->setEvents(array($event)) + ->setSenderAndRecipientPHID($this->requireActor()->getPHID()) + ->addTos(ReleephRequestMail::ENT_REQUESTOR) + ->addCCs(ReleephRequestMail::ENT_ACTORS) + ->addCCs(ReleephRequestMail::ENT_INTERESTED_PUSHERS) + ->send(); + } + } + + /** + * Record that a request was committed locally, and is about to be pushed to + * the remote repository. + * + * This lets us mark a ReleephRequest as being in a branch in real time so + * that no one else tries to pick it. + * + * When the daemons discover this commit in the repository with + * DifferentialReleephRequestFieldSpecification, we'll be able to recrod the + * commit's PHID as well. That process is slow though, and + * we don't want to wait a whole minute before marking something as cleanly + * picked or reverted. + */ + public function recordSuccessfulCommit($action, $new_commit_id) { + $table = $this->releephRequest; + $table->openTransaction(); + + $actor = $this->requireActor(); + + $event = id(new ReleephRequestEvent()) + ->setReleephRequestID($this->releephRequest->getID()) + ->setActorPHID($actor->getPHID()) + ->setType(ReleephRequestEvent::TYPE_COMMIT) + ->setDetail('action', $action) + ->setDetail('newCommitIdentifier', $new_commit_id) + ->save(); + + switch ($action) { + case 'pick': + $this->releephRequest + ->setInBranch(1) + ->setPickStatus(ReleephRequest::PICK_OK) + ->setCommitIdentifier($new_commit_id) + ->setCommitPHID(null) + ->setCommittedByUserPHID($actor->getPHID()) + ->save(); + break; + + case 'revert': + $this->releephRequest + ->setInBranch(0) + ->setPickStatus(ReleephRequest::REVERT_OK) + ->setCommitIdentifier(null) + ->setCommitPHID(null) + ->setCommittedByUserPHID(null) + ->save(); + break; + + default: + $table->killTransaction(); + throw new Exception("Unknown action {$action}!"); + break; + } + + $table->saveTransaction(); + + // Don't spam people about local commits -- we'll do that with + // discoverCommit() instead! + } + + /** + * Mark this request as picked or reverted based on discovering it in the + * branch. We have a PhabricatorRepositoryCommit, so we're able to + * setCommitPHID on the ReleephRequest (unlike recordSuccessfulCommit()). + */ + public function discoverCommit( + $action, + PhabricatorRepositoryCommit $commit, + PhabricatorRepositoryCommitData $data) { + + $table = $this->releephRequest; + $table->openTransaction(); + $table->beginWriteLocking(); + + $past_events = id(new ReleephRequestEvent())->loadAllWhere( + 'releephRequestID = %d AND type = %s', + $this->releephRequest->getID(), + ReleephRequestEvent::TYPE_DISCOVERY); + + foreach ($past_events as $past_event) { + if ($past_event->getDetail('newCommitIdentifier') + == $commit->getCommitIdentifier()) { + + // Avoid re-discovery if reparsing! + $table->endWriteLocking(); + $table->killTransaction(); + return; + } + } + + $actor = $this->requireActor(); + + $event = id(new ReleephRequestEvent()) + ->setReleephRequestID($this->releephRequest->getID()) + ->setActorPHID($actor->getPHID()) + ->setType(ReleephRequestEvent::TYPE_DISCOVERY) + ->setDateCreated($commit->getEpoch()) + ->setDetail('action', $action) + ->setDetail('newCommitIdentifier', $commit->getCommitIdentifier()) + ->setDetail('newCommitPHID', $commit->getPHID()) + ->setDetail('authorPHID', $data->getCommitDetail('authorPHID')) + ->setDetail('committerPHID', $data->getCommitDetail('committerPHID')) + ->save(); + + switch ($action) { + case 'pick': + $this->releephRequest + ->setInBranch(1) + ->setPickStatus(ReleephRequest::PICK_OK) + ->setCommitIdentifier($commit->getCommitIdentifier()) + ->setCommitPHID($commit->getPHID()) + ->setCommittedByUserPHID($actor->getPHID()) + ->save(); + break; + + case 'revert': + $this->releephRequest + ->setInBranch(0) + ->setPickStatus(ReleephRequest::REVERT_OK) + ->setCommitIdentifier(null) + ->setCommitPHID(null) + ->setCommittedByUserPHID(null) + ->save(); + break; + + default: + $table->killTransaction(); + throw new Exception("Unknown action {$action}!"); + break; + } + + $table->endWriteLocking(); + $table->saveTransaction(); + + // Mail + if (!$this->silentUpdate) { + $project = $this->releephRequest->loadReleephProject(); + $mail = id(new ReleephRequestMail()) + ->setReleephRequest($this->releephRequest) + ->setReleephProject($project) + ->setEvents(array($event)) + ->setSenderAndRecipientPHID($this->requireActor()->getPHID()) + ->addTos(ReleephRequestMail::ENT_REQUESTOR) + ->addCCs(ReleephRequestMail::ENT_ACTORS) + ->addCCs(ReleephRequestMail::ENT_INTERESTED_PUSHERS) + ->send(); + } + } + + public function addComment($comment) { + $event = $this->newEvent() + ->setType(ReleephRequestEvent::TYPE_COMMENT) + ->setDetail('comment', $comment); + $this->commit(); + + // Mail + if (!$this->silentUpdate) { + $project = $this->releephRequest->loadReleephProject(); + $mail = id(new ReleephRequestMail()) + ->setReleephRequest($this->releephRequest) + ->setReleephProject($project) + ->setEvents(array($event)) + ->setSenderAndRecipientPHID($this->requireActor()->getPHID()) + ->addTos(ReleephRequestMail::ENT_REQUESTOR) + ->addCCs(ReleephRequestMail::ENT_ACTORS) + ->addCCs(ReleephRequestMail::ENT_INTERESTED_PUSHERS) + ->send(); + } + } + + public function markManuallyActioned($action) { + $event = $this->newEvent() + ->setType(ReleephRequestEvent::TYPE_MANUAL_ACTION) + ->setDetail('action', $action); + + $actor = $this->requireActor(); + $project = $this->releephRequest->loadReleephProject(); + $requestor_phid = $this->releephRequest->getRequestUserPHID(); + if (!$project->isPusher($actor) && + $actor->getPHID() !== $requestor_phid) { + + throw new Exception( + "Only pushers or requestors can mark requests as ". + "manually picked or reverted!"); + } + + switch ($action) { + case 'pick': + $in_branch = true; + $intent = ReleephRequest::INTENT_WANT; + break; + + case 'revert': + $in_branch = false; + $intent = ReleephRequest::INTENT_PASS; + break; + + default: + throw new Exception("Unknown action {$action}!"); + break; + } + + $this->releephRequest + ->setInBranch((int)$in_branch) + ->setUserIntent($this->getActor(), $intent); + + $this->commit(); + + // Mail + if (!$this->silentUpdate) { + $project = $this->releephRequest->loadReleephProject(); + $mail = id(new ReleephRequestMail()) + ->setReleephRequest($this->releephRequest) + ->setReleephProject($project) + ->setEvents(array($event)) + ->setSenderAndRecipientPHID($this->requireActor()->getPHID()) + ->addTos(ReleephRequestMail::ENT_REQUESTOR) + ->addCCs(ReleephRequestMail::ENT_INTERESTED_PUSHERS) + ->send(); + } + } + +/* -( Implementation )----------------------------------------------------- */ + + /** + * Create and return a new ReleephRequestEvent bound to the editor's + * ReleephRequest, inside a transaction. + * + * When you call commit(), the event and this editor's ReleephRequest (along + * with any changes you made to the ReleephRequest) are saved and the + * transaction committed. + */ + private function newEvent() { + $actor = $this->requireActor(); + + if ($this->event) { + throw new Exception("You have already called newEvent()!"); + } + $rq = $this->releephRequest; + $rq->openTransaction(); + + $this->event = id(new ReleephRequestEvent()) + ->setReleephRequestID($rq->getID()) + ->setActorPHID($actor->getPHID()) + ->setStatusBefore($rq->getStatus()); + + return $this->event; + } + + private function commit() { + if (!$this->event) { + throw new Exception("You must call newEvent first!"); + } + $rq = $this->releephRequest; + $this->event + ->setStatusAfter($rq->getStatus()) + ->save(); + $rq->save(); + $rq->saveTransaction(); + $this->event = null; + } + +} diff --git a/src/applications/releeph/editor/mail/ReleephRequestMail.php b/src/applications/releeph/editor/mail/ReleephRequestMail.php new file mode 100644 index 000000000..a06f6f334 --- /dev/null +++ b/src/applications/releeph/editor/mail/ReleephRequestMail.php @@ -0,0 +1,213 @@ +<?php + +/** + * Build an email that renders a group of events with and appends some standard + * Releeph things (a URI for this request, and this branch). + * + * Also includes some helper stuff for adding groups of people to the To: and + * Cc: headers. + */ +final class ReleephRequestMail { + + const ENT_REQUESTOR = 'requestor'; + const ENT_DIFF = 'diff'; + const ENT_ALL_PUSHERS = 'pushers'; + const ENT_ACTORS = 'actors'; + const ENT_INTERESTED_PUSHERS = 'interested-pushers'; + + private $sender; + private $tos = array(); + private $ccs = array(); + private $events; + private $releephRequest; + private $releephProject; + + public function setReleephRequest(ReleephRequest $rq) { + $this->releephRequest = $rq; + return $this; + } + + public function setReleephProject(ReleephProject $rp) { + $this->releephProject = $rp; + return $this; + } + + public function setEvents(array $events) { + assert_instances_of($events, 'ReleephRequestEvent'); + $this->events = $events; + return $this; + } + + public function setSenderAndRecipientPHID($sender_phid) { + $this->sender = $sender_phid; + $this->tos[] = $sender_phid; + return $this; + } + + public function addTos($entity) { + $this->tos = array_merge( + $this->tos, + $this->getEntityPHIDs($entity)); + return $this; + } + + public function addCcs($entity) { + $this->ccs = array_merge( + $this->tos, + $this->getEntityPHIDs($entity)); + return $this; + } + + public function send() { + $this->buildMail()->save(); + } + + public function buildMail() { + return id(new PhabricatorMetaMTAMail()) + ->setSubject($this->renderSubject()) + ->setBody($this->buildBody()->render()) + ->setFrom($this->sender) + ->addTos($this->tos) + ->addCCs($this->ccs); + } + + private function getEntityPHIDs($entity) { + $phids = array(); + switch ($entity) { + // The requestor + case self::ENT_REQUESTOR: + $phids[] = $this->releephRequest->getRequestUserPHID(); + break; + + // People on the original diff + case self::ENT_DIFF: + $commit = $this->releephRequest->loadPhabricatorRepositoryCommit(); + $commit_data = $commit->loadCommitData(); + if ($commit_data) { + $phids[] = $commit_data->getCommitDetail('reviewerPHID'); + $phids[] = $commit_data->getCommitDetail('authorPHID'); + } + break; + + // All pushers for this project + case self::ENT_ALL_PUSHERS: + $phids = array_merge( + $phids, + $this->releephProject->getPushers()); + break; + + // Pushers who have explicitly wanted or passed on this request + case self::ENT_INTERESTED_PUSHERS: + $all_pushers = $this->releephProject->getPushers(); + $intents = $this->releephRequest->getUserIntents(); + foreach ($all_pushers as $pusher) { + if (idx($intents, $pusher)) { + $phids[] = $pusher; + } + } + break; + + // Anyone who created our list of events + case self::ENT_ACTORS: + $phids = array_merge( + $phids, + mpull($this->events, 'getActorPHID')); + break; + + default: + throw new Exception( + "Unknown entity type {$entity}!"); + break; + } + + return array_filter($phids); + } + + private function buildBody() { + $body = new PhabricatorMetaMTAMailBody(); + $rq = $this->releephRequest; + + // Events and comments + $phids = array( + $rq->getPHID(), + ); + foreach ($this->events as $event) { + $phids = array_merge($phids, $event->extractPHIDs()); + } + $handles = id(new PhabricatorObjectHandleData($phids)) + // By the time we're generating email, we can assume that whichever + // entitties are receving the email are authorized to see the loaded + // handles! + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->loadHandles(); + + $raw_events = id(new ReleephRequestEventListView()) + ->setUser(PhabricatorUser::getOmnipotentUser()) + ->setHandles($handles) + ->setEvents($this->events) + ->renderForEmail(); + + $body->addRawSection($raw_events); + + $project = $rq->loadReleephProject(); + $branch = $rq->loadReleephBranch(); + + /** + * If any of the events we are emailing about were TYPE_PICK_STATUS where + * the newPickStatus was a pick failure (and/or a revert failure?), include + * pick failure instructions. + */ + $pick_failure_events = array(); + foreach ($this->events as $event) { + if ($event->getType() == ReleephRequestEvent::TYPE_PICK_STATUS && + $event->getDetail('newPickStatus') == ReleephRequest::PICK_FAILED) { + + $pick_failure_events[] = $event; + } + } + + if ($pick_failure_events) { + $instructions = $project->getDetail('pick_failure_instructions'); + if ($instructions) { + $body->addTextSection('PICK FAILURE INSTRUCTIONS', $instructions); + } + } + + // Common stuff at the end + $body->addTextSection( + 'RELEEPH REQUEST', + $handles[$rq->getPHID()]->getFullName()."\n". + PhabricatorEnv::getProductionURI('/RQ'.$rq->getID())); + + $project_and_branch = sprintf( + '%s - %s', + $project->getName(), + $branch->getDisplayNameWithDetail()); + + $body->addTextSection( + 'RELEEPH BRANCH', + $project_and_branch."\n". + $branch->getURI()); + + // But verbose stuff at the *very* end! + foreach ($pick_failure_events as $event) { + $failure_details = $event->getDetail('commitDetails'); + if ($failure_details) { + $body->addRawSection('PICK FAILURE DETAILS'); + foreach ($failure_details as $heading => $data) { + $body->addTextSection($heading, $data); + } + } + } + + return $body; + } + + private function renderSubject() { + $rq = $this->releephRequest; + $id = $rq->getID(); + $summary = $rq->getSummaryForDisplay(); + return "RQ{$id}: {$summary}"; + } + +} diff --git a/src/applications/releeph/field/exception/ReleephFieldParseException.php b/src/applications/releeph/field/exception/ReleephFieldParseException.php new file mode 100644 index 000000000..fcb513df1 --- /dev/null +++ b/src/applications/releeph/field/exception/ReleephFieldParseException.php @@ -0,0 +1,12 @@ +<?php + +final class ReleephFieldParseException extends Exception { + + public function __construct(ReleephFieldSpecification $field, + $message) { + + $name = $field->getName(); + parent::__construct("{$name}: {$message}"); + } + +} diff --git a/src/applications/releeph/field/exception/ReleephFieldSpecificationIncompleteException.php b/src/applications/releeph/field/exception/ReleephFieldSpecificationIncompleteException.php new file mode 100644 index 000000000..6e67dcf35 --- /dev/null +++ b/src/applications/releeph/field/exception/ReleephFieldSpecificationIncompleteException.php @@ -0,0 +1,11 @@ +<?php + +final class ReleephFieldSpecificationIncompleteException extends Exception { + + public function __construct(ReleephFieldSpecification $field) { + $class = get_class($field); + parent::__construct( + "Releeph field class {$class} is incompletely implemented."); + } + +} diff --git a/src/applications/releeph/field/selector/ReleephDefaultFieldSelector.php b/src/applications/releeph/field/selector/ReleephDefaultFieldSelector.php new file mode 100644 index 000000000..26506ef2e --- /dev/null +++ b/src/applications/releeph/field/selector/ReleephDefaultFieldSelector.php @@ -0,0 +1,73 @@ +<?php + +final class ReleephDefaultFieldSelector extends ReleephFieldSelector { + + public function getFieldSpecifications() { + return array( + new ReleephCommitMessageFieldSpecification(), + new ReleephSummaryFieldSpecification(), + new ReleephReasonFieldSpecification(), + new ReleephAuthorFieldSpecification(), + new ReleephRevisionFieldSpecification(), + new ReleephRequestorFieldSpecification(), + new ReleephSeverityFieldSpecification(), + new ReleephOriginalCommitFieldSpecification(), + new ReleephDiffMessageFieldSpecification(), + new ReleephStatusFieldSpecification(), + new ReleephIntentFieldSpecification(), + new ReleephBranchCommitFieldSpecification(), + new ReleephDiffSizeFieldSpecification(), + new ReleephDiffChurnFieldSpecification(), + ); + } + + public function arrangeFieldsForHeaderView(array $fields) { + return array( + // Top group + array( + 'left' => self::selectFields($fields, array( + 'ReleephAuthorFieldSpecification', + 'ReleephRevisionFieldSpecification', + 'ReleephOriginalCommitFieldSpecification', + 'ReleephDiffSizeFieldSpecification', + 'ReleephDiffChurnFieldSpecification', + )), + 'right' => self::selectFields($fields, array( + 'ReleephRequestorFieldSpecification', + 'ReleephSeverityFieldSpecification', + 'ReleephStatusFieldSpecification', + 'ReleephIntentFieldSpecification', + 'ReleephBranchCommitFieldSpecification', + )) + ), + + // Bottom group + array( + 'left' => self::selectFields($fields, array( + 'ReleephDiffMessageFieldSpecification', + )), + 'right' => self::selectFields($fields, array( + 'ReleephReasonFieldSpecification', + )) + ) + ); + } + + public function arrangeFieldsForSelectForm(array $fields) { + self::selectFields($fields, array( + 'ReleephStatusFieldSpecification', + 'ReleephSeverityFieldSpecification', + 'ReleephRequestorFieldSpecification', + )); + } + + public function sortFieldsForCommitMessage(array $fields) { + self::selectFields($fields, array( + 'ReleephCommitMessageFieldSpecification', + 'ReleephRequestorFieldSpecification', + 'ReleephIntentFieldSpecification', + 'ReleephReasonFieldSpecification', + )); + } + +} diff --git a/src/applications/releeph/field/selector/ReleephFieldSelector.php b/src/applications/releeph/field/selector/ReleephFieldSelector.php new file mode 100644 index 000000000..3c7afe90d --- /dev/null +++ b/src/applications/releeph/field/selector/ReleephFieldSelector.php @@ -0,0 +1,53 @@ +<?php + +/** + * Control the rendering of ReleephRequestHeaderView, and the layout of the + * ReleephRequest search dialog (in ReleephBranchViewController.) + */ +abstract class ReleephFieldSelector { + + final public function __construct() { + // <empty> + } + + abstract public function getFieldSpecifications(); + + abstract public function arrangeFieldsForHeaderView(array $fields); + + abstract public function arrangeFieldsForSelectForm(array $fields); + + public function sortFieldsForCommitMessage(array $fields) { + assert_instances_of($fields, 'ReleephFieldSpecification'); + return $fields; + } + + protected static function selectFields(array $fields, array $classes) { + assert_instances_of($fields, 'ReleephFieldSpecification'); + + $map = array(); + foreach ($fields as $field) { + $map[get_class($field)] = $field; + } + + $result = array(); + foreach ($classes as $class) { + $field = idx($map, $class); + if (!$field) { + throw new Exception( + "Tried to select a in instance of '{$class}' but that field ". + "is not configured for this project!"); + } + + if (idx($result, $class)) { + throw new Exception( + "You have asked to select the field '{$class}' ". + "more than once!"); + } + + $result[$class] = $field; + } + + return $result; + } + +} diff --git a/src/applications/releeph/field/specification/ReleephAuthorFieldSpecification.php b/src/applications/releeph/field/specification/ReleephAuthorFieldSpecification.php new file mode 100644 index 000000000..610ecb2d5 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephAuthorFieldSpecification.php @@ -0,0 +1,39 @@ +<?php + +final class ReleephAuthorFieldSpecification + extends ReleephFieldSpecification { + + private static $authorMap = array(); + + public function bulkLoad(array $releeph_requests) { + foreach ($releeph_requests as $releeph_request) { + $commit = $releeph_request->loadPhabricatorRepositoryCommit(); + if ($commit) { + $author_phid = $commit->getAuthorPHID(); + self::$authorMap[$releeph_request->getPHID()] = $author_phid; + } + } + + ReleephUserView::getNewInstance() + ->setUser($this->getUser()) + ->setReleephProject($this->getReleephProject()) + ->load(self::$authorMap); + } + + public function getName() { + return 'Author'; + } + + public function renderValueForHeaderView() { + $rr = $this->getReleephRequest(); + $author_phid = idx(self::$authorMap, $rr->getPHID()); + if ($author_phid) { + return ReleephUserView::getNewInstance() + ->setRenderUserPHID($author_phid) + ->render(); + } else { + return 'Unknown Author'; + } + } + +} diff --git a/src/applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php b/src/applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php new file mode 100644 index 000000000..4aa2c93f2 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php @@ -0,0 +1,30 @@ +<?php + +final class ReleephBranchCommitFieldSpecification + extends ReleephFieldSpecification { + + public function getName() { + return 'Commit'; + } + + public function renderValueForHeaderView() { + $rr = $this->getReleephRequest(); + if (!$rr->getInBranch()) { + return null; + } + + $c_phid = $rr->getCommitPHID(); + $c_id = $rr->getCommitIdentifier(); + + if ($c_phid) { + $handles = $rr->getHandles(); + $val = $handles[$c_phid]->renderLink(); + } else if ($c_id) { + $val = $c_id; + } else { + $val = '???'; + } + return $val; + } + +} diff --git a/src/applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php b/src/applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php new file mode 100644 index 000000000..3ad528f3c --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php @@ -0,0 +1,46 @@ +<?php + +final class ReleephCommitMessageFieldSpecification + extends ReleephFieldSpecification { + + public function getName() { + return '__only_for_commit_message!'; + } + + public function shouldAppearOnCommitMessage() { + return true; + } + + public function renderLabelForCommitMessage() { + return $this->renderCommonLabel(); + } + + public function renderValueForCommitMessage() { + return $this->renderCommonValue( + DifferentialReleephRequestFieldSpecification::ACTION_PICKS); + } + + public function shouldAppearOnRevertMessage() { + return true; + } + + public function renderLabelForRevertMessage() { + return $this->renderCommonLabel(); + } + + public function renderValueForRevertMessage() { + return $this->renderCommonValue( + DifferentialReleephRequestFieldSpecification::ACTION_REVERTS); + } + + private function renderCommonLabel() { + return id(new DifferentialReleephRequestFieldSpecification()) + ->renderLabelForCommitMessage(); + } + + private function renderCommonValue($action) { + $rq = 'RQ'.$this->getReleephRequest()->getID(); + return "{$action} {$rq}"; + } + +} diff --git a/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php b/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php new file mode 100644 index 000000000..b8f4310a3 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php @@ -0,0 +1,77 @@ +<?php + +final class ReleephDiffChurnFieldSpecification + extends ReleephFieldSpecification { + + const REJECTIONS_WEIGHT = 30; + const COMMENTS_WEIGHT = 7; + const UPDATES_WEIGHT = 10; + const MAX_POINTS = 100; + + public function getName() { + return 'Churn'; + } + + public function renderValueForHeaderView() { + $diff_rev = $this->getReleephRequest()->loadDifferentialRevision(); + if (!$diff_rev) { + return null; + } + + $diff_rev = $this->getReleephRequest()->loadDifferentialRevision(); + $comments = $diff_rev->loadRelatives( + new DifferentialComment(), + 'revisionID'); + + $counts = array(); + foreach ($comments as $comment) { + $action = $comment->getAction(); + if (!isset($counts[$action])) { + $counts[$action] = 0; + } + $counts[$action] += 1; + } + + // 'none' action just means a plain comment + $comments = idx($counts, 'none', 0); + $rejections = idx($counts, 'reject', 0); + $updates = idx($counts, 'update', 0); + + $points = + self::REJECTIONS_WEIGHT * $rejections + + self::COMMENTS_WEIGHT * $comments + + self::UPDATES_WEIGHT * $updates; + + if ($points === 0) { + $points = 0.15 * self::MAX_POINTS; + $blurb = 'Silent diff'; + } else { + $parts = array(); + if ($rejections) { + $parts[] = pht('%d rejection(s)', $rejections); + } + if ($comments) { + $parts[] = pht('%d comment(s)', $comments); + } + if ($updates) { + $parts[] = pht('%d update(s)', $updates); + } + + if (count($parts) === 0) { + $blurb = ''; + } else if (count($parts) === 1) { + $blurb = head($parts); + } else { + $last = array_pop($parts); + $blurb = implode(', ', $parts).' and '.$last; + } + } + + return id(new AphrontProgressBarView()) + ->setValue($points) + ->setMax(self::MAX_POINTS) + ->setCaption($blurb) + ->render(); + } + +} diff --git a/src/applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php b/src/applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php new file mode 100644 index 000000000..9d87d616c --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php @@ -0,0 +1,37 @@ +<?php + +final class ReleephDiffMessageFieldSpecification + extends ReleephFieldSpecification { + + public function getName() { + return 'Message'; + } + + public function renderLabelForHeaderView() { + return null; + } + + public function renderValueForHeaderView() { + $commit_data = $this + ->getReleephRequest() + ->loadPhabricatorRepositoryCommitData(); + if (!$commit_data) { + return ''; + } + + $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine(); + $engine->setConfig('viewer', $this->getUser()); + $markup = phutil_tag( + 'div', + array( + 'class' => 'phabricator-remarkup', + ), + $engine->markupText($commit_data->getCommitMessage())); + + return id(new AphrontNoteView()) + ->setTitle('Commit Message') + ->appendChild($markup) + ->render(); + } + +} diff --git a/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php b/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php new file mode 100644 index 000000000..586db1b1d --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php @@ -0,0 +1,112 @@ +<?php + +/** + * While this class could take advantage of bulkLoad(), in practice + * loadRelatives fixes all that for us. + */ +final class ReleephDiffSizeFieldSpecification + extends ReleephFieldSpecification { + + const LINES_WEIGHT = 1; + const PATHS_WEIGHT = 30; + const MAX_POINTS = 1000; + + public function getName() { + return 'Size'; + } + + public function renderValueForHeaderView() { + $diff_rev = $this->getReleephRequest()->loadDifferentialRevision(); + if (!$diff_rev) { + return ''; + } + + $diffs = $diff_rev->loadRelatives( + new DifferentialDiff(), + 'revisionID', + 'getID', + 'creationMethod <> "commit"'); + + $all_changesets = array(); + $most_recent_changesets = null; + foreach ($diffs as $diff) { + $changesets = $diff->loadRelatives(new DifferentialChangeset(), 'diffID'); + $all_changesets += $changesets; + $most_recent_changesets = $changesets; + } + + // The score is based on all changesets for all versions of this diff + $all_changes = $this->countLinesAndPaths($all_changesets); + $points = + self::LINES_WEIGHT * $all_changes['code']['lines'] + + self::PATHS_WEIGHT * count($all_changes['code']['paths']); + + // The blurb is just based on the most recent version of the diff + $mr_changes = $this->countLinesAndPaths($most_recent_changesets); + + $test_tag = ''; + if ($mr_changes['tests']['paths']) { + Javelin::initBehavior('phabricator-tooltips'); + require_celerity_resource('aphront-tooltip-css'); + + $test_blurb = + pht('%d line(s)', $mr_changes['tests']['lines']).' and '. + pht('%d path(s)', count($mr_changes['tests']['paths'])). + " contain changes to test code:\n"; + foreach ($mr_changes['tests']['paths'] as $mr_test_path) { + $test_blurb .= pht("%s\n", $mr_test_path); + } + + $test_tag = javelin_tag( + 'span', + array( + 'sigil' => 'has-tooltip', + 'meta' => array( + 'tip' => $test_blurb, + 'align' => 'E', + 'size' => 'auto'), + 'style' => ''), + ' + tests'); + } + + $blurb = hsprintf("%s%s.", + pht('%d line(s)', $mr_changes['code']['lines']).' and '. + pht('%d path(s)', count($mr_changes['code']['paths'])).' over '. + pht('%d diff(s)', count($diffs)), + $test_tag); + + return id(new AphrontProgressBarView()) + ->setValue($points) + ->setMax(self::MAX_POINTS) + ->setCaption($blurb) + ->render(); + } + + private function countLinesAndPaths(array $changesets) { + assert_instances_of($changesets, 'DifferentialChangeset'); + $lines = 0; + $paths_touched = array(); + $test_lines = 0; + $test_paths_touched = array(); + + foreach ($changesets as $ch) { + if ($this->getReleephProject()->isTestFile($ch->getFilename())) { + $test_lines += $ch->getAddLines() + $ch->getDelLines(); + $test_paths_touched[] = $ch->getFilename(); + } else { + $lines += $ch->getAddLines() + $ch->getDelLines(); + $paths_touched[] = $ch->getFilename(); + } + } + return array( + 'code' => array( + 'lines' => $lines, + 'paths' => array_unique($paths_touched), + ), + 'tests' => array( + 'lines' => $test_lines, + 'paths' => array_unique($test_paths_touched), + ) + ); + } +} diff --git a/src/applications/releeph/field/specification/ReleephFieldSpecification.php b/src/applications/releeph/field/specification/ReleephFieldSpecification.php new file mode 100644 index 000000000..992808f12 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephFieldSpecification.php @@ -0,0 +1,359 @@ +<?php + +abstract class ReleephFieldSpecification { + + abstract public function getName(); + +/* -( Storage )------------------------------------------------------------ */ + + public function getStorageKey() { + return null; + } + + final public function isEditable() { + return $this->getStorageKey() !== null; + } + + /** + * This will be called many times if you are using **Selecting**. In + * particular, for N selecting fields, selectReleephRequests() is called + * N-squared times, each time for R ReleephRequests. + */ + final public function getValue() { + $key = $this->getRequiredStorageKey(); + return $this->getReleephRequest()->getDetail($key); + } + + final public function setValue($value) { + $key = $this->getRequiredStorageKey(); + return $this->getReleephRequest()->setDetail($key, $value); + } + + /** + * @throws ReleephFieldParseException, to show an error. + */ + public function validate($value) { + return; + } + + +/* -( Header View )-------------------------------------------------------- */ + + /** + * Return a label for use in rendering the fields table. If you return null, + * the renderLabelForHeaderView data will span both columns. + */ + public function renderLabelForHeaderView() { + return $this->getName(); + } + + public function renderValueForHeaderView() { + $key = $this->getRequiredStorageKey(); + return $this->getReleephRequest()->getDetail($key); + } + + +/* -( Edit View )---------------------------------------------------------- */ + + public function renderEditControl(AphrontRequest $request) { + throw new ReleephFieldSpecificationIncompleteException($this); + } + + public function setValueFromAphrontRequest(AphrontRequest $request) { + $data = $request->getRequestData(); + $value = idx($data, $this->getRequiredStorageKey()); + $this->validate($value); + $this->setValue($value); + } + + +/* -( Conduit )------------------------------------------------------------ */ + + public function getKeyForConduit() { + return $this->getRequiredStorageKey(); + } + + public function getValueForConduit() { + return $this->getValue(); + } + + public function setValueFromConduitAPIRequest(ConduitAPIRequest $request) { + $value = idx( + $request->getValue('fields', array()), + $this->getRequiredStorageKey()); + $this->validate($value); + $this->setValue($value); + } + + +/* -( Arcanist )----------------------------------------------------------- */ + + public function renderHelpForArcanist() { + return ''; + } + + +/* -( Context )------------------------------------------------------------ */ + + private $releephProject; + private $releephBranch; + private $releephRequest; + private $user; + + final public function setReleephProject(ReleephProject $rp) { + $this->releephProject = $rp; + return $this; + } + + final public function setReleephBranch(ReleephBranch $rb) { + $this->releephRequest = $rb; + return $this; + } + + final public function setReleephRequest(ReleephRequest $rr) { + $this->releephRequest = $rr; + return $this; + } + + final public function setUser(PhabricatorUser $user) { + $this->user = $user; + return $this; + } + + final public function getReleephProject() { + return $this->releephProject; + } + + final public function getReleephBranch() { + return $this->releephBranch; + } + + final public function getReleephRequest() { + return $this->releephRequest; + } + + final public function getUser() { + return $this->user; + } + + +/* -( Bulk loading )------------------------------------------------------- */ + + public function bulkLoad(array $releeph_requests) { + } + + +/* -( Selecting )---------------------------------------------------------- */ + + /** + * Append select controls to the given form. + * + * You are given: + * + * - the AphrontFormView to append to; + * + * - the AphrontRequest, so you can make use of the value currently selected + * in the form; + * + * - $all_releeph_requests: an array of all the ReleephRequests without any + * selection based filtering; and + * + * - $all_releeph_requests_without_this_field: an array of ReleephRequests + * that have been selected by all the other select controls on this page. + * + * The example in ReleephLevelFieldSpecification shows how to use these. + * $all_releeph_requests lets you find out all the values of a field in all + * ReleephRequests, so you can render controls for every known value. + * + * $all_releeph_requests_without_this_field lets you count how many + * ReleephRequests could be affected by this field's select control, after + * all the other fields have made their selections. + * ReleephLevelFieldSpecification uses this to render a preview count for + * each select button, and disables the button completely (but still renders + * it) if it couldn't possibly select anything. + */ + protected function appendSelectControls( + AphrontFormView $form, + AphrontRequest $request, + array $all_releeph_requests, + array $all_releeph_requests_without_this_field) { + + return null; + } + + /** + * Filter the $releeph_requests using the data you set with your form + * controls, and which is now available in the provided AphrontRequest. + */ + protected function selectReleephRequests(AphrontRequest $request, + array &$releeph_requests) { + return null; + } + + /** + * If you have PHIDs that can be used in an AphrontFormTokenizerControl, + * return true here, return the PHIDs in getSelectablePHIDs(), and return the + * URL the Tokenizer should use for the form control in + * getSelectTokenizerDatasource(). + * + * This is a cheap alternative to implementing appendSelectControls() and + * selectReleephRequests() in full. + */ + protected function hasSelectablePHIDs() { + return false; + } + + protected function getSelectablePHIDs() { + throw new ReleephFieldSpecificationIncompleteException($this); + } + + protected function getSelectTokenizerDatasource() { + throw new ReleephFieldSpecificationIncompleteException($this); + } + + +/* -( Commit Messages )---------------------------------------------------- */ + + public function shouldAppearOnCommitMessage() { + return false; + } + + public function renderLabelForCommitMessage() { + throw new ReleephFieldSpecificationIncompleteException($this); + } + + public function renderValueForCommitMessage() { + throw new ReleephFieldSpecificationIncompleteException($this); + } + + public function shouldAppearOnRevertMessage() { + return false; + } + + public function renderLabelForRevertMessage() { + return $this->renderLabelForCommitMessage(); + } + + public function renderValueForRevertMessage() { + return $this->renderValueForCommitMessage(); + } + + +/* -( Implementation )----------------------------------------------------- */ + + protected function getRequiredStorageKey() { + $key = $this->getStorageKey(); + if ($key === null) { + throw new ReleephFieldSpecificationIncompleteException($this); + } + if (strpos($key, '.') !== false) { + /** + * Storage keys are reused for form controls, and periods in form control + * names break HTML forms. + */ + throw new Exception( + "You can't use '.' in storage keys!"); + } + return $key; + } + + /** + * The "hook" functions ##appendSelectControlsHook()## and + * ##selectReleephRequestsHook()## are used with ##hasSelectablePHIDs()##, to + * use the tokenizing helpers if ##hasSelectablePHIDs()## returns true. + */ + public function appendSelectControlsHook( + AphrontFormView $form, + AphrontRequest $request, + array $all_releeph_requests, + array $all_releeph_requests_without_this_field) { + + if ($this->hasSelectablePHIDs()) { + $this->appendTokenizingSelectControl( + $form, + $request, + $all_releeph_requests, + $all_releeph_requests_without_this_field); + } else { + $this->appendSelectControls( + $form, + $request, + $all_releeph_requests, + $all_releeph_requests_without_this_field); + } + } + + // See above + public function selectReleephRequestsHook(AphrontRequest $request, + array &$releeph_requests) { + + if ($this->hasSelectablePHIDs()) { + $this->selectReleephRequestsFromTokens( + $request, + $releeph_requests); + } else { + $this->selectReleephRequests( + $request, + $releeph_requests); + } + } + + private function appendTokenizingSelectControl( + AphrontFormView $form, + AphrontRequest $request, + array $all_releeph_requests, + array $all_releeph_requests_without_this_field) { + + $key = urlencode(strtolower($this->getName())); + $selected_phids = $request->getArr($key); + $handles = id(new PhabricatorObjectHandleData($selected_phids)) + ->setViewer($request->getUser()) + ->loadHandles(); + + $tokens = array(); + foreach ($selected_phids as $phid) { + $tokens[$phid] = $handles[$phid]->getFullName(); + } + + $datasource = $this->getSelectTokenizerDatasource(); + $control = + id(new AphrontFormTokenizerControl()) + ->setDatasource($datasource) + ->setName($key) + ->setLabel($this->getName()) + ->setValue($tokens); + + $form->appendChild($control); + } + + private function selectReleephRequestsFromTokens(AphrontRequest $request, + array &$releeph_requests) { + + $key = urlencode(strtolower($this->getName())); + $selected_phids = $request->getArr($key); + if (!$selected_phids) { + return; + } + + $selected_phid_lookup = array(); + foreach ($selected_phids as $phid) { + $selected_phid_lookup[$phid] = $phid; + } + + $filtered = array(); + foreach ($releeph_requests as $releeph_request) { + $rq_phids = $this + ->setReleephRequest($releeph_request) + ->getSelectablePHIDs(); + foreach ($rq_phids as $rq_phid) { + if (idx($selected_phid_lookup, $rq_phid)) { + $filtered[] = $releeph_request; + break; + } + } + } + + $releeph_requests = $filtered; + } + +} diff --git a/src/applications/releeph/field/specification/ReleephIntentFieldSpecification.php b/src/applications/releeph/field/specification/ReleephIntentFieldSpecification.php new file mode 100644 index 000000000..6ba85271c --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephIntentFieldSpecification.php @@ -0,0 +1,81 @@ +<?php + +final class ReleephIntentFieldSpecification + extends ReleephFieldSpecification { + + public function getName() { + return 'Intent'; + } + + public function renderValueForHeaderView() { + return id(new ReleephRequestIntentsView()) + ->setReleephRequest($this->getReleephRequest()) + ->setReleephProject($this->getReleephProject()) + ->render(); + } + + public function shouldAppearOnCommitMessage() { + return true; + } + + public function shouldAppearOnRevertMessage() { + return true; + } + + public function renderLabelForCommitMessage() { + return "Approved By"; + } + + public function renderLabelForRevertMessage() { + return "Rejected By"; + } + + public function renderValueForCommitMessage() { + return $this->renderIntentsForCommitMessage(ReleephRequest::INTENT_WANT); + } + + public function renderValueForRevertMessage() { + return $this->renderIntentsForCommitMessage(ReleephRequest::INTENT_PASS); + } + + private function renderIntentsForCommitMessage($print_intent) { + $intents = $this->getReleephRequest()->getUserIntents(); + + $requestor = $this->getReleephRequest()->getRequestUserPHID(); + $pusher_phids = $this->getReleephProject()->getPushers(); + + $phids = array_unique($pusher_phids + array_keys($intents)); + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($this->getUser()) + ->loadHandles(); + + $tokens = array(); + foreach ($phids as $phid) { + $intent = idx($intents, $phid); + if ($intent == $print_intent) { + $name = $handles[$phid]->getName(); + $is_pusher = in_array($phid, $pusher_phids); + $is_requestor = $phid == $requestor; + + if ($is_pusher) { + if ($is_requestor) { + $token = "{$name} (pusher and requestor)"; + } else { + $token = "{$name} (pusher)"; + } + } else { + if ($is_requestor) { + $token = "{$name} (requestor)"; + } else { + $token = $name; + } + } + + $tokens[] = $token; + } + } + + return implode(', ', $tokens); + } + +} diff --git a/src/applications/releeph/field/specification/ReleephLevelFieldSpecification.php b/src/applications/releeph/field/specification/ReleephLevelFieldSpecification.php new file mode 100644 index 000000000..e1866d24b --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephLevelFieldSpecification.php @@ -0,0 +1,228 @@ +<?php + +/** + * Provides a convenient field for storing a set of levels that you can use to + * filter requests on. + * + * Levels are rendered with names and descriptions in the edit UI, and are + * automatically documented via the "arc request" interface. + * + * See ReleephSeverityFieldSpecification for an example. + */ +abstract class ReleephLevelFieldSpecification + extends ReleephFieldSpecification { + + private $error; + + abstract public function getLevels(); + abstract public function getDefaultLevel(); + abstract public function getNameForLevel($level); + abstract public function getDescriptionForLevel($level); + + /** + * Use getCanonicalLevel() to convert old, unsupported levels to new ones. + */ + protected function getCanonicalLevel($misc_level) { + return $misc_level; + } + + public function getStorageKey() { + $class = get_class($this); + throw new ReleephFieldSpecificationIncompleteException( + $this, + "You must implement getStorageKey() for children of {$class}!"); + } + + public function renderValueForHeaderView() { + $raw_level = $this->getValue(); + $level = $this->getCanonicalLevel($raw_level); + return $this->getNameForLevel($level); + } + + public function renderEditControl(AphrontRequest $request) { + $control_name = $this->getRequiredStorageKey(); + $all_levels = $this->getLevels(); + + $level = $request->getStr($control_name); + + if (!$level) { + $level = $this->getCanonicalLevel($this->getValue()); + } + + if (!$level) { + $level = $this->getDefaultLevel(); + } + + $control = id(new AphrontFormRadioButtonControl()) + ->setLabel('Level') + ->setName($control_name) + ->setValue($level); + + if ($this->error) { + $control->setError($this->error); + } elseif ($this->getDefaultLevel()) { + $control->setError(true); + } + + foreach ($all_levels as $level) { + $name = $this->getNameForLevel($level); + $description = $this->getDescriptionForLevel($level); + $control->addButton($level, $name, $description); + } + + return $control; + } + + public function renderHelpForArcanist() { + $text = ''; + $levels = $this->getLevels(); + $default = $this->getDefaultLevel(); + foreach ($levels as $level) { + $name = $this->getNameForLevel($level); + $description = $this->getDescriptionForLevel($level); + $default_marker = ' '; + if ($level === $default) { + $default_marker = '*'; + } + $text .= " {$default_marker} **{$name}**\n"; + $text .= phutil_console_wrap($description."\n", 8); + } + return $text; + } + + public function validate($value) { + if ($value === null) { + $this->error = 'Required'; + $label = $this->getName(); + throw new ReleephFieldParseException( + $this, + "You must provide a {$label} level"); + } + + $levels = $this->getLevels(); + if (!in_array($value, $levels)) { + $label = $this->getName(); + throw new ReleephFieldParseException( + $this, + "Level '{$value}' is not a valid {$label} level in this project."); + } + } + + public function setValueFromConduitAPIRequest(ConduitAPIRequest $request) { + $key = $this->getRequiredStorageKey(); + $label = $this->getName(); + $name = idx($request->getValue('fields', array()), $key); + + if (!$name) { + $level = $this->getDefaultLevel(); + if (!$level) { + throw new ReleephFieldParseException( + $this, + "No value given for {$label}, ". + "and no default is given for this level!"); + } + } else { + $level = $this->getLevelByName($name); + } + + if (!$level) { + throw new ReleephFieldParseException( + $this, + "Unknown {$label} level name '{$name}'"); + } + $this->setValue($level); + } + + private $nameMap = array(); + + public function getLevelByName($name) { + // Build this once + if (!$this->nameMap) { + foreach ($this->getLevels() as $level) { + $level_name = $this->getNameForLevel($level); + $this->nameMap[$level_name] = $level; + } + } + return idx($this->nameMap, $name); + } + + protected function appendSelectControls( + AphrontFormView $form, + AphrontRequest $request, + array $all_releeph_requests, + array $all_releeph_requests_without_this_field) { + + $buttons = array(null => 'All'); + + // Add in known level/names + foreach ($this->getLevels() as $level) { + $name = $this->getNameForLevel($level); + $buttons[$name] = $name; + } + + // Add in any names we've seen in the wild, as well. + foreach ($all_releeph_requests as $releeph_request) { + $raw_level = $this->setReleephRequest($releeph_request)->getValue(); + if (!$raw_level) { + // The ReleephRequest might not have a level set + continue; + } + $level = $this->getCanonicalLevel($raw_level); + $name = $this->getNameForLevel($level); + $buttons[$name] = $name; + } + + $key = $this->getRequiredStorageKey(); + $current = $request->getStr($key); + + $counters = array(null => count($all_releeph_requests_without_this_field)); + foreach ($all_releeph_requests_without_this_field as $releeph_request) { + $raw_level = $this->setReleephRequest($releeph_request)->getValue(); + if (!$raw_level) { + // The ReleephRequest might not have a level set + continue; + } + $level = $this->getCanonicalLevel($raw_level); + $name = $this->getNameForLevel($level); + + if (!isset($counters[$name])) { + $counters[$name] = 0; + } + $counters[$name]++; + } + + $control = id(new AphrontFormCountedToggleButtonsControl()) + ->setLabel($this->getName()) + ->setValue($current) + ->setBaseURI($request->getRequestURI(), $key) + ->setButtons($buttons) + ->setCounters($counters); + + $form + ->appendChild($control) + ->addHiddenInput($key, $current); + } + + protected function selectReleephRequests(AphrontRequest $request, + array &$releeph_requests) { + $key = $this->getRequiredStorageKey(); + $current = $request->getStr($key); + + if (!$current) { + return; + } + + $filtered = array(); + foreach ($releeph_requests as $releeph_request) { + $raw_level = $this->setReleephRequest($releeph_request)->getValue(); + $level = $this->getCanonicalLevel($raw_level); + $name = $this->getNameForLevel($level); + if ($name == $current) { + $filtered[] = $releeph_request; + } + } + + $releeph_requests = $filtered; + } + +} diff --git a/src/applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php b/src/applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php new file mode 100644 index 000000000..3f4ec6ae1 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php @@ -0,0 +1,16 @@ +<?php + +final class ReleephOriginalCommitFieldSpecification + extends ReleephFieldSpecification { + + public function getName() { + return 'Commit'; + } + + public function renderValueForHeaderView() { + $rr = $this->getReleephRequest(); + $handles = $rr->getHandles(); + return $handles[$rr->getRequestCommitPHID()]->renderLink(); + } + +} diff --git a/src/applications/releeph/field/specification/ReleephReasonFieldSpecification.php b/src/applications/releeph/field/specification/ReleephReasonFieldSpecification.php new file mode 100644 index 000000000..7b805cd49 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephReasonFieldSpecification.php @@ -0,0 +1,78 @@ +<?php + +final class ReleephReasonFieldSpecification + extends ReleephFieldSpecification { + + public function getName() { + return 'Reason'; + } + + public function getStorageKey() { + return 'reason'; + } + + public function renderLabelForHeaderView() { + return null; + } + + public function renderValueForHeaderView() { + $reason = $this->getValue(); + if (!$reason) { + return ''; + } + + $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine(); + $engine->setConfig('viewer', $this->getUser()); + $markup = phutil_tag( + 'div', + array( + 'class' => 'phabricator-remarkup', + ), + $engine->markupText($reason)); + + return id(new AphrontNoteView()) + ->setTitle('Reason') + ->appendChild($markup) + ->render(); + } + + private $error = true; + + public function renderEditControl(AphrontRequest $request) { + $reason = $request->getStr('reason', $this->getValue()); + return id(new AphrontFormTextAreaControl()) + ->setLabel('Reason') + ->setName('reason') + ->setError($this->error) + ->setValue($reason); + } + + public function validate($reason) { + if (!$reason) { + $this->error = 'Required'; + throw new ReleephFieldParseException( + $this, + "You must give a reason for your request."); + } + } + + public function renderHelpForArcanist() { + $text = + "Fully explain why you are requesting this code be included ". + "in the next release.\n"; + return phutil_console_wrap($text, 8); + } + + public function shouldAppearOnCommitMessage() { + return true; + } + + public function renderLabelForCommitMessage() { + return 'Request Reason'; + } + + public function renderValueForCommitMessage() { + return $this->getValue(); + } + +} diff --git a/src/applications/releeph/field/specification/ReleephRequestorFieldSpecification.php b/src/applications/releeph/field/specification/ReleephRequestorFieldSpecification.php new file mode 100644 index 000000000..aed8b0186 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephRequestorFieldSpecification.php @@ -0,0 +1,59 @@ +<?php + +final class ReleephRequestorFieldSpecification + extends ReleephFieldSpecification { + + public function bulkLoad(array $releeph_requests) { + $phids = mpull($releeph_requests, 'getRequestUserPHID'); + ReleephUserView::getNewInstance() + ->setUser($this->getUser()) + ->setReleephProject($this->getReleephProject()) + ->load($phids); + } + + public function getName() { + return 'Requestor'; + } + + public function renderValueForHeaderView() { + $phid = $this->getReleephRequest()->getRequestUserPHID(); + return ReleephUserView::getNewInstance() + ->setRenderUserPHID($phid) + ->render(); + } + + public function hasSelectablePHIDs() { + return true; + } + + public function getSelectTokenizerDatasource() { + return '/typeahead/common/users/'; + } + + public function getSelectablePHIDs() { + return array( + $this->getReleephRequest()->getRequestUserPHID(), + ); + } + + public function shouldAppearOnCommitMessage() { + return true; + } + + public function shouldAppearOnRevertMessage() { + return true; + } + + public function renderLabelForCommitMessage() { + return "Requested By"; + } + + public function renderValueForCommitMessage() { + $phid = $this->getReleephRequest()->getRequestUserPHID(); + $handles = id(new PhabricatorObjectHandleData(array($phid))) + ->setViewer($this->getUser()) + ->loadHandles(); + return $handles[$phid]->getName(); + } + +} diff --git a/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php b/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php new file mode 100644 index 000000000..80b0d0f99 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php @@ -0,0 +1,37 @@ +<?php + +final class ReleephRevisionFieldSpecification + extends ReleephFieldSpecification { + + public function getName() { + return 'Revision'; + } + + public function renderValueForHeaderView() { + $data = $this + ->getReleephRequest() + ->loadPhabricatorRepositoryCommitData(); + if (!$data) { + return null; + } + + $phid = $data->getCommitDetail('differential.revisionPHID'); + if (!$phid) { + return null; + } + + $handles = $this->getReleephRequest()->getHandles(); + $handle = $handles[$phid]; + $link = $handle + // Hack to remove the strike-through rendering of diff links + ->setStatus(null) + ->renderLink(); + return phutil_tag( + 'div', + array( + 'class' => 'releeph-header-text-truncated', + ), + $link); + } + +} diff --git a/src/applications/releeph/field/specification/ReleephRiskFieldSpecification.php b/src/applications/releeph/field/specification/ReleephRiskFieldSpecification.php new file mode 100644 index 000000000..7ab3a33a1 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephRiskFieldSpecification.php @@ -0,0 +1,63 @@ +<?php + +final class ReleephRiskFieldSpecification + extends ReleephFieldSpecification { + + static $defaultRisks = array( + 'NONE' => 'Completely safe to pick this request.', + 'SOME' => 'There is some risk this could break things, but not much.', + 'HIGH' => 'This is pretty risky, but is also very important.', + ); + + public function getName() { + return 'Riskiness'; + } + + public function getStorageKey() { + return 'risk'; + } + + public function renderLabelForHeaderView() { + return 'Riskiness'; + } + + private $error = true; + + public function renderEditControl(AphrontRequest $request) { + $value = $request->getStr('risk', $this->getValue()); + $buttons = id(new AphrontFormRadioButtonControl()) + ->setLabel('Riskiness') + ->setName('risk') + ->setError($this->error) + ->setValue($value); + foreach (self::$defaultRisks as $value => $description) { + $buttons->addButton($value, $value, $description); + } + return $buttons; + } + + public function validate($risk) { + if (!$risk) { + $this->error = 'Required'; + throw new ReleephFieldParseException( + $this, + "No risk was given, which probably means we've changed the set ". + "of valid risks since you made this request. Please pick one."); + } + if (!idx(self::$defaultRisks, $risk)) { + throw new ReleephFieldParseException( + $this, + "Unknown risk '{$risk}'."); + } + } + + public function renderHelpForArcanist() { + $help = ''; + foreach (self::$defaultRisks as $name => $description) { + $help .= " **{$name}**\n"; + $help .= phutil_console_wrap($description."\n", 8); + } + return $help; + } + +} diff --git a/src/applications/releeph/field/specification/ReleephSeverityFieldSpecification.php b/src/applications/releeph/field/specification/ReleephSeverityFieldSpecification.php new file mode 100644 index 000000000..9b362cbfd --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephSeverityFieldSpecification.php @@ -0,0 +1,46 @@ +<?php + +final class ReleephSeverityFieldSpecification + extends ReleephLevelFieldSpecification { + + const HOTFIX = 'HOTFIX'; + const RELEASE = 'RELEASE'; + + public function getName() { + return 'Severity'; + } + + public function getStorageKey() { + return 'releeph:severity'; + } + + public function getLevels() { + return array( + self::HOTFIX, + self::RELEASE, + ); + } + + public function getDefaultLevel() { + return self::RELEASE; + } + + public function getNameForLevel($level) { + static $names = array( + self::HOTFIX => 'HOTFIX', + self::RELEASE => 'RELEASE', + ); + return idx($names, $level, $level); + } + + public function getDescriptionForLevel($level) { + static $descriptions = array( + self::HOTFIX => + 'Needs merging and fixing right now.', + self::RELEASE => + 'Required for the currently rolling release.', + ); + return idx($descriptions, $level); + } + +} diff --git a/src/applications/releeph/field/specification/ReleephStatusFieldSpecification.php b/src/applications/releeph/field/specification/ReleephStatusFieldSpecification.php new file mode 100644 index 000000000..202e5aba8 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephStatusFieldSpecification.php @@ -0,0 +1,89 @@ +<?php + +final class ReleephStatusFieldSpecification + extends ReleephFieldSpecification { + + public function getName() { + return 'Status'; + } + + public function renderValueForHeaderView() { + return id(new ReleephRequestStatusView()) + ->setReleephRequest($this->getReleephRequest()) + ->render(); + } + + private static $filters = array( + 'req' => ReleephRequest::STATUS_REQUESTED, + 'app' => ReleephRequest::STATUS_NEEDS_PICK, + 'rej' => ReleephRequest::STATUS_REJECTED, + 'abn' => ReleephRequest::STATUS_ABANDONED, + 'mer' => ReleephRequest::STATUS_PICKED, + 'rrq' => ReleephRequest::STATUS_NEEDS_REVERT, + 'rev' => ReleephRequest::STATUS_REVERTED, + ); + + protected function appendSelectControls( + AphrontFormView $form, + AphrontRequest $request, + array $all_releeph_requests, + array $all_releeph_requests_without_this_field) { + + $filter_names = array( + null => 'All', + ); + + foreach (self::$filters as $code => $status) { + $name = ReleephRequest::getStatusDescriptionFor($status); + $filter_names[$code] = $name; + } + + $key = 'status'; + $code = $request->getStr($key); + $current_status = idx(self::$filters, $code); + + $codes = array_flip(self::$filters); + + $counters = array(null => count($all_releeph_requests_without_this_field)); + foreach ($all_releeph_requests_without_this_field as $releeph_request) { + $this_status = $releeph_request->getStatus(); + $this_code = idx($codes, $this_status); + if (!isset($counters[$this_code])) { + $counters[$this_code] = 0; + } + $counters[$this_code]++; + } + + $control = id(new AphrontFormCountedToggleButtonsControl()) + ->setLabel($this->getName()) + ->setValue($code) + ->setBaseURI($request->getRequestURI(), $key) + ->setButtons($filter_names) + ->setCounters($counters); + + $form + ->appendChild($control) + ->addHiddenInput($key, $code); + } + + protected function selectReleephRequests(AphrontRequest $request, + array &$releeph_requests) { + + $key = 'status'; + $code = $request->getStr($key); + if (!$code) { + return; + } + + $current_status = idx(self::$filters, $code); + + $filtered = array(); + foreach ($releeph_requests as $releeph_request) { + if ($releeph_request->getStatus() == $current_status) { + $filtered[] = $releeph_request; + } + } + $releeph_requests = $filtered; + } + +} diff --git a/src/applications/releeph/field/specification/ReleephSummaryFieldSpecification.php b/src/applications/releeph/field/specification/ReleephSummaryFieldSpecification.php new file mode 100644 index 000000000..7ff398604 --- /dev/null +++ b/src/applications/releeph/field/specification/ReleephSummaryFieldSpecification.php @@ -0,0 +1,46 @@ +<?php + +final class ReleephSummaryFieldSpecification + extends ReleephFieldSpecification { + + const MAX_SUMMARY_LENGTH = 60; + + public function getName() { + return 'Summary'; + } + + public function getStorageKey() { + return 'summary'; + } + + private $error = false; + + public function renderEditControl(AphrontRequest $request) { + $summary = $request->getStr('summary', $this->getValue()); + return id(new AphrontFormTextControl()) + ->setLabel('Summary') + ->setName('summary') + ->setError($this->error) + ->setValue($summary) + ->setCaption( + 'Leave this blank to use the original commit title'); + } + + public function renderHelpForArcanist() { + $text = + "A one-line title summarizing this request. ". + "Leave blank to use the original commit title.\n"; + return phutil_console_wrap($text, 8); + } + + public function validate($summary) { + if ($summary && strlen($summary) > self::MAX_SUMMARY_LENGTH) { + $this->error = 'Too long!'; + throw new ReleephFieldParseException( + $this, sprintf( + 'Please keep your summary to under %d characters.', + self::MAX_SUMMARY_LENGTH)); + } + } + +} diff --git a/src/applications/releeph/storage/ReleephBranch.php b/src/applications/releeph/storage/ReleephBranch.php new file mode 100644 index 000000000..904cb3076 --- /dev/null +++ b/src/applications/releeph/storage/ReleephBranch.php @@ -0,0 +1,154 @@ +<?php + +final class ReleephBranch extends ReleephDAO { + + protected $phid; + protected $releephProjectID; + protected $isActive; + protected $createdByUserPHID; + + // The immutable name of this branch ('releases/foo-2013.01.24') + protected $name; + protected $basename; + + // The symbolic name of this branch (LATEST, PRODUCTION, RC, ...) + // See SYMBOLIC_NAME_NOTE below + protected $symbolicName; + + // Where to cut the branch + protected $cutPointCommitIdentifier; + protected $cutPointCommitPHID; + + protected $details = array(); + + public function getConfiguration() { + return array( + self::CONFIG_AUX_PHID => true, + self::CONFIG_SERIALIZATION => array( + 'details' => self::SERIALIZATION_JSON, + ), + ) + parent::getConfiguration(); + } + + public function generatePHID() { + return PhabricatorPHID::generateNewPHID( + ReleephPHIDConstants::PHID_TYPE_REBR); + } + + public function getDetail($key, $default = null) { + return idx($this->getDetails(), $key, $default); + } + + public function setDetail($key, $value) { + $this->details[$key] = $value; + return $this; + } + + public function willWriteData(array &$data) { + // If symbolicName is omitted, set it to the basename. + // + // This means that we can enforce symbolicName as a UNIQUE column in the + // DB. We'll interpret symbolicName === basename as meaning "no symbolic + // name". + // + // SYMBOLIC_NAME_NOTE + if (!$data['symbolicName']) { + $data['symbolicName'] = $data['basename']; + } + parent::willWriteData($data); + } + + public function getSymbolicName() { + // See SYMBOLIC_NAME_NOTE above for why this is needed + if ($this->symbolicName == $this->getBasename()) { + return ''; + } + return $this->symbolicName; + } + + public function setSymbolicName($name) { + if ($name) { + parent::setSymbolicName($name); + } else { + parent::setSymbolicName($this->getBasename()); + } + return $this; + } + + public function getDisplayName() { + if ($sn = $this->getSymbolicName()) { + return $sn; + } + return $this->getBasename(); + } + + public function getDisplayNameWithDetail() { + $n = $this->getBasename(); + if ($sn = $this->getSymbolicName()) { + return "{$sn} ({$n})"; + } else { + return $n; + } + } + + public function getURI($path = null) { + $components = array( + '/releeph', + rawurlencode($this->loadReleephProject()->getName()), + rawurlencode($this->getBasename()), + $path + ); + return PhabricatorEnv::getProductionURI(implode('/', $components)); + } + + public function loadReleephProject() { + return $this->loadOneRelative( + new ReleephProject(), + 'id', + 'getReleephProjectID'); + } + + private function loadReleephRequestHandles(PhabricatorUser $user, $reqs) { + $phids_to_phetch = array(); + foreach ($reqs as $rr) { + $phids_to_phetch[] = $rr->getRequestCommitPHID(); + $phids_to_phetch[] = $rr->getRequestUserPHID(); + $phids_to_phetch[] = $rr->getCommitPHID(); + + $intents = $rr->getUserIntents(); + if ($intents) { + foreach ($intents as $user_phid => $intent) { + $phids_to_phetch[] = $user_phid; + } + } + + $request_commit = $rr->loadPhabricatorRepositoryCommit(); + if ($request_commit) { + $phids_to_phetch[] = $request_commit->getAuthorPHID(); + $phids_to_phetch[] = $rr->loadRequestCommitDiffPHID(); + } + } + $handles = id(new PhabricatorObjectHandleData($phids_to_phetch)) + ->setViewer($user) + ->loadHandles(); + return $handles; + } + + public function populateReleephRequestHandles(PhabricatorUser $user, $reqs) { + $handles = $this->loadReleephRequestHandles($user, $reqs); + foreach ($reqs as $req) { + $req->setHandles($handles); + } + } + + public function loadReleephRequests(PhabricatorUser $user) { + $reqs = $this->loadRelatives(new ReleephRequest(), 'branchID'); + $this->populateReleephRequestHandles($user, $reqs); + return $reqs; + } + + public function isActive() { + return $this->getIsActive(); + } + +} diff --git a/src/applications/releeph/storage/ReleephDAO.php b/src/applications/releeph/storage/ReleephDAO.php new file mode 100644 index 000000000..638e16a73 --- /dev/null +++ b/src/applications/releeph/storage/ReleephDAO.php @@ -0,0 +1,9 @@ +<?php + +abstract class ReleephDAO extends PhabricatorLiskDAO { + + public function getApplicationName() { + return 'releeph'; + } + +} diff --git a/src/applications/releeph/storage/ReleephProject.php b/src/applications/releeph/storage/ReleephProject.php new file mode 100644 index 000000000..1337340da --- /dev/null +++ b/src/applications/releeph/storage/ReleephProject.php @@ -0,0 +1,176 @@ +<?php + +final class ReleephProject extends ReleephDAO { + + const DEFAULT_BRANCH_NAMESPACE = 'releeph-releases'; + const SYSTEM_AGENT_USERNAME_PREFIX = 'releeph-agent-'; + + const COMMIT_AUTHOR_NONE = 'commit-author-none'; + const COMMIT_AUTHOR_FROM_DIFF = 'commit-author-is-from-diff'; + const COMMIT_AUTHOR_REQUESTOR = 'commit-author-is-requestor'; + + protected $phid; + protected $name; + + // Specifying the place to pick from is a requirement for svn, though not + // for git. It's always useful though for reasoning about what revs have + // been picked and which haven't. + protected $trunkBranch; + + protected $repositoryID; + protected $repositoryPHID; + protected $isActive; + protected $createdByUserPHID; + protected $arcanistProjectID; + protected $projectID; + + protected $details = array(); + + public function getConfiguration() { + return array( + self::CONFIG_AUX_PHID => true, + self::CONFIG_SERIALIZATION => array( + 'details' => self::SERIALIZATION_JSON, + ), + ) + parent::getConfiguration(); + } + + public function generatePHID() { + return PhabricatorPHID::generateNewPHID( + ReleephPHIDConstants::PHID_TYPE_REPR); + } + + public function getDetail($key, $default = null) { + return idx($this->details, $key, $default); + } + + public function getURI($path = null) { + $components = array( + '/releeph/project', + $this->getID(), + $path + ); + return PhabricatorEnv::getProductionURI(implode('/', $components)); + } + + public function setDetail($key, $value) { + $this->details[$key] = $value; + return $this; + } + + public function willSaveObject() { + // Do this first, to generate the PHID + parent::willSaveObject(); + + $banned_names = $this->getBannedNames(); + if (in_array($this->name, $banned_names)) { + throw new Exception(sprintf( + "The name '%s' is in the list of banned project names!", + $this->name, + implode(', ', $banned_names))); + } + + if (!$this->getDetail('releaseCounter')) { + $this->setDetail('releaseCounter', 0); + } + } + + public function loadPhabricatorProject() { + if ($id = $this->getProjectID()) { + return id(new PhabricatorProject())->load($id); + } + return id(new PhabricatorProject())->makeEphemeral(); // dummy + } + + public function loadArcanistProject() { + return $this->loadOneRelative( + new PhabricatorRepositoryArcanistProject(), + 'id', + 'getArcanistProjectID'); + } + + public function getPushers() { + return $this->getDetail('pushers', array()); + } + + public function isPusherPHID($phid) { + $pusher_phids = $this->getDetail('pushers', array()); + return in_array($phid, $pusher_phids); + } + + public function isPusher(PhabricatorUser $user) { + return $this->isPusherPHID($user->getPHID()); + } + + public function loadPhabricatorRepository() { + return $this->loadOneRelative( + new PhabricatorRepository(), + 'id', + 'getRepositoryID'); + } + + public function getCurrentReleaseNumber() { + $current_release_numbers = array(); + + // From the project... + $current_release_numbers[] = $this->getDetail('releaseCounter', 0); + + // From any branches... + $branches = id(new ReleephBranch())->loadAllWhere( + 'releephProjectID = %d', $this->getID()); + if ($branches) { + $release_numbers = array(); + foreach ($branches as $branch) { + $current_release_numbers[] = $branch->getDetail('releaseNumber', 0); + } + } + + return max($current_release_numbers); + } + + public function getReleephFieldSelector() { + $class = $this->getDetail('field_selector'); + if (!$class) { + $key = 'releeph.field-selector'; + $class = PhabricatorEnv::getEnvConfig($key); + } + + if ($class) { + return newv($class, array()); + } else { + return new ReleephDefaultFieldSelector(); + } + } + + /** + * Wrapper to setIsActive() that logs who deactivated a project + */ + public function deactivate(PhabricatorUser $actor) { + return $this + ->setIsActive(0) + ->setDetail('last_deactivated_user', $actor->getPHID()) + ->setDetail('last_deactivated_time', time()); + } + + // Hide this from the public + private function setIsActive($v) { + return parent::setIsActive($v); + } + + private function getBannedNames() { + return array( + 'branch', // no one's tried this... yet! + ); + } + + public function isTestFile($filename) { + $test_paths = $this->getDetail('testPaths', array()); + + foreach ($test_paths as $test_path) { + if (preg_match($test_path, $filename)) { + return true; + } + } + return false; + } +} diff --git a/src/applications/releeph/storage/ReleephRequest.php b/src/applications/releeph/storage/ReleephRequest.php new file mode 100644 index 000000000..d7bb01304 --- /dev/null +++ b/src/applications/releeph/storage/ReleephRequest.php @@ -0,0 +1,309 @@ +<?php + +final class ReleephRequest extends ReleephDAO { + + protected $phid; + protected $branchID; + protected $requestUserPHID; + protected $details = array(); + protected $userIntents = array(); + protected $inBranch; + protected $pickStatus; + + // Information about the thing being requested + protected $requestCommitIdentifier; + protected $requestCommitPHID; + protected $requestCommitOrdinal; + + // Information about the last commit to the releeph branch + protected $commitIdentifier; + protected $committedByUserPHID; + protected $commitPHID; + + // Pre-populated handles that we'll bulk load in ReleephBranch + private $handles; + + +/* -( Constants and helper methods )--------------------------------------- */ + + const INTENT_WANT = 'want'; + const INTENT_PASS = 'pass'; + + const PICK_PENDING = 1; // old + const PICK_FAILED = 2; + const PICK_OK = 3; + const PICK_MANUAL = 4; // old + const REVERT_OK = 5; + const REVERT_FAILED = 6; + + const STATUS_REQUESTED = 1; + const STATUS_NEEDS_PICK = 2; // aka approved + const STATUS_REJECTED = 3; + const STATUS_ABANDONED = 4; + const STATUS_PICKED = 5; + const STATUS_REVERTED = 6; + const STATUS_NEEDS_REVERT = 7; // aka revert requested + + public function shouldBeInBranch() { + return + $this->getPusherIntent() == self::INTENT_WANT && + /** + * We use "!= pass" instead of "== want" in case the requestor intent is + * not present. In other words, only revert if the requestor explicitly + * passed. + */ + $this->getRequestorIntent() != self::INTENT_PASS; + } + + /** + * Will return INTENT_WANT if any pusher wants this request, and no pusher + * passes on this request. + */ + public function getPusherIntent() { + $project = $this->loadReleephProject(); + if (!$project->getPushers()) { + return self::INTENT_WANT; + } + + $found_pusher_want = false; + foreach ($this->userIntents as $phid => $intent) { + if ($project->isPusherPHID($phid)) { + if ($intent == self::INTENT_PASS) { + return self::INTENT_PASS; + } + + $found_pusher_want = true; + } + } + + if ($found_pusher_want) { + return self::INTENT_WANT; + } else { + return null; + } + } + + public function getRequestorIntent() { + return idx($this->userIntents, $this->requestUserPHID); + } + + public function getStatus() { + return $this->calculateStatus(); + } + + private function calculateStatus() { + if ($this->shouldBeInBranch()) { + if ($this->getInBranch()) { + return self::STATUS_PICKED; + } else { + return self::STATUS_NEEDS_PICK; + } + } else { + if ($this->getInBranch()) { + return self::STATUS_NEEDS_REVERT; + } else { + $has_been_in_branch = $this->getCommitIdentifier(); + // Regardless of why we reverted something, always say reverted if it + // was once in the branch. + if ($has_been_in_branch) { + return self::STATUS_REVERTED; + } elseif ($this->getPusherIntent() === ReleephRequest::INTENT_PASS) { + // Otherwise, if it has never been in the branch, explicitly say why: + return self::STATUS_REJECTED; + } elseif ($this->getRequestorIntent() === ReleephRequest::INTENT_WANT) { + return self::STATUS_REQUESTED; + } else { + return self::STATUS_ABANDONED; + } + } + } + } + + public static function getStatusDescriptionFor($status) { + static $descriptions = array( + self::STATUS_REQUESTED => 'Requested', + self::STATUS_REJECTED => 'Rejected', + self::STATUS_ABANDONED => 'Abandoned', + self::STATUS_PICKED => 'Picked', + self::STATUS_REVERTED => 'Reverted', + self::STATUS_NEEDS_PICK => 'Needs Pick', + self::STATUS_NEEDS_REVERT => 'Needs Revert', + ); + return idx($descriptions, $status, '??'); + } + + public static function getStatusClassSuffixFor($status) { + $description = self::getStatusDescriptionFor($status); + $class = str_replace(' ', '-', strtolower($description)); + return $class; + } + + +/* -( Lisk mechanics )----------------------------------------------------- */ + + public function getConfiguration() { + return array( + self::CONFIG_AUX_PHID => true, + self::CONFIG_SERIALIZATION => array( + 'details' => self::SERIALIZATION_JSON, + 'userIntents' => self::SERIALIZATION_JSON, + ), + ) + parent::getConfiguration(); + } + + public function generatePHID() { + return PhabricatorPHID::generateNewPHID( + ReleephPHIDConstants::PHID_TYPE_RERQ); + } + + +/* -( Helpful accessors )--------------------------------------------------- */ + + public function setHandles($handles) { + $this->handles = $handles; + return $this; + } + + public function getHandles() { + if (!$this->handles) { + throw new Exception( + "You must call ReleephBranch::populateReleephRequestHandles() first"); + } + return $this->handles; + } + + public function getDetail($key, $default = null) { + return idx($this->getDetails(), $key, $default); + } + + public function setDetail($key, $value) { + $this->details[$key] = $value; + return $this; + } + + public function getReason() { + // Backward compatibility: reason used to be called comments + $reason = $this->getDetail('reason'); + if (!$reason) { + return $this->getDetail('comments'); + } + return $reason; + } + + public function getSummary() { + /** + * Instead, you can use: + * - getDetail('summary') // the actual user-chosen summary + * - getSummaryForDisplay() // falls back to the original commit title + * + * Or for the fastidious: + * - id(new ReleephSummaryFieldSpecification()) + * ->setReleephRequest($rr) + * ->getValue() // programmatic equivalent to getDetail() + */ + throw new Exception( + "getSummary() has been deprecated!"); + } + + /** + * Allow a null summary, and fall back to the title of the commit. + */ + public function getSummaryForDisplay() { + $summary = $this->getDetail('summary'); + + if (!$summary) { + $pr_commit_data = $this->loadPhabricatorRepositoryCommitData(); + if ($pr_commit_data) { + $message_lines = explode("\n", $pr_commit_data->getCommitMessage()); + $message_lines = array_filter($message_lines); + $summary = head($message_lines); + } + } + + if (!$summary) { + $summary = '(no summary given and commit message empty or unparsed)'; + } + + return $summary; + } + + public function loadRequestCommitDiffPHID() { + $commit_data = $this->loadPhabricatorRepositoryCommitData(); + if (!$commit_data) { + return null; + } + return $commit_data->getCommitDetail('differential.revisionPHID'); + } + + +/* -( Loading external objects )------------------------------------------- */ + + public function loadReleephBranch() { + return $this->loadOneRelative( + new ReleephBranch(), + 'id', + 'getBranchID'); + } + + public function loadReleephProject() { + return $this->loadReleephBranch()->loadReleephProject(); + } + + public function loadEvents() { + return $this->loadRelatives( + new ReleephRequestEvent(), + 'releephRequestID', + 'getID', + '(1 = 1) ORDER BY dateCreated, id'); + } + + public function loadPhabricatorRepositoryCommit() { + return $this->loadOneRelative( + new PhabricatorRepositoryCommit(), + 'phid', + 'getRequestCommitPHID'); + } + + public function loadPhabricatorRepositoryCommitData() { + return $this->loadOneRelative( + new PhabricatorRepositoryCommitData(), + 'commitID', + 'getRequestCommitOrdinal'); + } + + public function loadDifferentialRevision() { + return $this->loadOneRelative( + new DifferentialRevision(), + 'phid', + 'loadRequestCommitDiffPHID'); + } + + +/* -( State change helpers )----------------------------------------------- */ + + public function setUserIntent(PhabricatorUser $user, $intent) { + $this->userIntents[$user->getPHID()] = $intent; + return $this; + } + + +/* -( Migrating to status-less ReleephRequests )--------------------------- */ + + protected function didReadData() { + if ($this->userIntents === null) { + $this->userIntents = array(); + } + } + + public function setStatus($value) { + throw new Exception('`status` is now deprecated!'); + } + + +/* -( Make magic Lisk methods private )------------------------------------ */ + + private function setUserIntents(array $ar) { + return parent::setUserIntents($ar); + } + +} diff --git a/src/applications/releeph/storage/event/ReleephEvent.php b/src/applications/releeph/storage/event/ReleephEvent.php new file mode 100644 index 000000000..e3333ec4e --- /dev/null +++ b/src/applications/releeph/storage/event/ReleephEvent.php @@ -0,0 +1,39 @@ +<?php + +final class ReleephEvent extends ReleephDAO { + + const TYPE_BRANCH_CREATE = 'branch-create'; + const TYPE_BRANCH_ACCESS = 'branch-access-change'; + + protected $releephProjectID; + protected $releephBranchID; + protected $type; + protected $epoch; + protected $actorPHID; + protected $details = array(); + + public function getConfiguration() { + return array( + self::CONFIG_SERIALIZATION => array( + 'details' => self::SERIALIZATION_JSON, + ), + ) + parent::getConfiguration(); + } + + public function getDetail($key, $default = null) { + return idx($this->details, $key, $default); + } + + public function setDetail($key, $value) { + $this->details[$key] = $value; + return $this; + } + + protected function willSaveObject() { + parent::willSaveObject(); + if (!$this->epoch) { + $this->epoch = $this->dateCreated; + } + } + +} diff --git a/src/applications/releeph/storage/request/ReleephRequestEvent.php b/src/applications/releeph/storage/request/ReleephRequestEvent.php new file mode 100644 index 000000000..b427516d4 --- /dev/null +++ b/src/applications/releeph/storage/request/ReleephRequestEvent.php @@ -0,0 +1,94 @@ +<?php + +final class ReleephRequestEvent extends ReleephDAO { + + const TYPE_CREATE = 'create'; + const TYPE_STATUS = 'status'; // old events + const TYPE_USER_INTENT = 'user-intent'; + const TYPE_PICK_STATUS = 'pick-status'; + const TYPE_COMMIT = 'commit'; + const TYPE_MANUAL_ACTION = 'manual-action'; + const TYPE_DISCOVERY = 'discovery'; + const TYPE_COMMENT = 'comment'; + + protected $releephRequestID; + protected $type; + protected $actorPHID; + protected $details = array(); + + public function getConfiguration() { + return array( + self::CONFIG_SERIALIZATION => array( + 'details' => self::SERIALIZATION_JSON, + ), + ) + parent::getConfiguration(); + } + + public function getDetail($key, $default = null) { + return idx($this->details, $key, $default); + } + + public function setDetail($key, $value) { + $this->details[$key] = $value; + return $this; + } + + private function setDetails(array $details) { + throw new Exception('Use setDetail()!'); + } + + public function setStatusBefore($status) { + return $this->setDetail('oldStatus', $status); + } + + public function setStatusAfter($status) { + return $this->setDetail('newStatus', $status); + } + + public function getStatusBefore() { + return $this->getDetail('oldStatus'); + } + + public function getStatusAfter() { + return $this->getDetail('newStatus'); + } + + public function getComment() { + return $this->getDetail('comment'); + } + + public function extractPHIDs() { + $phids = array(); + $phids[] = $this->actorPHID; + foreach ($this->details as $key => $value) { + if (strpos($key, 'PHID') !== false || strpos($key, 'phid') !== false) { + $phids[] = $value; + } + } + return $phids; + } + + public function canGroupWith(ReleephRequestEvent $next) { + if ($this->getActorPHID() != $next->getActorPHID()) { + return false; + } + + if ($this->getComment() && $next->getComment()) { + return false; + } + + // Break the chain if the next event changes the status + if ($next->getStatusBefore() != $next->getStatusAfter()) { + return false; + } + + // Don't group if the next event starts off with a different status to the + // one we ended with. This probably shouldn't ever happen. + if ($this->getStatusAfter() != $next->getStatusBefore()) { + return false; + } + + return true; + } + +} diff --git a/src/applications/releeph/storage/request/exception/ReleephRequestException.php b/src/applications/releeph/storage/request/exception/ReleephRequestException.php new file mode 100644 index 000000000..6f22f8c29 --- /dev/null +++ b/src/applications/releeph/storage/request/exception/ReleephRequestException.php @@ -0,0 +1,3 @@ +<?php + +final class ReleephRequestException extends Exception {} diff --git a/src/applications/releeph/view/ReleephProjectView.php b/src/applications/releeph/view/ReleephProjectView.php new file mode 100644 index 000000000..49f17d135 --- /dev/null +++ b/src/applications/releeph/view/ReleephProjectView.php @@ -0,0 +1,155 @@ +<?php + +final class ReleephProjectView extends AphrontView { + + private $showOpenBranches = true; + private $releephProject; + private $releephBranches; + + public function setShowOpenBranches($active) { + $this->showOpenBranches = $active; + return $this; + } + + public function setReleephProject($releeph_project) { + $this->releephProject = $releeph_project; + return $this; + } + + public function setBranches($branches) { + $this->releephBranches = $branches; + return $this; + } + + public function render() { + $releeph_project = $this->releephProject; + + if ($this->showOpenBranches) { + $releeph_branches = mfilter($this->releephBranches, 'getIsActive'); + } else { + $releeph_branches = mfilter($this->releephBranches, 'getIsActive', true); + } + + // Load all relevant PHID handles + $phids = array_merge( + array( + $this->releephProject->getPHID(), + $this->releephProject->getRepositoryPHID(), + ), + mpull($releeph_branches, 'getCreatedByUserPHID'), + mpull($releeph_branches, 'getCutPointCommitPHID'), + $releeph_project->getPushers()); + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($this->getUser()) + ->loadHandles(); + + // Sort branches, which requires the handles above + $releeph_branches = self::sortBranches($releeph_branches, $handles); + + // The header + $repository_phid = $releeph_project->getRepositoryPHID(); + + $header = hsprintf( + '%s in %s repository', + $releeph_project->getName(), + $handles[$repository_phid]->renderLink()); + + if ($this->showOpenBranches) { + $view_other_link = phutil_tag( + 'a', + array( + 'href' => $releeph_project->getURI('closedbranches/'), + ), + 'View closed branches'); + } else { + $view_other_link = phutil_tag( + 'a', + array( + 'href' => $releeph_project->getURI(), + ), + 'View open branches'); + } + + $header = hsprintf("%s · %s", $header, $view_other_link); + + // The "create branch" button + $create_branch_url = $releeph_project->getURI('cutbranch/'); + + // Pushers info + $pushers_info = array(); + $pushers = $releeph_project->getPushers(); + require_celerity_resource('releeph-project'); + if ($pushers) { + $pushers_info[] = phutil_tag('h2', array(), 'Pushers'); + foreach ($pushers as $user_phid) { + $handle = $handles[$user_phid]; + $div = phutil_tag( + 'div', + array( + 'class' => 'releeph-pusher', + 'style' => 'background-image: url('.$handle->getImageURI().');', + ), + phutil_tag( + 'div', + array( + 'class' => 'releeph-pusher-body', + ), + $handles[$user_phid]->renderLink())); + $pushers_info[] = $div; + } + + $pushers_info[] = hsprintf('<div style="clear: both;"></div>'); + } + + // Put it all together + $panel = id(new AphrontPanelView()) + ->setHeader($header) + ->appendChild(phutil_implode_html('', $pushers_info)); + + foreach ($releeph_branches as $ii => $releeph_branch) { + $box = id(new ReleephBranchBoxView()) + ->setUser($this->user) + ->setHandles($handles) + ->setReleephBranch($releeph_branch) + ->setNamed(); + + if ($ii === 0) { + $box->setLatest(); + } + $panel->appendChild($box); + } + + return $panel->render(); + } + + /** + * Sort branches by the point at which they were cut, newest cut points + * first. + * + * If branches share a cut point, sort newest branch first. + */ + private static function sortBranches($branches, $handles) { + // Group by commit phid + $groups = mgroup($branches, 'getCutPointCommitPHID'); + + // Convert commit phid to a commit timestamp + $ar = array(); + foreach ($groups as $cut_phid => $group) { + $handle = $handles[$cut_phid]; + // Pack (timestamp, group-with-this-timestamp) pairs into $ar + $ar[] = array( + $handle->getTimestamp(), + msort($group, 'getDateCreated') + ); + } + + $branches = array(); + // Sort by timestamp, pull groups, and flatten into one big group + foreach (ipull(isort($ar, 0), 1) as $group) { + $branches = array_merge($branches, $group); + } + + return array_reverse($branches); + } + +} diff --git a/src/applications/releeph/view/branch/ReleephBranchBoxView.php b/src/applications/releeph/view/branch/ReleephBranchBoxView.php new file mode 100644 index 000000000..54b756d3f --- /dev/null +++ b/src/applications/releeph/view/branch/ReleephBranchBoxView.php @@ -0,0 +1,225 @@ +<?php + +final class ReleephBranchBoxView extends AphrontView { + + private $releephBranch; + private $isLatest = false; + private $isNamed = false; + private $handles; + + public function setReleephBranch(ReleephBranch $br) { + $this->releephBranch = $br; + return $this; + } + + // Primary highlighted branch + public function setLatest() { + $this->isLatest = true; + return $this; + } + + // Secondary highlighted branch(es) + public function setNamed() { + $this->isNamed = true; + return $this; + } + + public function setHandles($handles) { + $this->handles = $handles; + return $this; + } + + public function render() { + $br = $this->releephBranch; + + require_celerity_resource('releeph-branch'); + return phutil_tag( + 'div', + array( + 'class' => 'releeph-branch-box'. + ($this->isNamed ? ' releeph-branch-box-named' : ''). + ($this->isLatest ? ' releeph-branch-box-latest' : ''), + ), + array( + $this->renderNames(), + $this->renderDatesTable(), + // "float: right" means the ordering here is weird + $this->renderButtons(), + $this->renderStatisticsTable(), + phutil_tag( + 'div', + array( + 'style' => 'clear:both;', + ), + ''))); + } + + private function renderNames() { + $br = $this->releephBranch; + + return phutil_tag( + 'div', + array( + 'class' => 'names', + ), + array( + phutil_tag( + 'h1', + array(), + $br->getDisplayName()), + phutil_tag( + 'h2', + array(), + $br->getName()))); + } + + private function renderDatesTable() { + $br = $this->releephBranch; + $branch_commit_handle = $this->handles[$br->getCutPointCommitPHID()]; + + $properties = array(); + $properties['Created by'] = + + $cut_age = phabricator_format_relative_time( + time() - $branch_commit_handle->getTimestamp()); + + return phutil_tag( + 'div', + array( + 'class' => 'date-info', + ), + array( + $this->handles[$br->getCreatedByUserPHID()]->renderLink(), + phutil_tag('br'), + phutil_tag( + 'a', + array( + 'href' => $branch_commit_handle->getURI(), + ), + $cut_age.' old'))); + } + + private function renderStatisticsTable() { + $statistics = array(); + + $requests = $this->releephBranch->loadReleephRequests($this->getUser()); + foreach ($requests as $request) { + $status = $request->getStatus(); + if (!isset($statistics[$status])) { + $statistics[$status] = 0; + } + $statistics[$status]++; + } + + static $col_groups = 3; + + $cells = array(); + foreach ($statistics as $status => $count) { + $description = ReleephRequest::getStatusDescriptionFor($status); + $cells[] = phutil_tag('th', array(), $count); + $cells[] = phutil_tag('td', array(), $description); + } + + $rows = array(); + while ($cells) { + $row_cells = array(); + for ($ii = 0; $ii < 2 * $col_groups; $ii++) { + $row_cells[] = array_shift($cells); + } + $rows[] = phutil_tag('tr', array(), $row_cells); + } + + if (!$rows) { + $rows = hsprintf('<tr><th></th><td>%s</td></tr>', 'none'); + } + + return phutil_tag( + 'div', + array( + 'class' => 'request-statistics', + ), + phutil_tag( + 'table', + array(), + $rows)); + } + + private function renderButtons() { + $br = $this->releephBranch; + + $buttons = array(); + + $buttons[] = phutil_tag( + 'a', + array( + 'class' => 'small grey button', + 'href' => $br->getURI(), + ), + 'View Requests'); + + $repo = $br->loadReleephProject()->loadPhabricatorRepository(); + if (!$repo) { + $buttons[] = phutil_tag( + 'a', + array( + 'class' => 'small button disabled', + ), + "Diffusion \xE2\x86\x97"); + } else { + $diffusion_request = DiffusionRequest::newFromDictionary(array( + 'repository' => $repo, + )); + $diffusion_branch_uri = $diffusion_request->generateURI(array( + 'action' => 'branch', + 'branch' => $br->getName(), + )); + $diffusion_button_class = 'small grey button'; + + $buttons[] = phutil_tag( + 'a', + array( + 'class' => $diffusion_button_class, + 'target' => '_blank', + 'href' => $diffusion_branch_uri, + ), + "Diffusion \xE2\x86\x97"); + } + + $releeph_project = $br->loadReleephProject(); + if (!$releeph_project->getPushers() || + $releeph_project->isPusher($this->user)) { + + $buttons[] = phutil_tag( + 'a', + array( + 'class' => 'small blue button', + 'href' => $br->getURI('edit/'), + ), + 'Edit'); + + if ($br->isActive()) { + $button_text = "Close"; + $href = $br->getURI('close/'); + } else { + $button_text = "Re-open"; + $href = $br->getURI('re-open/'); + } + $buttons[] = javelin_tag( + 'a', + array( + 'class' => 'small blue button', + 'href' => $href, + 'sigil' => 'workflow', + ), + $button_text); + } + + return phutil_tag( + 'div', + array( + 'class' => 'buttons', + ), + $buttons); + } + +} diff --git a/src/applications/releeph/view/branch/ReleephBranchPreviewView.php b/src/applications/releeph/view/branch/ReleephBranchPreviewView.php new file mode 100644 index 000000000..8f5f344f6 --- /dev/null +++ b/src/applications/releeph/view/branch/ReleephBranchPreviewView.php @@ -0,0 +1,60 @@ +<?php + +final class ReleephBranchPreviewView extends AphrontFormControl { + + private $statics = array(); + private $dynamics = array(); + + public function addControl($param_name, AphrontFormControl $control) { + $celerity_id = celerity_generate_unique_node_id(); + $control->setID($celerity_id); + $this->dynamics[$param_name] = $celerity_id; + return $this; + } + + public function addStatic($param_name, $value) { + $this->statics[$param_name] = $value; + return $this; + } + + public function getCustomControlClass() { + require_celerity_resource('releeph-preview-branch'); + return 'releeph-preview-branch'; + } + + public function renderInput() { + static $required_params = array( + 'arcProjectID', + 'projectName', + 'isSymbolic', + 'template', + ); + + $all_params = array_merge($this->statics, $this->dynamics); + foreach ($required_params as $param_name) { + if (idx($all_params, $param_name) === null) { + throw new Exception( + "'{$param_name}' is not set as either a static or dynamic!"); + } + } + + $output_id = celerity_generate_unique_node_id(); + + Javelin::initBehavior('releeph-preview-branch', array( + 'uri' => '/releeph/branch/preview/', + 'outputID' => $output_id, + 'params' => array( + 'static' => $this->statics, + 'dynamic' => $this->dynamics, + ) + )); + + return phutil_tag( + 'div', + array( + 'id' => $output_id, + ), + ''); + } + +} diff --git a/src/applications/releeph/view/branch/ReleephBranchTemplate.php b/src/applications/releeph/view/branch/ReleephBranchTemplate.php new file mode 100644 index 000000000..cef13ee25 --- /dev/null +++ b/src/applications/releeph/view/branch/ReleephBranchTemplate.php @@ -0,0 +1,241 @@ +<?php + +final class ReleephBranchTemplate { + + const KEY = 'releeph.default-branch-template'; + + public static function getDefaultTemplate() { + return PhabricatorEnv::getEnvConfig(self::KEY); + } + + public static function getRequiredDefaultTemplate() { + $template = self::getDefaultTemplate(); + if (!$template) { + throw new Exception(sprintf( + "Config setting '%s' must be set, ". + "or you must provide a branch-template for each project!", + self::KEY)); + } + return $template; + } + + public static function getFakeCommitHandleFor($arc_project_id) { + $arc_project = id(new PhabricatorRepositoryArcanistProject()) + ->load($arc_project_id); + if (!$arc_project) { + throw new Exception( + "No Arc project found with id '{$arc_project_id}'!"); + } + + $repository = $arc_project->loadRepository(); + return id(new PhabricatorObjectHandle()) + ->setName($repository->formatCommitName('100000000000')); + } + + private $commitHandle; + private $branchDate = null; + private $projectName; + private $isSymbolic; + + public function setCommitHandle(PhabricatorObjectHandle $handle) { + $this->commitHandle = $handle; + return $this; + } + + public function setBranchDate($branch_date) { + $this->branchDate = $branch_date; + return $this; + } + + public function setReleephProjectName($project_name) { + $this->projectName = $project_name; + return $this; + } + + public function setSymbolic($is_symbolic) { + $this->isSymbolic = $is_symbolic; + return $this; + } + + public function interpolate($template) { + if (!$this->projectName) { + return array('', array()); + } + + list($name, $name_errors) = $this->interpolateInner( + $template, + $this->isSymbolic); + + if ($this->isSymbolic) { + return array($name, $name_errors); + } else { + $validate_errors = $this->validateAsBranchName($name); + $errors = array_merge($name_errors, $validate_errors); + return array($name, $errors); + } + } + + public static function getHelpRemarkup() { + return <<<EOTEXT + +==== Interpolations ==== + +| Code | Meaning +| ----- | ------- +| `%P` | The name of your project, with spaces changed to "-". +| `%p` | Like %P, but all lowercase. +| `%Y` | The four digit year associated with the branch date. +| `%m` | The two digit month. +| `%d` | The two digit day. +| `%v` | The handle of the commit where the branch was cut ("rXYZa4b3c2d1"). +| `%V` | The abbreviated commit id where the branch was cut ("a4b3c2d1"). +| `%..` | Any other sequence interpreted by `strftime()`. +| `%%` | A literal percent sign. + + +==== Tips for Branch Templates ==== + +Use a directory to separate your release branches from other branches: + + lang=none + releases/%Y-%M-%d-%v + => releases/2012-30-16-rHERGE32cd512a52b7 + +Include a second hierarchy if you share your repository with other projects: + + lang=none + releases/%P/%p-release-%Y%m%d-%V + => releases/Tintin/tintin-release-20121116-32cd512a52b7 + +Keep your branch names simple, avoiding strange punctuation, most of which is +forbidden or escaped anyway: + + lang=none, counterexample + releases//..clown-releases..//`date --iso=seconds`-$(sudo halt) + +Include the date early in your template, in an order which sorts properly: + + lang=none + releases/%Y%m%d-%v + => releases/20121116-rHERGE32cd512a52b7 (good!) + + releases/%V-%m.%d.%Y + => releases/32cd512a52b7-11.16.2012 (awful!) + + +EOTEXT + ; + } + + /* + * xsprintf() would be useful here, but that's for formatting concrete lists + * of things in a certain way... + * + * animal_printf('%A %A %A', $dog1, $dog2, $dog3); + * + * ...rather than interpolating percent-control-strings like strftime does. + */ + private function interpolateInner($template, $is_symbolic) { + $name = $template; + $errors = array(); + + $safe_project_name = str_replace(' ', '-', $this->projectName); + $short_commit_id = last( + preg_split('/r[A-Z]+/', $this->commitHandle->getName())); + + $interpolations = array(); + for ($ii = 0; $ii < strlen($name); $ii++) { + $char = substr($name, $ii, 1); + $prev = null; + if ($ii > 0) { + $prev = substr($name, $ii - 1, 1); + } + $next = substr($name, $ii + 1, 1); + if ($next && $char == '%' && $prev != '%') { + $interpolations[$ii] = $next; + } + } + + $variable_interpolations = array(); + + $reverse_interpolations = $interpolations; + krsort($reverse_interpolations); + + if ($this->branchDate) { + $branch_date = $this->branchDate; + } else { + $branch_date = $this->commitHandle->getTimestamp(); + } + + foreach ($reverse_interpolations as $position => $code) { + $replacement = null; + switch ($code) { + case 'v': + $replacement = $this->commitHandle->getName(); + $is_variable = true; + break; + + case 'V': + $replacement = $short_commit_id; + $is_variable = true; + break; + + case 'P': + $replacement = $safe_project_name; + $is_variable = false; + break; + + case 'p': + $replacement = strtolower($safe_project_name); + $is_variable = false; + break; + + default: + // Format anything else using strftime() + $replacement = strftime("%{$code}", $branch_date); + $is_variable = true; + break; + } + + if ($is_variable) { + $variable_interpolations[] = $code; + } + $name = substr_replace($name, $replacement, $position, 2); + } + + if (!$is_symbolic && !$variable_interpolations) { + $errors[] = "Include additional interpolations that aren't static!"; + } + + return array($name, $errors); + } + + private function validateAsBranchName($name) { + $errors = array(); + + if (preg_match('{^/}', $name) || preg_match('{/$}', $name)) { + $errors[] = "Branches cannot begin or end with '/'"; + } + + if (preg_match('{//+}', $name)) { + $errors[] = "Branches cannot contain multiple consective '/'"; + } + + $parts = array_filter(explode('/', $name)); + foreach ($parts as $index => $part) { + $part_error = null; + if (preg_match('{^\.}', $part) || preg_match('{\.$}', $part)) { + $errors[] = "Path components cannot begin or end with '.'"; + } elseif (preg_match('{^(?!\w)}', $part)) { + $errors[] = "Path components must begin with an alphanumeric"; + } elseif (!preg_match('{^\w ([\w-_%\.]* [\w-_%])?$}x', $part)) { + $errors[] = + "Path components may only contain alphanumerics ". + "or '-', '_', or '.'"; + } + } + + return $errors; + } + +} diff --git a/src/applications/releeph/view/project/list/ReleephActiveProjectListView.php b/src/applications/releeph/view/project/list/ReleephActiveProjectListView.php new file mode 100644 index 000000000..6b9d533f2 --- /dev/null +++ b/src/applications/releeph/view/project/list/ReleephActiveProjectListView.php @@ -0,0 +1,102 @@ +<?php + +final class ReleephActiveProjectListView extends AphrontView { + + private $releephProjects; + + public function setReleephProjects(array $releeph_projects) { + $this->releephProjects = $releeph_projects; + return $this; + } + + public function render() { + $rows = array(); + foreach ($this->releephProjects as $releeph_project) { + $project_uri = $releeph_project->getURI(); + + $name_link = phutil_tag( + 'a', + array( + 'href' => $project_uri, + 'style' => 'font-weight: bold;', + ), + $releeph_project->getName()); + + $edit_button = phutil_tag( + 'a', + array( + 'href' => $releeph_project->getURI('edit/'), + 'class' => 'small grey button', + ), + 'Edit'); + + $deactivate_button = javelin_tag( + 'a', + array( + 'href' => $releeph_project->getURI('action/deactivate/'), + 'class' => 'small grey button', + 'sigil' => 'workflow', + ), + 'Remove'); + + $arc_project = $releeph_project->loadArcanistProject(); + if ($arc_project) { + $arc_project_name = $arc_project->getName(); + } else { + $arc_project_name = phutil_tag( + 'i', + array(), + 'Deleted Arcanist Project'); + } + + $repo = $releeph_project->loadPhabricatorRepository(); + + if ($repo) { + $vcs_type = + PhabricatorRepositoryType::getNameForRepositoryType( + $repo->getVersionControlSystem()); + + $rows[] = array( + $name_link, + $repo->getName(), + $arc_project_name, + $vcs_type, + $edit_button, + $deactivate_button, + ); + } else { + $rows[] = array( + $name_link, + phutil_tag('i', array(), 'Deleted Repository'), + $arc_project_name, + null, + null, + $deactivate_button, + ); + } + } + + $table = new AphrontTableView($rows); + + $table->setHeaders(array( + 'Name', + 'Repository', + 'Arcanist Project', + 'Type', + '', + '' + )); + + $table->setColumnClasses(array( + null, + null, + 'wide', + null, + 'action', + 'action' + )); + + return $table->render(); + } + +} diff --git a/src/applications/releeph/view/project/list/ReleephInactiveProjectListView.php b/src/applications/releeph/view/project/list/ReleephInactiveProjectListView.php new file mode 100644 index 000000000..765145e20 --- /dev/null +++ b/src/applications/releeph/view/project/list/ReleephInactiveProjectListView.php @@ -0,0 +1,112 @@ +<?php + +final class ReleephInactiveProjectListView extends AphrontView { + + private $releephProjects; + + public function setReleephProjects(array $releeph_projects) { + $this->releephProjects = $releeph_projects; + return $this; + } + + public function render() { + $rows = array(); + + $phids = array(); + foreach ($this->releephProjects as $releeph_project) { + $phids[] = $releeph_project->getCreatedByUserPHID(); + if ($phid = $releeph_project->getDetail('last_deactivated_user')) { + $phids[] = $phid; + } + } + + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($this->getUser()) + ->loadHandles(); + + foreach ($this->releephProjects as $releeph_project) { + $repository = $releeph_project->loadPhabricatorRepository(); + + if (!$repository) { + // Ignore projects referring to repositories that have been deleted. + continue; + } + + $activate_link = javelin_tag( + 'a', + array( + 'href' => $releeph_project->getURI('action/activate/'), + 'class' => 'small grey button', + 'sigil' => 'workflow', + ), + 'Revive'); + + $delete_link = javelin_tag( + 'a', + array( + 'href' => $releeph_project->getURI('action/delete/'), + 'class' => 'small grey button', + 'sigil' => 'workflow', + ), + 'Delete'); + + $rows[] = array( + $releeph_project->getName(), + $repository->getName(), + $this->renderCreationInfo($releeph_project, $handles), + $this->renderDeletionInfo($releeph_project, $handles), + $activate_link, + $delete_link, + ); + } + + $table = new AphrontTableView($rows); + + $table->setHeaders(array( + 'Name', + 'Repository', + 'Created', + 'Deleted', + '', + '', + )); + + $table->setColumnClasses(array( + null, + null, + null, + 'wide', + 'action', + 'action', + )); + + return $table->render(); + } + + private function renderCreationInfo($releeph_project, $handles) { + $creator = $handles[$releeph_project->getCreatedByUserPHID()]; + $when = $releeph_project->getDateCreated(); + return hsprintf( + '%s by %s', + phabricator_relative_date($when, $this->user), + $creator->getName()); + } + + private function renderDeletionInfo($releeph_project, $handles) { + $deleted_on = $releeph_project->getDetail('last_deactivated_time'); + + $deleted_by_name = null; + $deleted_by_phid = $releeph_project->getDetail('last_deactivated_user'); + if ($deleted_by_phid) { + $deleted_by_name = $handles[$deleted_by_phid]->getName(); + } else { + $deleted_by_name = 'unknown'; + } + + return hsprintf( + '%s by %s', + phabricator_relative_date($deleted_on, $this->user), + $deleted_by_name); + } + +} diff --git a/src/applications/releeph/view/request/ReleephRequestIntentsView.php b/src/applications/releeph/view/request/ReleephRequestIntentsView.php new file mode 100644 index 000000000..b9c78680a --- /dev/null +++ b/src/applications/releeph/view/request/ReleephRequestIntentsView.php @@ -0,0 +1,104 @@ +<?php + +final class ReleephRequestIntentsView extends AphrontView { + + private $releephRequest; + private $releephProject; + + public function setReleephRequest(ReleephRequest $rq) { + $this->releephRequest = $rq; + return $this; + } + + public function setReleephProject(ReleephProject $rp) { + $this->releephProject = $rp; + return $this; + } + + public function render() { + require_celerity_resource('releeph-intents'); + + return phutil_tag( + 'div', + array( + 'class' => 'releeph-intents', + ), + array( + $this->renderIntentList(ReleephRequest::INTENT_WANT), + $this->renderIntentList(ReleephRequest::INTENT_PASS) + )); + } + + private function renderIntentList($render_intent) { + if (!$this->releephProject) { + throw new Exception("Must call setReleephProject() first!"); + } + + $project = $this->releephProject; + $request = $this->releephRequest; + $handles = $request->getHandles(); + + $is_want = $render_intent == ReleephRequest::INTENT_WANT; + $should = $request->shouldBeInBranch(); + + $pusher_links = array(); + $user_links = array(); + + $intents = $request->getUserIntents(); + foreach ($intents as $user_phid => $user_intent) { + if ($user_intent == $render_intent) { + $is_pusher = $project->isPusherPHID($user_phid); + + if ($is_pusher) { + $pusher_links[] = phutil_tag( + 'span', + array( + 'class' => 'pusher' + ), + $handles[$user_phid]->renderLink()); + } else { + $class = 'bystander'; + if ($request->getRequestUserPHID() == $user_phid) { + $class = 'requestor'; + } + $user_links[] = phutil_tag( + 'span', + array( + 'class' => $class, + ), + $handles[$user_phid]->renderLink()); + } + } + } + + // Don't render anything + if (!$pusher_links && !$user_links) { + return null; + } + + $links = array_merge($pusher_links, $user_links); + if ($links) { + $markup = $links; + } else { + $markup = array(' '); + } + + // Stick an arrow up front + $arrow_class = 'arrow '.$render_intent; + array_unshift($markup, phutil_tag( + 'div', + array( + 'class' => $arrow_class, + ), + '')); + + return phutil_tag( + 'div', + array( + 'class' => 'intents', + ), + $markup); + } + + +} diff --git a/src/applications/releeph/view/request/ReleephRequestStatusView.php b/src/applications/releeph/view/request/ReleephRequestStatusView.php new file mode 100644 index 000000000..4076f037f --- /dev/null +++ b/src/applications/releeph/view/request/ReleephRequestStatusView.php @@ -0,0 +1,53 @@ +<?php + +final class ReleephRequestStatusView extends AphrontView { + + private $releephRequest; + + public function setReleephRequest(ReleephRequest $rq) { + $this->releephRequest = $rq; + return $this; + } + + public function render() { + require_celerity_resource('releeph-status'); + + $request = $this->releephRequest; + $status = $request->getStatus(); + $pick_status = $request->getPickStatus(); + + $description = ReleephRequest::getStatusDescriptionFor($status); + + $warning = null; + + if ($status == ReleephRequest::STATUS_NEEDS_PICK) { + if ($pick_status == ReleephRequest::PICK_FAILED) { + $warning = 'Last pick failed!'; + } + } elseif ($status == ReleephRequest::STATUS_NEEDS_REVERT) { + if ($pick_status == ReleephRequest::REVERT_FAILED) { + $warning = 'Last revert failed!'; + } + } + + return phutil_tag( + 'div', + array( + 'class' => 'releeph-status', + ), + array( + phutil_tag( + 'div', + array( + 'class' => 'description', + ), + $description), + phutil_tag( + 'div', + array( + 'class' => 'warning', + ), + $warning))); + } + +} diff --git a/src/applications/releeph/view/request/ReleephRequestTypeaheadControl.php b/src/applications/releeph/view/request/ReleephRequestTypeaheadControl.php new file mode 100644 index 000000000..a6f0355fd --- /dev/null +++ b/src/applications/releeph/view/request/ReleephRequestTypeaheadControl.php @@ -0,0 +1,58 @@ +<?php + +final class ReleephRequestTypeaheadControl extends AphrontFormControl { + + private $repo; + private $startTime; + + public function setRepo(PhabricatorRepository $repo) { + $this->repo = $repo; + return $this; + } + + public function setStartTime($epoch) { + $this->startTime = $epoch; + return $this; + } + + public function getCustomControlClass() { + return 'releeph-request-typeahead'; + } + + public function renderInput() { + $id = celerity_generate_unique_node_id(); + + $div = phutil_tag( + 'div', + array( + 'style' => 'position: relative;', + 'id' => $id, + ), + phutil_tag( + 'input', + array( + 'autocomplete' => 'off', + 'type' => 'text', + 'name' => $this->getName(), + ), + '')); + + require_celerity_resource('releeph-request-typeahead-css'); + + Javelin::initBehavior('releeph-request-typeahead', array( + 'id' => $id, + 'src' => '/releeph/request/typeahead/', + 'placeholder' => 'Type a commit id or first line of commit message...', + 'value' => $this->getValue(), + 'aux' => array( + 'repo' => $this->repo->getID(), + 'callsign' => $this->repo->getCallsign(), + 'since' => $this->startTime, + 'limit' => 16, + ) + )); + + return $div; + } + +} diff --git a/src/applications/releeph/view/request/header/ReleephRequestHeaderListView.php b/src/applications/releeph/view/request/header/ReleephRequestHeaderListView.php new file mode 100644 index 000000000..98dd9d44b --- /dev/null +++ b/src/applications/releeph/view/request/header/ReleephRequestHeaderListView.php @@ -0,0 +1,113 @@ +<?php + +final class ReleephRequestHeaderListView + extends AphrontView { + + private $originType; + private $releephProject; + private $releephBranch; + private $releephRequests; + private $aphrontRequest; + private $reload = false; + + private $errors = array(); + + public function setOriginType($origin) { + $this->originType = $origin; + return $this; + } + + public function setReleephProject(ReleephProject $rp) { + $this->releephProject = $rp; + return $this; + } + + public function setReleephBranch(ReleephBranch $rb) { + $this->releephBranch = $rb; + return $this; + } + + public function setReleephRequests(array $requests) { + assert_instances_of($requests, 'ReleephRequest'); + $this->releephRequests = $requests; + return $this; + } + + public function setAphrontRequest(AphrontRequest $request) { + $this->aphrontRequest = $request; + return $this; + } + + public function setReloadOnStateChange($bool) { + $this->reload = $bool; + return $this; + } + + public function render() { + $views = $this->renderInner(); + require_celerity_resource('phabricator-notification-css'); + Javelin::initBehavior('releeph-request-state-change', array( + 'reload' => $this->reload, + )); + + $error_view = null; + if ($this->errors) { + $error_view = id(new AphrontErrorView()) + ->setTitle('Bulk load errors') + ->setSeverity(AphrontErrorView::SEVERITY_WARNING) + ->setErrors($this->errors) + ->render(); + } + + $list = phutil_tag( + 'div', + array( + 'data-sigil' => 'releeph-request-header-list', + ), + $views); + + return $this->renderSingleView(array( + $error_view, + $list)); + } + + /** + * Required for generating markup for ReleephRequestActionController. + * + * That controller just needs the markup, and doesn't need to start the + * javelin behavior. + */ + public function renderInner() { + $selector = $this->releephProject->getReleephFieldSelector(); + $fields = $selector->getFieldSpecifications(); + foreach ($fields as $field) { + $field + ->setReleephProject($this->releephProject) + ->setReleephBranch($this->releephBranch) + ->setUser($this->user); + try { + $field->bulkLoad($this->releephRequests); + } catch (Exception $ex) { + $this->errors[] = $ex; + } + } + + $field_groups = $selector->arrangeFieldsForHeaderView($fields); + + $views = array(); + foreach ($this->releephRequests as $releeph_request) { + $views[] = id(new ReleephRequestHeaderView()) + ->setUser($this->user) + ->setAphrontRequest($this->aphrontRequest) + ->setOriginType($this->originType) + ->setReleephProject($this->releephProject) + ->setReleephBranch($this->releephBranch) + ->setReleephRequest($releeph_request) + ->setReleephFieldGroups($field_groups) + ->render(); + } + + return $views; + } + +} diff --git a/src/applications/releeph/view/request/header/ReleephRequestHeaderView.php b/src/applications/releeph/view/request/header/ReleephRequestHeaderView.php new file mode 100644 index 000000000..87753e5b8 --- /dev/null +++ b/src/applications/releeph/view/request/header/ReleephRequestHeaderView.php @@ -0,0 +1,334 @@ +<?php + +final class ReleephRequestHeaderView extends AphrontView { + + const THROW_PARAM = '__releeph_throw'; + + private $aphrontRequest; + private $releephRequest; + private $releephBranch; + private $releephProject; + private $originType; + private $fieldGroups; + + public function setAphrontRequest(AphrontRequest $request) { + $this->aphrontRequest = $request; + return $this; + } + + public function setReleephProject(ReleephProject $rp) { + $this->releephProject = $rp; + return $this; + } + + public function setReleephBranch(ReleephBranch $rb) { + $this->releephBranch = $rb; + return $this; + } + + public function setReleephRequest(ReleephRequest $rr) { + $this->releephRequest = $rr; + return $this; + } + + public function setOriginType($origin) { + // For the Edit controller + $this->originType = $origin; + return $this; + } + + public function setReleephFieldGroups(array $field_groups) { + $this->fieldGroups = $field_groups; + return $this; + } + + protected function getOrigin() { + return $this->originType; + } + + public function render() { + require_celerity_resource('releeph-core'); + $all_properties_table = $this->renderFields(); + + require_celerity_resource('releeph-colors'); + $status = $this->releephRequest->getStatus(); + $rr_div_class = + 'releeph-request-header '. + 'releeph-request-header-border '. + 'releeph-border-color-'.ReleephRequest::getStatusClassSuffixFor($status); + + $hidden_link = phutil_tag( + 'a', + array( + 'href' => '/RQ'.$this->releephRequest->getID(), + 'target' => '_blank', + 'data-sigil' => 'hidden-link', + ), + ''); + + $focus_char = phutil_tag( + 'div', + array( + 'class' => 'focus-char', + 'data-sigil' => 'focus-char', + ), + "\xE2\x98\x86"); + + $rr_div = phutil_tag( + 'div', + array( + 'data-sigil' => 'releeph-request-header', + 'class' => $rr_div_class, + ), + array( + phutil_tag( + 'div', + array(), + array( + phutil_tag( + 'h1', + array(), + array( + $focus_char, + $this->renderTitleLink(), + $hidden_link + )), + $all_properties_table, + )), + phutil_tag( + 'div', + array( + 'class' => 'button-divider', + ), + $this->renderActionButtonsTable()))); + + return $rr_div; + } + + private function renderFields() { + $field_row_groups = $this->fieldGroups; + + $trs = array(); + foreach ($field_row_groups as $field_column_group) { + $tds = array(); + foreach ($field_column_group as $side => $fields) { + $rows = array(); + foreach ($fields as $field) { + $rows[] = $this->renderOneField($field); + } + $pane = phutil_tag( + 'table', + array( + 'class' => 'fields', + ), + $rows); + $tds[] = phutil_tag( + 'td', + array( + 'class' => 'side '.$side, + ), + $pane); + } + $trs[] = phutil_tag( + 'tr', + array(), + $tds); + } + + return phutil_tag( + 'table', + array( + 'class' => 'panes', + ), + $trs); + } + + private function renderOneField(ReleephFieldSpecification $field) { + $field + ->setUser($this->user) + ->setReleephProject($this->releephProject) + ->setReleephBranch($this->releephBranch) + ->setReleephRequest($this->releephRequest); + + $label = $field->renderLabelForHeaderView(); + try { + $value = $field->renderValueForHeaderView(); + } catch (Exception $ex) { + if ($this->aphrontRequest->getInt(self::THROW_PARAM)) { + throw $ex; + } else { + $value = $this->renderExceptionIcon($ex); + } + } + + if ($value) { + if (!$label) { + return phutil_tag( + 'tr', + array(), + phutil_tag('td', array('colspan' => 2), $value)); + } else { + return phutil_tag( + 'tr', + array(), + array( + phutil_tag('th', array(), $label), + phutil_tag('td', array(), $value))); + } + } + } + + private function renderExceptionIcon(Exception $ex) { + Javelin::initBehavior('phabricator-tooltips'); + require_celerity_resource('aphront-tooltip-css'); + $throw_uri = $this + ->aphrontRequest + ->getRequestURI() + ->setQueryParam(self::THROW_PARAM, 1); + + $message = $ex->getMessage(); + if (!$message) { + $message = get_class($ex).' with no message.'; + } + + return javelin_tag( + 'a', + array( + 'class' => 'releeph-field-error', + 'sigil' => 'has-tooltip', + 'meta' => array( + 'tip' => $message, + 'size' => 400, + 'align' => 'E', + ), + 'href' => $throw_uri, + ), + '!!!'); + } + + private function renderTitleLink() { + $rq_id = $this->releephRequest->getID(); + $summary = $this->releephRequest->getSummaryForDisplay(); + return phutil_tag( + 'a', + array( + 'href' => '/RQ'.$rq_id, + ), + hsprintf( + 'RQ%d: %s', + $rq_id, + $summary)); + } + + private function renderActionButtonsTable() { + $left_buttons = array(); + $right_buttons = array(); + + $user_phid = $this->user->getPHID(); + $is_pusher = $this->releephProject->isPusherPHID($user_phid); + $is_requestor = $this->releephRequest->getRequestUserPHID() === $user_phid; + + $current_intent = idx( + $this->releephRequest->getUserIntents(), + $this->user->getPHID()); + + if ($is_pusher) { + $left_buttons[] = $this->renderIntentButton(true, 'Approve', 'green'); + $left_buttons[] = $this->renderIntentButton(false, 'Reject'); + } else { + if ($is_requestor) { + $right_buttons[] = $this->renderIntentButton(true, 'Request'); + $right_buttons[] = $this->renderIntentButton(false, 'Remove'); + } else { + $right_buttons[] = $this->renderIntentButton(true, 'Want'); + $right_buttons[] = $this->renderIntentButton(false, 'Pass'); + } + } + + // Allow the pusher to mark a request as manually picked or reverted. + if ($is_pusher || $is_requestor) { + if ($this->releephRequest->getInBranch()) { + $left_buttons[] = $this->renderActionButton( + 'Mark Manually Reverted', + 'mark-manually-reverted'); + } else { + $left_buttons[] = $this->renderActionButton( + 'Mark Manually Picked', + 'mark-manually-picked'); + } + } + + $right_buttons[] = phutil_tag( + 'a', + array( + 'href' => '/releeph/request/edit/'.$this->releephRequest->getID(). + '?origin='.$this->originType, + 'class' => 'small blue button', + ), + 'Edit'); + + if (!$left_buttons && !$right_buttons) { + return; + } + + $cells = array(); + foreach ($left_buttons as $button) { + $cells[] = phutil_tag('td', array('align' => 'left'), $button); + } + $cells[] = phutil_tag('td', array('class' => 'wide'), ''); + foreach ($right_buttons as $button) { + $cells[] = phutil_tag('td', array('align' => 'right'), $button); + } + + $table = phutil_tag( + 'table', + array( + 'class' => 'buttons', + ), + phutil_tag( + 'tr', + array(), + $cells)); + + return $table; + } + + private function renderIntentButton($want, $name, $class = null) { + $current_intent = idx( + $this->releephRequest->getUserIntents(), + $this->user->getPHID()); + + if ($current_intent) { + // If this is a "want" button, and they already want it, disable the + // button (and vice versa for the "pass" case.) + if (($want && $current_intent == ReleephRequest::INTENT_WANT) || + (!$want && $current_intent == ReleephRequest::INTENT_PASS)) { + + $class .= ' disabled'; + } + } + + $action = $want ? 'want' : 'pass'; + return $this->renderActionButton($name, $action, $class); + } + + private function renderActionButton($name, $action, $class=null) { + $attributes = array( + 'class' => 'small button '.$class, + 'sigil' => 'releeph-request-state-change '.$action, + 'meta' => null, + ); + + if ($class != 'disabled') { + // NB the trailing slash on $uri is critical, otherwise the URI will + // redirect to one with a slash, which will turn our GET into a POST. + $attributes['meta'] = sprintf( + '/releeph/request/action/%s/%d/', + $action, + $this->releephRequest->getID()); + } + + return javelin_tag('a', $attributes, $name); + } + +} diff --git a/src/applications/releeph/view/requestevent/ReleephRequestEventListView.php b/src/applications/releeph/view/requestevent/ReleephRequestEventListView.php new file mode 100644 index 000000000..ab0bca7d5 --- /dev/null +++ b/src/applications/releeph/view/requestevent/ReleephRequestEventListView.php @@ -0,0 +1,266 @@ +<?php + +final class ReleephRequestEventListView extends AphrontView { + + private $events; + private $handles; + + public function setEvents(array $events) { + assert_instances_of($events, 'ReleephRequestEvent'); + $this->events = $events; + return $this; + } + + public function setHandles(array $handles) { + assert_instances_of($handles, 'PhabricatorObjectHandle'); + $this->handles = $handles; + return $this; + } + + public function render() { + $views = array(); + + $discovered_commits = array(); + foreach ($this->events as $event) { + $commit_id = $event->getDetail('newCommitIdentifier'); + switch ($event->getType()) { + case ReleephRequestEvent::TYPE_DISCOVERY: + $discovered_commits[$commit_id] = true; + break; + } + } + + $markup_engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine(); + $markup_engine->setConfig('viewer', $this->getUser()); + + foreach ($this->events as $event) { + $description = $this->describeEvent($event); + if (!$description) { + continue; + } + + if ($event->getType() === ReleephRequestEvent::TYPE_COMMIT) { + $commit_id = $event->getDetail('newCommitIdentifier'); + if (idx($discovered_commits, $commit_id)) { + continue; + } + } + + $actor_handle = $this->handles[$event->getActorPHID()]; + $description = $this->describeEvent($event); + $action = phutil_tag( + 'div', + array(), + array( + $actor_handle->renderLink(), + ' ', + $description)); + + $view = id(new PhabricatorTransactionView()) + ->setUser($this->user) + ->setImageURI($actor_handle->getImageURI()) + ->setEpoch($event->getDateCreated()) + ->setActions(array($action)) + ->addClass($this->getTransactionClass($event)); + + $comment = $this->getEventComment($event); + if ($comment) { + $markup = phutil_tag( + 'div', + array( + 'class' => 'phabricator-remarkup', + ), + phutil_safe_html( + $markup_engine->markupText($comment))); + $view->appendChild($markup); + } + + $views[] = $view; + } + + return phutil_tag( + 'div', + array( + 'class' => 'releeph-request-event-list', + ), + $views); + } + + public function renderForEmail() { + $items = array(); + foreach ($this->events as $event) { + $description = $this->describeEvent($event); + if (!$description) { + continue; + } + $actor = $this->handles[$event->getActorPHID()]->getName(); + $items[] = $actor.' '.$description; + + $comment = $this->getEventComment($event); + if ($comment) { + $items[] = preg_replace('/^/m', ' ', $comment); + } + } + + return implode("\n\n", $items); + } + + private function describeEvent(ReleephRequestEvent $event) { + $type = $event->getType(); + + switch ($type) { + case ReleephRequestEvent::TYPE_CREATE: + return "created this request."; + break; + + case ReleephRequestEvent::TYPE_STATUS: + $status = $event->getStatusAfter(); + return sprintf( + "updated status to %s.", + ReleephRequest::getStatusDescriptionFor($status)); + break; + + case ReleephRequestEvent::TYPE_USER_INTENT: + $intent = $event->getDetail('newIntent'); + $was_pusher = $event->getDetail('wasPusher'); + if ($intent == ReleephRequest::INTENT_WANT) { + if ($was_pusher) { + $verb = "approved"; + } else { + $verb = "wanted"; + } + } else { + if ($was_pusher) { + $verb = "rejected"; + } else { + $verb = "passed on"; + } + } + return "{$verb} this request."; + break; + + case ReleephRequestEvent::TYPE_PICK_STATUS: + $pick_status = $event->getDetail('newPickStatus'); + switch ($pick_status) { + case ReleephRequest::PICK_FAILED: + return "found a conflict when picking."; + break; + + case ReleephRequest::REVERT_FAILED: + return "found a conflict when reverting."; + break; + + case ReleephRequest::PICK_OK: + case ReleephRequest::REVERT_OK: + // (nothing) + break; + + default: + return "changed pick-status to {$pick_status}."; + break; + } + break; + + case ReleephRequestEvent::TYPE_MANUAL_ACTION: + $action = $event->getDetail('action'); + return "claimed to have manually {$action}ed this request."; + break; + + case ReleephRequestEvent::TYPE_COMMIT: + $action = $event->getDetail('action'); + if ($action) { + return "{$action}ed this request."; + } else { + return "did something with this request."; + } + break; + + case ReleephRequestEvent::TYPE_DISCOVERY: + $action = $event->getDetail('action'); + if ($action) { + return "{$action}ed this request."; + } else { + // It's unlikely we'll have action-less TYPE_DISCOVERY events, but I + // used this during testing and I guess it's a useful safety net. + return "discovered this request in the branch."; + } + break; + + case ReleephRequestEvent::TYPE_COMMENT: + return "commented on this request."; + break; + + default: + return "did event of type {$type}."; + break; + } + } + + private function getEventComment(ReleephRequestEvent $event) { + switch ($event->getType()) { + case ReleephRequestEvent::TYPE_CREATE: + $commit_phid = $event->getDetail('commitPHID'); + return sprintf( + "Commit %s was requested.", + $this->handles[$commit_phid]->getName()); + break; + + case ReleephRequestEvent::TYPE_STATUS: + case ReleephRequestEvent::TYPE_USER_INTENT: + case ReleephRequestEvent::TYPE_PICK_STATUS: + case ReleephRequestEvent::TYPE_MANUAL_ACTION: + // no comment! + break; + + case ReleephRequestEvent::TYPE_COMMIT: + return sprintf( + "Closed by commit %s.", + $event->getDetail('newCommitIdentifier')); + break; + + case ReleephRequestEvent::TYPE_DISCOVERY: + $author_phid = $event->getDetail('authorPHID'); + $commit_phid = $event->getDetail('newCommitPHID'); + if ($author_phid && $author_phid != $event->getActorPHID()) { + return sprintf( + "Closed by commit %s (with author set to @%s).", + $this->handles[$commit_phid]->getName(), + $this->handles[$author_phid]->getName()); + } else { + return sprintf( + 'Closed by commit %s.', + $this->handles[$commit_phid]->getName()); + } + break; + + case ReleephRequestEvent::TYPE_COMMENT: + return $event->getComment(); + break; + } + } + + private function getTransactionClass($event) { + switch ($event->getType()) { + case ReleephRequestEvent::TYPE_COMMIT: + case ReleephRequestEvent::TYPE_DISCOVERY: + $action = $event->getDetail('action'); + if ($action == 'pick') { + return 'releeph-border-color-picked'; + } else { + return 'releeph-border-color-abandoned'; + } + break; + + case ReleephRequestEvent::TYPE_COMMENT: + return 'releeph-border-color-comment'; + break; + + default: + $status_after = $event->getStatusAfter(); + $class_suffix = ReleephRequest::getStatusClassSuffixFor($status_after); + return ' releeph-border-color-'.$class_suffix; + break; + } + } + +} diff --git a/src/applications/releeph/view/user/ReleephDefaultUserView.php b/src/applications/releeph/view/user/ReleephDefaultUserView.php new file mode 100644 index 000000000..93819cdad --- /dev/null +++ b/src/applications/releeph/view/user/ReleephDefaultUserView.php @@ -0,0 +1,9 @@ +<?php + +final class ReleephDefaultUserView extends ReleephUserView { + + public function render() { + return $this->getHandle()->renderLink(); + } + +} diff --git a/src/applications/releeph/view/user/ReleephUserView.php b/src/applications/releeph/view/user/ReleephUserView.php new file mode 100644 index 000000000..129c846ba --- /dev/null +++ b/src/applications/releeph/view/user/ReleephUserView.php @@ -0,0 +1,74 @@ +<?php + +abstract class ReleephUserView extends AphrontView { + + /** + * This function should bulk load everything you need to render all the given + * user phids. + * + * Many parts of Releeph load users for rendering. Accordingly, this + * function will be called multiple times for each part of the UI that + * renders users, so you should accumulate your results on each call. + * + * You should also implement render() (from AphrontView) to render each + * user's PHID. + */ + protected function loadInner(array $phids) { + // This is a hook! + } + + final public static function getNewInstance() { + $key = 'releeph.user-view'; + $class = PhabricatorEnv::getEnvConfig($key); + return newv($class, array()); + } + + private static $handles = array(); + private static $seen = array(); + + final public function load(array $phids) { + $todo = array(); + + foreach ($phids as $key => $phid) { + if (!idx(self::$seen, $phid)) { + $todo[$key] = $phid; + self::$seen[$phid] = true; + } + } + + if ($todo) { + self::$handles = array_merge( + self::$handles, + id(new PhabricatorObjectHandleData($todo)) + ->setViewer($this->getUser()) + ->loadHandles()); + $this->loadInner($todo); + } + } + + private $phid; + private $releephProject; + + final public function setRenderUserPHID($phid) { + $this->phid = $phid; + return $this; + } + + final public function setReleephProject(ReleephProject $project) { + $this->releephProject = $project; + return $this; + } + + final protected function getRenderUserPHID() { + return $this->phid; + } + + final protected function getReleephProject() { + return $this->releephProject; + } + + final protected function getHandle() { + return self::$handles[$this->phid]; + } + +} diff --git a/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php b/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php index 743be93d3..6cf673a37 100644 --- a/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php +++ b/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php @@ -1,292 +1,298 @@ <?php abstract class PhabricatorBaseEnglishTranslation extends PhabricatorTranslation { final public function getLanguage() { return 'en'; } public function getTranslations() { return array( 'Differential Revision(s)' => array( 'Differential Revision', 'Differential Revisions', ), 'file(s)' => array('file', 'files'), 'Maniphest Task(s)' => array('Maniphest Task', 'Maniphest Tasks'), 'Please fix these errors and try again.' => array( 'Please fix this error and try again.', 'Please fix these errors and try again.', ), '%d Error(s)' => array('%d Error', '%d Errors'), '%d Warning(s)' => array('%d Warning', '%d Warnings'), '%d Auto-Fix(es)' => array('%d Auto-Fix', '%d Auto-Fixes'), '%d Advice(s)' => array('%d Advice', '%d Pieces of Advice'), '%d Detail(s)' => array('%d Detail', '%d Details'), '(%d line(s))' => array('(%d line)', '(%d lines)'), 'COMMIT(S)' => array('COMMIT', 'COMMITS'), '%d line(s)' => array('%d line', '%d lines'), + '%d path(s)' => array('%d path', '%d paths'), + '%d diff(s)' => array('%d diff', '%d diffs'), 'added %d commit(s): %s' => array( 'added commit: %2$s', 'added commits: %2$s', ), 'removed %d commit(s): %s' => array( 'removed commit: %2$s', 'removed commits: %2$s', ), 'changed %d commit(s), added %d: %s; removed %d: %s' => 'changed commits, added: %3$s; removed: %5$s', 'ATTACHED %d COMMIT(S)' => array( 'ATTACHED COMMIT', 'ATTACHED COMMITS', ), 'added %d dependencie(s): %s' => array( 'added dependency: %2$s', 'added dependencies: %2$s', ), 'added %d dependent task(s): %s' => array( 'added dependent task: %2$s', 'added dependent tasks: %2$s', ), 'removed %d dependencie(s): %s' => array( 'removed dependency: %2$s', 'removed dependencies: %2$s', ), 'removed %d dependent task(s): %s' => array( 'removed dependent task: %2$s', 'removed dependent tasks: %2$s', ), 'changed %d dependencie(s), added %d: %s; removed %d: %s' => 'changed dependencies, added: %3$s; removed: %5$s', 'changed %d dependent task(s), added %d: %s; removed %d: %s', 'changed dependent tasks, added: %3$s; removed: %5$s', 'DEPENDENT %d TASK(s)' => array( 'DEPENDENT TASK', 'DEPENDENT TASKS', ), 'DEPENDS ON %d TASK(S)' => array( 'DEPENDS ON TASK', 'DEPENDS ON TASKS', ), 'DIFFERENTIAL %d REVISION(S)' => array( 'DIFFERENTIAL REVISION', 'DIFFERENTIAL REVISIONS', ), 'added %d revision(s): %s' => array( 'added revision: %2$s', 'added revisions: %2$s', ), 'removed %d revision(s): %s' => array( 'removed revision: %2$s', 'removed revisions: %2$s', ), 'changed %d revision(s), added %d: %s; removed %d: %s' => 'changed revisions, added %3$s; removed %5$s', 'There are %d raw fact(s) in storage.' => array( 'There is %d raw fact in storage.', 'There are %d raw facts in storage.', ), 'There are %d aggregate fact(s) in storage.' => array( 'There is %d aggregate fact in storage.', 'There are %d aggregate facts in storage.', ), '%d Commit(s) Awaiting Audit' => array( '%d Commit Awaiting Audit', '%d Commits Awaiting Audit', ), '%d Problem Commit(s)' => array( '%d Problem Commit', '%d Problem Commits', ), '%d Review(s) Blocking Others' => array( '%d Review Blocking Others', '%d Reviews Blocking Others', ), '%d Review(s) Need Attention' => array( '%d Review Needs Attention', '%d Reviews Need Attention', ), '%d Review(s) Waiting on Others' => array( '%d Review Waiting on Others', '%d Reviews Waiting on Others', ), '%d Flagged Object(s)' => array( '%d Flagged Object', '%d Flagged Objects', ), '%d Unbreak Now Task(s)!' => array( '%d Unbreak Now Task!', '%d Unbreak Now Tasks!', ), '%d Assigned Task(s)' => array( '%d Assigned Task', '%d Assigned Tasks', ), 'Show %d Lint Message(s)' => array( 'Show %d Lint Message', 'Show %d Lint Messages', ), 'Hide %d Lint Message(s)' => array( 'Hide %d Lint Message', 'Hide %d Lint Messages', ), 'Switch for %d Lint Message(s)' => array( 'Switch for %d Lint Message', 'Switch for %d Lint Messages', ), '%d Lint Message(s)' => array( '%d Lint Message', '%d Lint Messages', ), 'This is a binary file. It is %s byte(s) in length.' => array( 'This is a binary file. It is %s byte in length.', 'This is a binary file. It is %s bytes in length.', ), '%d Action(s) Have No Effect' => array( 'Action Has No Effect', 'Actions Have No Effect', ), '%d Action(s) With No Effect' => array( 'Action With No Effect', 'Actions With No Effect', ), '%s added %d subscriber(s): %s.' => array( array( '%s added a subscriber: %3$s.', '%s added subscribers: %3$s.', ), ), '%s removed %d subscriber(s): %s.' => array( array( '%s removed a subscriber: %3$s.', '%s removed subscribers: %3$s.', ), ), '%s added %d participant(s): %s.' => array( array( '%s added a participant: %3$s.', '%s added participants: %3$s.', ), ), '%s removed %d participant(s): %s.' => array( array( '%s removed a participant: %3$s.', '%s removed participants: %3$s.', ), ), '%s Line(s)' => array( '%s Line', '%s Lines', ), "Indexing %d object(s) of type %s." => array( "Indexing %d object of type %s.", "Indexing %d object of type %s.", ), 'Run these %d command(s):' => array( 'Run this command:', 'Run these commands:', ), 'Install these %d PHP extension(s):' => array( 'Install this PHP extension:', 'Install these PHP extensions:', ), 'The current Phabricator configuration has these %d value(s):' => array( 'The current Phabricator configuration has this value:', 'The current Phabricator configuration has these values:', ), 'To update these %d value(s), run these command(s) from the command line:' => array( 'To update this value, run this command from the command line:', 'To update these values, run these commands from the command line:', ), 'You can update these %d value(s) here:' => array( 'You can update this value here:', 'You can update these values here:', ), 'The current PHP configuration has these %d value(s):' => array( 'The current PHP configuration has this value:', 'The current PHP configuration has these values:', ), 'To update these %d value(s), edit your PHP configuration file.' => array( 'To update this %d value, edit your PHP configuration file.', 'To update these %d values, edit your PHP configuration file.', ), 'To update these %d value(s), edit your PHP configuration file, located '. 'here:' => array( 'To update this value, edit your PHP configuration file, located '. 'here:', 'To update these values, edit your PHP configuration file, located '. 'here:', ), 'PHP also loaded these configuration file(s):' => array( 'PHP also loaded this configuration file:', 'PHP also loaded these configuration files:', ), 'You have %d unresolved setup issue(s)...' => array( 'You have an unresolved setup issue...', 'You have %d unresolved setup issues...', ), '%s added %d inline comment(s).' => array( array( '%s added an inline comment.', '%s added inline comments.', ), ), + '%d comment(s)' => array('%d comment', '%d comments'), + '%d rejection(s)' => array('%d rejection', '%d rejections'), + '%d update(s)' => array('%d update', '%d updates'), + ); } } diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php index 2d4d5ec19..7a3a96fb7 100644 --- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php +++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php @@ -1,1171 +1,1179 @@ <?php final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList { public function getNamespace() { return 'phabricator'; } private function getPatchPath($file) { $root = dirname(phutil_get_library_root('phabricator')); $path = $root.'/resources/sql/patches/'.$file; // Make sure it exists. Filesystem::readFile($path); return $path; } public function getPatches() { return array( 'db.audit' => array( 'type' => 'db', 'name' => 'audit', 'after' => array( /* First Patch */ ), ), 'db.calendar' => array( 'type' => 'db', 'name' => 'calendar', ), 'db.chatlog' => array( 'type' => 'db', 'name' => 'chatlog', ), 'db.conduit' => array( 'type' => 'db', 'name' => 'conduit', ), 'db.countdown' => array( 'type' => 'db', 'name' => 'countdown', ), 'db.daemon' => array( 'type' => 'db', 'name' => 'daemon', ), 'db.differential' => array( 'type' => 'db', 'name' => 'differential', ), 'db.draft' => array( 'type' => 'db', 'name' => 'draft', ), 'db.drydock' => array( 'type' => 'db', 'name' => 'drydock', ), 'db.feed' => array( 'type' => 'db', 'name' => 'feed', ), 'db.file' => array( 'type' => 'db', 'name' => 'file', ), 'db.flag' => array( 'type' => 'db', 'name' => 'flag', ), 'db.harbormaster' => array( 'type' => 'db', 'name' => 'harbormaster', ), 'db.herald' => array( 'type' => 'db', 'name' => 'herald', ), 'db.maniphest' => array( 'type' => 'db', 'name' => 'maniphest', ), 'db.meta_data' => array( 'type' => 'db', 'name' => 'meta_data', ), 'db.metamta' => array( 'type' => 'db', 'name' => 'metamta', ), 'db.oauth_server' => array( 'type' => 'db', 'name' => 'oauth_server', ), 'db.owners' => array( 'type' => 'db', 'name' => 'owners', ), 'db.pastebin' => array( 'type' => 'db', 'name' => 'pastebin', ), 'db.phame' => array( 'type' => 'db', 'name' => 'phame', ), 'db.phriction' => array( 'type' => 'db', 'name' => 'phriction', ), 'db.project' => array( 'type' => 'db', 'name' => 'project', ), 'db.repository' => array( 'type' => 'db', 'name' => 'repository', ), 'db.search' => array( 'type' => 'db', 'name' => 'search', ), 'db.slowvote' => array( 'type' => 'db', 'name' => 'slowvote', ), 'db.timeline' => array( 'type' => 'db', 'name' => 'timeline', ), 'db.user' => array( 'type' => 'db', 'name' => 'user', ), 'db.worker' => array( 'type' => 'db', 'name' => 'worker', ), 'db.xhpastview' => array( 'type' => 'db', 'name' => 'xhpastview', ), 'db.cache' => array( 'type' => 'db', 'name' => 'cache', ), 'db.fact' => array( 'type' => 'db', 'name' => 'fact', ), 'db.ponder' => array( 'type' => 'db', 'name' => 'ponder', ), 'db.xhprof' => array( 'type' => 'db', 'name' => 'xhprof', ), 'db.pholio' => array( 'type' => 'db', 'name' => 'pholio', ), 'db.conpherence' => array( 'type' => 'db', 'name' => 'conpherence', ), 'db.config' => array( 'type' => 'db', 'name' => 'config', ), 'db.token' => array( 'type' => 'db', 'name' => 'token', ), + 'db.releeph' => array( + 'type' => 'db', + 'name' => 'releeph', + ), '0000.legacy.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('0000.legacy.sql'), 'legacy' => 0, ), '000.project.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('000.project.sql'), 'legacy' => 0, ), '001.maniphest_projects.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('001.maniphest_projects.sql'), 'legacy' => 1, ), '002.oauth.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('002.oauth.sql'), 'legacy' => 2, ), '003.more_oauth.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('003.more_oauth.sql'), 'legacy' => 3, ), '004.daemonrepos.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('004.daemonrepos.sql'), 'legacy' => 4, ), '005.workers.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('005.workers.sql'), 'legacy' => 5, ), '006.repository.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('006.repository.sql'), 'legacy' => 6, ), '007.daemonlog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('007.daemonlog.sql'), 'legacy' => 7, ), '008.repoopt.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('008.repoopt.sql'), 'legacy' => 8, ), '009.repo_summary.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('009.repo_summary.sql'), 'legacy' => 9, ), '010.herald.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('010.herald.sql'), 'legacy' => 10, ), '011.badcommit.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('011.badcommit.sql'), 'legacy' => 11, ), '012.dropphidtype.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('012.dropphidtype.sql'), 'legacy' => 12, ), '013.commitdetail.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('013.commitdetail.sql'), 'legacy' => 13, ), '014.shortcuts.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('014.shortcuts.sql'), 'legacy' => 14, ), '015.preferences.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('015.preferences.sql'), 'legacy' => 15, ), '016.userrealnameindex.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('016.userrealnameindex.sql'), 'legacy' => 16, ), '017.sessionkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('017.sessionkeys.sql'), 'legacy' => 17, ), '018.owners.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('018.owners.sql'), 'legacy' => 18, ), '019.arcprojects.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('019.arcprojects.sql'), 'legacy' => 19, ), '020.pathcapital.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('020.pathcapital.sql'), 'legacy' => 20, ), '021.xhpastview.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('021.xhpastview.sql'), 'legacy' => 21, ), '022.differentialcommit.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('022.differentialcommit.sql'), 'legacy' => 22, ), '023.dxkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('023.dxkeys.sql'), 'legacy' => 23, ), '024.mlistkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('024.mlistkeys.sql'), 'legacy' => 24, ), '025.commentopt.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('025.commentopt.sql'), 'legacy' => 25, ), '026.diffpropkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('026.diffpropkey.sql'), 'legacy' => 26, ), '027.metamtakeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('027.metamtakeys.sql'), 'legacy' => 27, ), '028.systemagent.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('028.systemagent.sql'), 'legacy' => 28, ), '029.cursors.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('029.cursors.sql'), 'legacy' => 29, ), '030.imagemacro.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('030.imagemacro.sql'), 'legacy' => 30, ), '031.workerrace.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('031.workerrace.sql'), 'legacy' => 31, ), '032.viewtime.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('032.viewtime.sql'), 'legacy' => 32, ), '033.privtest.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('033.privtest.sql'), 'legacy' => 33, ), '034.savedheader.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('034.savedheader.sql'), 'legacy' => 34, ), '035.proxyimage.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('035.proxyimage.sql'), 'legacy' => 35, ), '036.mailkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('036.mailkey.sql'), 'legacy' => 36, ), '037.setuptest.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('037.setuptest.sql'), 'legacy' => 37, ), '038.admin.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('038.admin.sql'), 'legacy' => 38, ), '039.userlog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('039.userlog.sql'), 'legacy' => 39, ), '040.transform.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('040.transform.sql'), 'legacy' => 40, ), '041.heraldrepetition.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('041.heraldrepetition.sql'), 'legacy' => 41, ), '042.commentmetadata.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('042.commentmetadata.sql'), 'legacy' => 42, ), '043.pastebin.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('043.pastebin.sql'), 'legacy' => 43, ), '044.countdown.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('044.countdown.sql'), 'legacy' => 44, ), '045.timezone.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('045.timezone.sql'), 'legacy' => 45, ), '046.conduittoken.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('046.conduittoken.sql'), 'legacy' => 46, ), '047.projectstatus.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('047.projectstatus.sql'), 'legacy' => 47, ), '048.relationshipkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('048.relationshipkeys.sql'), 'legacy' => 48, ), '049.projectowner.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('049.projectowner.sql'), 'legacy' => 49, ), '050.taskdenormal.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('050.taskdenormal.sql'), 'legacy' => 50, ), '051.projectfilter.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('051.projectfilter.sql'), 'legacy' => 51, ), '052.pastelanguage.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('052.pastelanguage.sql'), 'legacy' => 52, ), '053.feed.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('053.feed.sql'), 'legacy' => 53, ), '054.subscribers.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('054.subscribers.sql'), 'legacy' => 54, ), '055.add_author_to_files.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('055.add_author_to_files.sql'), 'legacy' => 55, ), '056.slowvote.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('056.slowvote.sql'), 'legacy' => 56, ), '057.parsecache.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('057.parsecache.sql'), 'legacy' => 57, ), '058.missingkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('058.missingkeys.sql'), 'legacy' => 58, ), '059.engines.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('059.engines.php'), 'legacy' => 59, ), '060.phriction.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('060.phriction.sql'), 'legacy' => 60, ), '061.phrictioncontent.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('061.phrictioncontent.sql'), 'legacy' => 61, ), '062.phrictionmenu.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('062.phrictionmenu.sql'), 'legacy' => 62, ), '063.pasteforks.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('063.pasteforks.sql'), 'legacy' => 63, ), '064.subprojects.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('064.subprojects.sql'), 'legacy' => 64, ), '065.sshkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('065.sshkeys.sql'), 'legacy' => 65, ), '066.phrictioncontent.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('066.phrictioncontent.sql'), 'legacy' => 66, ), '067.preferences.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('067.preferences.sql'), 'legacy' => 67, ), '068.maniphestauxiliarystorage.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('068.maniphestauxiliarystorage.sql'), 'legacy' => 68, ), '069.heraldxscript.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('069.heraldxscript.sql'), 'legacy' => 69, ), '070.differentialaux.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('070.differentialaux.sql'), 'legacy' => 70, ), '071.contentsource.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('071.contentsource.sql'), 'legacy' => 71, ), '072.blamerevert.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('072.blamerevert.sql'), 'legacy' => 72, ), '073.reposymbols.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('073.reposymbols.sql'), 'legacy' => 73, ), '074.affectedpath.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('074.affectedpath.sql'), 'legacy' => 74, ), '075.revisionhash.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('075.revisionhash.sql'), 'legacy' => 75, ), '076.indexedlanguages.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('076.indexedlanguages.sql'), 'legacy' => 76, ), '077.originalemail.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('077.originalemail.sql'), 'legacy' => 77, ), '078.nametoken.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('078.nametoken.sql'), 'legacy' => 78, ), '079.nametokenindex.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('079.nametokenindex.php'), 'legacy' => 79, ), '080.filekeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('080.filekeys.sql'), 'legacy' => 80, ), '081.filekeys.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('081.filekeys.php'), 'legacy' => 81, ), '082.xactionkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('082.xactionkey.sql'), 'legacy' => 82, ), '083.dxviewtime.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('083.dxviewtime.sql'), 'legacy' => 83, ), '084.pasteauthorkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('084.pasteauthorkey.sql'), 'legacy' => 84, ), '085.packagecommitrelationship.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('085.packagecommitrelationship.sql'), 'legacy' => 85, ), '086.formeraffil.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('086.formeraffil.sql'), 'legacy' => 86, ), '087.phrictiondelete.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('087.phrictiondelete.sql'), 'legacy' => 87, ), '088.audit.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('088.audit.sql'), 'legacy' => 88, ), '089.projectwiki.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('089.projectwiki.sql'), 'legacy' => 89, ), '090.forceuniqueprojectnames.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('090.forceuniqueprojectnames.php'), 'legacy' => 90, ), '091.uniqueslugkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('091.uniqueslugkey.sql'), 'legacy' => 91, ), '092.dropgithubnotification.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('092.dropgithubnotification.sql'), 'legacy' => 92, ), '093.gitremotes.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('093.gitremotes.php'), 'legacy' => 93, ), '094.phrictioncolumn.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('094.phrictioncolumn.sql'), 'legacy' => 94, ), '095.directory.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('095.directory.sql'), 'legacy' => 95, ), '096.filename.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('096.filename.sql'), 'legacy' => 96, ), '097.heraldruletypes.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('097.heraldruletypes.sql'), 'legacy' => 97, ), '098.heraldruletypemigration.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('098.heraldruletypemigration.php'), 'legacy' => 98, ), '099.drydock.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('099.drydock.sql'), 'legacy' => 99, ), '100.projectxaction.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('100.projectxaction.sql'), 'legacy' => 100, ), '101.heraldruleapplied.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('101.heraldruleapplied.sql'), 'legacy' => 101, ), '102.heraldcleanup.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('102.heraldcleanup.php'), 'legacy' => 102, ), '103.heraldedithistory.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('103.heraldedithistory.sql'), 'legacy' => 103, ), '104.searchkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('104.searchkey.sql'), 'legacy' => 104, ), '105.mimetype.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('105.mimetype.sql'), 'legacy' => 105, ), '106.chatlog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('106.chatlog.sql'), 'legacy' => 106, ), '107.oauthserver.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('107.oauthserver.sql'), 'legacy' => 107, ), '108.oauthscope.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('108.oauthscope.sql'), 'legacy' => 108, ), '109.oauthclientphidkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('109.oauthclientphidkey.sql'), 'legacy' => 109, ), '110.commitaudit.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('110.commitaudit.sql'), 'legacy' => 110, ), '111.commitauditmigration.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('111.commitauditmigration.php'), 'legacy' => 111, ), '112.oauthaccesscoderedirecturi.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('112.oauthaccesscoderedirecturi.sql'), 'legacy' => 112, ), '113.lastreviewer.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('113.lastreviewer.sql'), 'legacy' => 113, ), '114.auditrequest.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('114.auditrequest.sql'), 'legacy' => 114, ), '115.prepareutf8.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('115.prepareutf8.sql'), 'legacy' => 115, ), '116.utf8-backup-first-expect-wait.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('116.utf8-backup-first-expect-wait.sql'), 'legacy' => 116, ), '117.repositorydescription.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('117.repositorydescription.php'), 'legacy' => 117, ), '118.auditinline.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('118.auditinline.sql'), 'legacy' => 118, ), '119.filehash.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('119.filehash.sql'), 'legacy' => 119, ), '120.noop.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('120.noop.sql'), 'legacy' => 120, ), '121.drydocklog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('121.drydocklog.sql'), 'legacy' => 121, ), '122.flag.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('122.flag.sql'), 'legacy' => 122, ), '123.heraldrulelog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('123.heraldrulelog.sql'), 'legacy' => 123, ), '124.subpriority.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('124.subpriority.sql'), 'legacy' => 124, ), '125.ipv6.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('125.ipv6.sql'), 'legacy' => 125, ), '126.edges.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('126.edges.sql'), 'legacy' => 126, ), '127.userkeybody.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('127.userkeybody.sql'), 'legacy' => 127, ), '128.phabricatorcom.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('128.phabricatorcom.sql'), 'legacy' => 128, ), '129.savedquery.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('129.savedquery.sql'), 'legacy' => 129, ), '130.denormalrevisionquery.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('130.denormalrevisionquery.sql'), 'legacy' => 130, ), '131.migraterevisionquery.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('131.migraterevisionquery.php'), 'legacy' => 131, ), '132.phame.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('132.phame.sql'), 'legacy' => 132, ), '133.imagemacro.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('133.imagemacro.sql'), 'legacy' => 133, ), '134.emptysearch.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('134.emptysearch.sql'), 'legacy' => 134, ), '135.datecommitted.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('135.datecommitted.sql'), 'legacy' => 135, ), '136.sex.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('136.sex.sql'), 'legacy' => 136, ), '137.auditmetadata.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('137.auditmetadata.sql'), 'legacy' => 137, ), '138.notification.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('138.notification.sql'), ), 'holidays.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('holidays.sql'), ), 'userstatus.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('userstatus.sql'), ), 'emailtable.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('emailtable.sql'), ), 'emailtableport.sql' => array( 'type' => 'php', 'name' => $this->getPatchPath('emailtableport.php'), ), 'emailtableremove.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('emailtableremove.sql'), ), 'phiddrop.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('phiddrop.sql'), ), 'testdatabase.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('testdatabase.sql'), ), 'ldapinfo.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('ldapinfo.sql'), ), 'threadtopic.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('threadtopic.sql'), ), 'usertranslation.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('usertranslation.sql'), ), 'differentialbookmarks.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('differentialbookmarks.sql'), ), 'harbormasterobject.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('harbormasterobject.sql'), ), 'markupcache.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('markupcache.sql'), ), 'maniphestxcache.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('maniphestxcache.sql'), ), 'migrate-maniphest-dependencies.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('migrate-maniphest-dependencies.php'), ), 'migrate-differential-dependencies.php' => array( 'type' => 'php', 'name' => $this->getPatchPath( 'migrate-differential-dependencies.php'), ), 'phameblog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('phameblog.sql'), ), 'migrate-maniphest-revisions.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('migrate-maniphest-revisions.php'), ), 'daemonstatus.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('daemonstatus.sql'), ), 'symbolcontexts.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('symbolcontexts.sql'), ), 'migrate-project-edges.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('migrate-project-edges.php'), ), 'fact-raw.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('fact-raw.sql'), ), 'ponder.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('ponder.sql') ), 'policy-project.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('policy-project.sql'), ), 'daemonstatuskey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('daemonstatuskey.sql'), ), 'edgetype.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('edgetype.sql'), ), 'ponder-comments.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('ponder-comments.sql'), ), 'pastepolicy.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('pastepolicy.sql'), ), 'xhprof.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('xhprof.sql'), ), 'draft-metadata.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('draft-metadata.sql'), ), 'phamedomain.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('phamedomain.sql'), ), 'ponder-mailkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('ponder-mailkey.sql'), ), 'ponder-mailkey-populate.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('ponder-mailkey-populate.php'), ), 'phamepolicy.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('phamepolicy.sql'), ), 'phameoneblog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('phameoneblog.sql'), ), 'statustxt.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('statustxt.sql'), ), 'daemontaskarchive.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('daemontaskarchive.sql'), ), 'drydocktaskid.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('drydocktaskid.sql'), ), 'drydockresoucetype.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('drydockresourcetype.sql'), ), 'liskcounters.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('liskcounters.sql'), ), 'liskcounters.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('liskcounters.php'), ), 'dropfileproxyimage.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('dropfileproxyimage.sql'), ), 'repository-lint.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('repository-lint.sql'), ), 'liskcounters-task.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('liskcounters-task.sql'), ), 'pholio.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('pholio.sql'), ), 'owners-exclude.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('owners-exclude.sql'), ), '20121209.pholioxactions.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20121209.pholioxactions.sql'), ), '20121209.xmacroadd.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20121209.xmacroadd.sql'), ), '20121209.xmacromigrate.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('20121209.xmacromigrate.php'), ), '20121209.xmacromigratekey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20121209.xmacromigratekey.sql'), ), '20121220.generalcache.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20121220.generalcache.sql'), ), '20121226.config.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20121226.config.sql'), ), '20130101.confxaction.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130101.confxaction.sql'), ), '20130102.metamtareceivedmailmessageidhash.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130102.metamtareceivedmailmessageidhash.sql'), ), '20130103.filemetadata.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130103.filemetadata.sql'), ), '20130111.conpherence.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130111.conpherence.sql'), ), '20130127.altheraldtranscript.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130127.altheraldtranscript.sql'), ), '20130201.revisionunsubscribed.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('20130201.revisionunsubscribed.php'), ), '20130201.revisionunsubscribed.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130201.revisionunsubscribed.sql'), ), '20130131.conpherencepics.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130131.conpherencepics.sql'), ), '20130214.chatlogchannel.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130214.chatlogchannel.sql'), ), '20130214.chatlogchannelid.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130214.chatlogchannelid.sql'), ), '20130214.token.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130214.token.sql'), ), '20130215.phabricatorfileaddttl.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130215.phabricatorfileaddttl.sql'), ), '20130217.cachettl.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130217.cachettl.sql'), ), '20130218.updatechannelid.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('20130218.updatechannelid.php'), ), '20130218.longdaemon.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130218.longdaemon.sql'), ), '20130219.commitsummary.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130219.commitsummary.sql'), ), '20130219.commitsummarymig.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('20130219.commitsummarymig.php'), ), '20130222.dropchannel.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130222.dropchannel.sql'), ), '20130226.commitkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130226.commitkey.sql'), ), '20131302.maniphestvalue.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20131302.maniphestvalue.sql'), ), '20130304.lintauthor.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('20130304.lintauthor.sql'), ), + 'releeph.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('releeph.sql'), + ), ); } } diff --git a/webroot/rsrc/css/application/releeph/releeph-branch.css b/webroot/rsrc/css/application/releeph/releeph-branch.css new file mode 100644 index 000000000..2bc7c83a7 --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-branch.css @@ -0,0 +1,79 @@ +/** + * @provides releeph-branch + */ + +.releeph-branch-box { + margin-bottom: .5em; + padding: .5em .5em .5em; + + border: 2px solid #d5d5d5; + /*border-top-color: #D5D5D5; + border-right-color: #BBB; + border-bottom-color: #A4A4A4; + border-left-color: #BBB;*/ + + background: #bbb; +} + +/* Types of branch */ + +.releeph-branch-box-named { + background: #ddd; +} + +.releeph-branch-box-latest { + background: #ffd; +} + +/* Branch symbolic name and full name */ + +.releeph-branch-box .names { + width: 25em; + float: left; + margin-bottom: 1em; +} + +.releeph-branch-box .names h1 { + font-size: 125%; + padding: 0px; +} + +.releeph-branch-box .names h2 { + font-weight: normal; + font-size: 85%; +} + +/* Date info */ + +.releeph-branch-box .date-info { + width: 10%; + float: left; + color: #555; + margin-bottom: .3em; +} + +/* Statistics table */ + +.releeph-branch-box .request-statistics { + float: right; + padding-right: 2em; + font-size: 85%; +} + +.releeph-branch-box .request-statistics th { + width: 1em; + text-align: right; + padding-right: .4em; + padding-left: .4em; +} + +.releeph-branch-box .request-statistics td { + white-space: nowrap; + font-style: italic; +} + +/* Buttons */ + +.releeph-branch-box .buttons { + float: right; +} diff --git a/webroot/rsrc/css/application/releeph/releeph-colors.css b/webroot/rsrc/css/application/releeph/releeph-colors.css new file mode 100644 index 000000000..481ff7031 --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-colors.css @@ -0,0 +1,35 @@ +/** + * @provides releeph-colors + */ + +.releeph-border-color-failed { + border-color: #d2d; +} + +.releeph-border-color-requested { + border-color: #ddd; +} + +.releeph-border-color-comment { + border-color: #ddd; +} + +.releeph-border-color-needs-pick { + border-color: #096; +} + +.releeph-border-color-rejected { + border-color: #d00; +} + +.releeph-border-color-needs-revert { + border-color: #d00; +} + +.releeph-border-color-abandoned { + border-color: #222; +} + +.releeph-border-color-picked { + border-color: #069; +} diff --git a/webroot/rsrc/css/application/releeph/releeph-core.css b/webroot/rsrc/css/application/releeph/releeph-core.css new file mode 100644 index 000000000..fdeb2810c --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-core.css @@ -0,0 +1,199 @@ +/** + * @provides releeph-core + */ + +.releeph-request-header { + margin: .5em 2em 3em; + + /** + * Copied from the old .differential-panel, present in commit + * f04d8ab1a747dc9719d378d9286088b677ce224c + * + * (As is the <h1> code below) + */ + max-width: 1120px; + border: 1px solid #666622; + background: #efefdf; + padding: 15px 20px; + font-size: 13px; +} + +.releeph-request-header h1 { + width: 100%; + border-bottom: 1px solid #aaaa99; + padding-bottom: 8px; + margin-bottom: 8px; + position: relative; +} + +.releeph-request-header .focus-char { + left: -10px; + display: none; + float: left; + position: absolute; + top: 0px; + left: -1em; + + font-weight: bold; + + color: #880; + font-family: "Hiragino Kaku Gothic Pro", "Osaka", "Zapf Dingbats"; +} + +.releeph-request-header.focus .focus-char { + display: block; +} + +.releeph-request-header-border { + border-width: 1px 10px 1px; + border-color: #ddd; +} + + +/* Laying out properties / fields */ + +.releeph-request-header table.panes { + width: 100%; +} + +.releeph-request-header table.panes td.side { + width: 50%; + max-width: 1em; +} + +.releeph-request-header table.panes td.side.left { + padding-right: 20px; + border-right: 3px solid #bbb; +} + +.releeph-request-header table.panes td.side.right { + padding-left: 20px; +} + +.releeph-request-header table.panes td.side table.fields { + width: 100%; +} + +.releeph-request-header table.panes td.side table.fields tr { + vertical-align: middle; +} + +.releeph-request-header table.panes td.side table.fields th { + font-weight: bold; + text-align: right; + padding-right: 1em; + white-space: nowrap; +} + +.releeph-request-header table.panes td.side table.fields td { + width: 100%; /* wide! */ + max-width: 1em; +} + + +/* Buttons */ + +.releeph-request-header .button-divider { + clear: both; + margin-top: 1.5em; + border-top: 1px solid #bbb; +} + +.releeph-request-header .buttons { + width: 100%; +} + +.releeph-request-header .buttons tr { + padding: 1em; + margin: 3em; +} + +.releeph-request-header .buttons td { + padding: 1em .5em 0.2em; +} + +.releeph-request-header .buttons td.wide { + width: 100%; +} + +/* Colors: match differential colors */ + +.releeph-request-comment { + border-color: #ddd; +} + +.releeph-request-comment-pusher { + background: #8DEE8D; + border-color: #096; +} + +.releeph-request-comment-pusher div { + background: #8DEE8D; +} + +/* The diff size bar */ + +.releeph-request-header .diff-bar { + border: 0px; +} + +.releeph-request-header .diff-bar div { + width: 100px; + border: 1px solid; + border-top-color: #A4A4A4; + border-right-color: #BBB; + border-bottom-color: #D5D5D5; + border-left-color: #BBB; + background: white; + float: left; + margin-right: 1em; +} + +.releeph-request-header .diff-bar div div { + height: 10px; +} + +.releeph-request-header .diff-bar span { + color: #555; +} + +/* Rendering pick / commit errors, etc. */ + +.releeph-request-pick-failed-event h1:before { + content: '\2014 '; +} + +.releeph-request-pick-failed-event h1:after { + content: ' \2014'; +} + +.releeph-request-pick-failed-event h1 { + padding: 3px 10px 3px; + margin-bottom: 0.5em; + background: #ffb; + font-size: small; +} + +.releeph-request-pick-failed-event div { + font-family: monospace; + margin-bottom: 1.5em; + padding-left: 1em; + width: 70em; +} + +/* History view of request */ + +.releeph-request-event-list { + margin: .5em 2em .5em; +} + + +/* Shorten long header-text */ + +.releeph-header-text-truncated { + width: 100%; + float: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/webroot/rsrc/css/application/releeph/releeph-intents.css b/webroot/rsrc/css/application/releeph/releeph-intents.css new file mode 100644 index 000000000..9e7691149 --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-intents.css @@ -0,0 +1,37 @@ +/** + * @provides releeph-intents + */ + +.releeph-intents .intents { + clear: left; + width: 100%; + margin-top: 3px; +} + +.releeph-intents .arrow { + float: left; + clear: left; + margin-right: 0.4em; + padding: 8px; + background: transparent 0 0 no-repeat; +} + +.releeph-intents .arrow.want { + background-image: url('/rsrc/custom/image/icon/tango/go-next.png'); +} + +.releeph-intents .arrow.pass { + background-image: url('/rsrc/custom/image/icon/tango/go-previous-gray.png'); +} + +.releeph-intents a { + margin-right: 0.4em; +} + +.releeph-intents .pusher { + font-weight: bold; +} + +.releeph-intents .requestor { + font-weight: normal; +} diff --git a/webroot/rsrc/css/application/releeph/releeph-preview-branch.css b/webroot/rsrc/css/application/releeph/releeph-preview-branch.css new file mode 100644 index 000000000..2bce6632d --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-preview-branch.css @@ -0,0 +1,29 @@ +/** + * @provides releeph-preview-branch + */ + +.releeph-preview-branch { + min-height: 4em; + position: relative; +} + +.releeph-preview-branch .error { + padding-left: 22px; + background-repeat: no-repeat; + background-size: 16px auto; + background-image: url(/rsrc/custom/image/releeph/releeph_warning.png); + float: left; + position: absolute; + top: 2.5em; +} + +.releeph-preview-branch .name { + clear: both; + float: left; + position: absolute; + font-family: monospace; + font-size: 9pt !important; + background: white; + top: 0.7em; + padding: 2px; +} diff --git a/webroot/rsrc/css/application/releeph/releeph-project.css b/webroot/rsrc/css/application/releeph/releeph-project.css new file mode 100644 index 000000000..3a14751bd --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-project.css @@ -0,0 +1,25 @@ +/** + * @provides releeph-project + */ + +/** + * ...from aphront-transaction.css + */ + +.releeph-pusher { + background: 2px 2px no-repeat; + margin-top: 1em; + margin-bottom: 1.25em; + margin-right: 1em; + min-height: 50px; + padding: 2px 0px; + + background-color: white; + border: 2px solid gray; + float: left; +} + +.releeph-pusher-body { + margin-left: 54px; + padding: 1em; +} diff --git a/webroot/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css b/webroot/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css new file mode 100644 index 000000000..7101f7878 --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css @@ -0,0 +1,17 @@ +/** + * @provides releeph-request-differential-create-dialog + */ + +.releeph-request-differential-create-dialog h1 { + color: gray; + font-style: italic; + font-size: 16px; + margin-top: 0.8em; +} + +.releeph-request-differential-create-dialog a { + font-weight: bold; + margin-left: 2em; + display: block; + margin-top: 1em; +} diff --git a/webroot/rsrc/css/application/releeph/releeph-request-typeahead.css b/webroot/rsrc/css/application/releeph/releeph-request-typeahead.css new file mode 100644 index 000000000..91a81acea --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-request-typeahead.css @@ -0,0 +1,27 @@ +/** + * @provides releeph-request-typeahead-css + */ + +.releeph-request-typeahead .commit-id { + color: #aaf; /* blue... */ + font-family: monospace; + font-size: 100%; + display: block; + float: left; +} + +.releeph-request-typeahead .author-info { + color: #080; /* ...and green, for search results! */ + text-align: right; + display: block; + float: right; + padding-left: 1em; +} + +.releeph-request-typeahead .focused .author-info { + color: #8b8; +} + +.releeph-request-typeahead .summary { + clear: both; +} diff --git a/webroot/rsrc/css/application/releeph/releeph-status.css b/webroot/rsrc/css/application/releeph/releeph-status.css new file mode 100644 index 000000000..f41330e97 --- /dev/null +++ b/webroot/rsrc/css/application/releeph/releeph-status.css @@ -0,0 +1,26 @@ +/** + * @provides releeph-status + */ + +.releeph-status .description { + background: #d3d3d3; + padding: 2px 6px 3px; + margin-right: 4px; + margin-bottom: 5px; + display: block; + float: left; + border-radius: 8px; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + text-decoration: none; +} + +.releeph-status .warning { + margin-top: 2px; + margin-left: 0.8em; + float: left; + padding-left: 22px; + background-repeat: no-repeat; + background-size: 16px auto; + background-image: url(/rsrc/custom/image/releeph/releeph_warning.png); +} diff --git a/webroot/rsrc/js/application/releeph/releeph-preview-branch.js b/webroot/rsrc/js/application/releeph/releeph-preview-branch.js new file mode 100644 index 000000000..76e406bd7 --- /dev/null +++ b/webroot/rsrc/js/application/releeph/releeph-preview-branch.js @@ -0,0 +1,49 @@ +/** + * @provides javelin-behavior-releeph-preview-branch + * @requires javelin-behavior + * javelin-dom + * javelin-stratcom + * javelin-uri + * javelin-util + */ + +JX.behavior('releeph-preview-branch', function(config) { + + var uri = JX.$U(config.uri); + for (param_name in config.params.static) { + var value = config.params.static[param_name]; + uri.setQueryParam(param_name, value); + } + + var output = JX.$(config.outputID); + + var dynamics = config.params.dynamic; + + function renderPreview() { + for (param_name in dynamics) { + var node_id = dynamics[param_name]; + var input = JX.$(node_id); + uri.setQueryParam(param_name, input.value); + } + var request = new JX.Request(uri, function(response) { + JX.DOM.setContent(output, JX.$H(response.markup)); + }); + request.send(); + } + + renderPreview(); + + for (ii in dynamics) { + var node_id = dynamics[ii]; + var input = JX.$(node_id); + JX.DOM.listen( + input, + ['keyup', 'click', 'change'], + null, + function(e) { + renderPreview(); + } + ); + } + +}); diff --git a/webroot/rsrc/js/application/releeph/releeph-request-state-change.js b/webroot/rsrc/js/application/releeph/releeph-request-state-change.js new file mode 100644 index 000000000..286d527b8 --- /dev/null +++ b/webroot/rsrc/js/application/releeph/releeph-request-state-change.js @@ -0,0 +1,145 @@ +/** + * @provides javelin-behavior-releeph-request-state-change + * @requires javelin-behavior + * javelin-dom + * javelin-stratcom + * javelin-util + * phabricator-keyboard-shortcut + * phabricator-notification + */ + +JX.behavior('releeph-request-state-change', function(config) { + var root = JX.DOM.find(document, 'div', 'releeph-request-header-list'); + + function getRequestHeaderNodes() { + return JX.DOM.scry(root, 'div', 'releeph-request-header'); + } + + /** + * Keyboard navigation + */ + var keynav_cursor = -1; + var notification = new JX.Notification(); + + function keynavJump(manager, delta) { + // Calculate this everytime, because the DOM changes. + var headers = getRequestHeaderNodes(); + keynav_cursor += delta; + + if (keynav_cursor < 0) { + keynav_cursor = -1; + window.scrollTo(0); + keynavMarkup(); + return; + } + + if (keynav_cursor >= headers.length) { + keynav_cursor = headers.length - 1; + } + + var focus = headers[keynav_cursor]; + manager.scrollTo(focus); + + keynavMarkup(); + } + + function keynavMarkup() { + var headers = getRequestHeaderNodes(); + for (ii in headers) { + JX.DOM.alterClass(headers[ii], 'focus', ii == keynav_cursor); + } + } + + function keynavAction(manager, action_name) { + var headers = getRequestHeaderNodes(); + var header = headers[keynav_cursor]; + + if (keynav_cursor < 0) { + return; + } + + var sigil = action_name; + var button = JX.DOM.find(header, 'a', sigil); + if (button) { + button.click(); + } + } + + function keynavNavigateToRequestPage() { + var headers = getRequestHeaderNodes(); + var header = headers[keynav_cursor]; + JX.DOM.find(header, 'a', 'hidden-link').click(); + } + + new JX.KeyboardShortcut('j', 'Jump to next request.') + .setHandler(function(manager) { + keynavJump(manager, +1); + }) + .register(); + + new JX.KeyboardShortcut('k', 'Jump to previous request.') + .setHandler(function(manager) { + keynavJump(manager, -1); + }) + .register(); + + new JX.KeyboardShortcut('a', 'Approve the selected request.') + .setHandler(function(manager) { + keynavAction(manager, 'want'); + }) + .register(); + + new JX.KeyboardShortcut('r', 'Reject the selected request.') + .setHandler(function(manager) { + keynavAction(manager, 'pass'); + }) + .register(); + + new JX.KeyboardShortcut('g', "Open selected request's page in a new tab.") + .setHandler(function(manager) { + keynavNavigateToRequestPage(); + }) + .register(); + + + /** + * AJAXy state changes for request buttons. + */ + function request_action(node, url) { + var request = new JX.Request(url, function(response) { + if (config.reload) { + window.location.reload(); + } else { + var markup = JX.$H(response.markup); + JX.DOM.replace(node, markup); + keynavMarkup(); + } + }); + + request.send(); + } + + JX.Stratcom.listen( + 'click', + 'releeph-request-state-change', + function(e) { + var button = e.getNode('releeph-request-state-change'); + var node = e.getNode('releeph-request-header'); + var url = e.getNodeData('releeph-request-state-change'); + + // If this button has no action, or we've already responded to the first + // click... + if (!url || button.disabled) { + return; + } + + // There's a race condition here though :( + + JX.DOM.alterClass(button, 'disabled', true); + button.disabled = true; + + e.prevent(); + request_action(node, url); + } + ); +}); diff --git a/webroot/rsrc/js/application/releeph/releeph-request-typeahead.js b/webroot/rsrc/js/application/releeph/releeph-request-typeahead.js new file mode 100644 index 000000000..fd932dd73 --- /dev/null +++ b/webroot/rsrc/js/application/releeph/releeph-request-typeahead.js @@ -0,0 +1,84 @@ +/** + * @provides javelin-behavior-releeph-request-typeahead + * @requires javelin-behavior + * javelin-util + * javelin-dom + * javelin-typeahead + * javelin-tokenizer + * javelin-typeahead-preloaded-source + * javelin-typeahead-ondemand-source + * javelin-dom + * javelin-stratcom + * javelin-util + */ + +JX.behavior('releeph-request-typeahead', function(config) { + var root = JX.$(config.id); + var datasource = new JX.TypeaheadOnDemandSource(config.src); + var callsign = config.aux.callsign; + + datasource.setAuxiliaryData(config.aux); + + datasource.setTransformer( + function(object) { + var full_commit_id = object[0]; + var short_commit_id = object[1]; + var author = object[2]; + var ago = object[3]; + var summary = object[4]; + + var callsign_commit_id = 'r' + callsign + short_commit_id; + + var box = + JX.$N( + 'div', + {}, + [ + JX.$N( + 'div', + { className: 'commit-id' }, + callsign_commit_id + ), + JX.$N( + 'div', + { className: 'author-info' }, + ago + ' ago by ' + author + ), + JX.$N( + 'div', + { className: 'summary' }, + summary + ), + ] + ); + + return { + name: callsign_commit_id, + tokenizable: callsign_commit_id + ' '+ short_commit_id + ' ' + summary, + display: box, + uri: null, + id: full_commit_id + }; + }); + + /** + * The default normalizer removes useful control characters that would help + * out search. For example, I was just trying to search for a commit with + * the string "a_file" in the message, which was normalized to "afile". + */ + datasource.setNormalizer(function(query) { + return query; + }); + + datasource.setMaximumResultCount(config.aux.limit); + + var typeahead = new JX.Typeahead(root); + typeahead.setDatasource(datasource); + + var placeholder = config.value || config.placeholder; + if (placeholder) { + typeahead.setPlaceholder(placeholder); + } + + typeahead.start(); +});