Page MenuHomePhorge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 57cef3ab..d29a1fe5 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,2020 +1,2023 @@
<?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(
'AASTNode' => 'parser/aast/api/AASTNode.php',
'AASTNodeList' => 'parser/aast/api/AASTNodeList.php',
'AASTToken' => 'parser/aast/api/AASTToken.php',
'AASTTree' => 'parser/aast/api/AASTTree.php',
'AbstractDirectedGraph' => 'utils/AbstractDirectedGraph.php',
'AbstractDirectedGraphTestCase' => 'utils/__tests__/AbstractDirectedGraphTestCase.php',
'ArcanistAbstractMethodBodyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistAbstractMethodBodyXHPASTLinterRule.php',
'ArcanistAbstractMethodBodyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistAbstractMethodBodyXHPASTLinterRuleTestCase.php',
'ArcanistAbstractPrivateMethodXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistAbstractPrivateMethodXHPASTLinterRule.php',
'ArcanistAbstractPrivateMethodXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistAbstractPrivateMethodXHPASTLinterRuleTestCase.php',
'ArcanistAlias' => 'toolset/ArcanistAlias.php',
'ArcanistAliasEffect' => 'toolset/ArcanistAliasEffect.php',
'ArcanistAliasEngine' => 'toolset/ArcanistAliasEngine.php',
'ArcanistAliasFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistAliasFunctionXHPASTLinterRule.php',
'ArcanistAliasFunctionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistAliasFunctionXHPASTLinterRuleTestCase.php',
'ArcanistAliasWorkflow' => 'toolset/workflow/ArcanistAliasWorkflow.php',
'ArcanistAliasesConfigOption' => 'config/option/ArcanistAliasesConfigOption.php',
'ArcanistAmendWorkflow' => 'workflow/ArcanistAmendWorkflow.php',
'ArcanistAnoidWorkflow' => 'workflow/ArcanistAnoidWorkflow.php',
'ArcanistArcConfigurationEngineExtension' => 'config/arc/ArcanistArcConfigurationEngineExtension.php',
'ArcanistArcToolset' => 'toolset/ArcanistArcToolset.php',
'ArcanistArcWorkflow' => 'toolset/workflow/ArcanistArcWorkflow.php',
'ArcanistArrayCombineXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArrayCombineXHPASTLinterRule.php',
'ArcanistArrayCombineXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistArrayCombineXHPASTLinterRuleTestCase.php',
'ArcanistArrayIndexSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArrayIndexSpacingXHPASTLinterRule.php',
'ArcanistArrayIndexSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistArrayIndexSpacingXHPASTLinterRuleTestCase.php',
'ArcanistArraySeparatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArraySeparatorXHPASTLinterRule.php',
'ArcanistArraySeparatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistArraySeparatorXHPASTLinterRuleTestCase.php',
'ArcanistArrayValueXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArrayValueXHPASTLinterRule.php',
'ArcanistArrayValueXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistArrayValueXHPASTLinterRuleTestCase.php',
'ArcanistBaseCommitParser' => 'parser/ArcanistBaseCommitParser.php',
'ArcanistBaseCommitParserTestCase' => 'parser/__tests__/ArcanistBaseCommitParserTestCase.php',
'ArcanistBaseXHPASTLinter' => 'lint/linter/ArcanistBaseXHPASTLinter.php',
'ArcanistBinaryExpressionSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBinaryExpressionSpacingXHPASTLinterRule.php',
'ArcanistBinaryExpressionSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBinaryExpressionSpacingXHPASTLinterRuleTestCase.php',
'ArcanistBinaryNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBinaryNumericScalarCasingXHPASTLinterRule.php',
'ArcanistBinaryNumericScalarCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBinaryNumericScalarCasingXHPASTLinterRuleTestCase.php',
'ArcanistBlacklistedFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBlacklistedFunctionXHPASTLinterRule.php',
'ArcanistBlacklistedFunctionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBlacklistedFunctionXHPASTLinterRuleTestCase.php',
'ArcanistBlindlyTrustHTTPEngineExtension' => 'configuration/ArcanistBlindlyTrustHTTPEngineExtension.php',
'ArcanistBookmarksWorkflow' => 'workflow/ArcanistBookmarksWorkflow.php',
'ArcanistBoolConfigOption' => 'config/option/ArcanistBoolConfigOption.php',
'ArcanistBraceFormattingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBraceFormattingXHPASTLinterRule.php',
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBraceFormattingXHPASTLinterRuleTestCase.php',
'ArcanistBranchesWorkflow' => 'workflow/ArcanistBranchesWorkflow.php',
'ArcanistBrowseCommitHardpointQuery' => 'browse/query/ArcanistBrowseCommitHardpointQuery.php',
'ArcanistBrowseCommitURIHardpointQuery' => 'browse/query/ArcanistBrowseCommitURIHardpointQuery.php',
'ArcanistBrowseObjectNameURIHardpointQuery' => 'browse/query/ArcanistBrowseObjectNameURIHardpointQuery.php',
'ArcanistBrowsePathURIHardpointQuery' => 'browse/query/ArcanistBrowsePathURIHardpointQuery.php',
'ArcanistBrowseRef' => 'browse/ref/ArcanistBrowseRef.php',
'ArcanistBrowseRefInspector' => 'inspector/ArcanistBrowseRefInspector.php',
'ArcanistBrowseRevisionURIHardpointQuery' => 'browse/query/ArcanistBrowseRevisionURIHardpointQuery.php',
'ArcanistBrowseURIHardpointQuery' => 'browse/query/ArcanistBrowseURIHardpointQuery.php',
'ArcanistBrowseURIRef' => 'browse/ref/ArcanistBrowseURIRef.php',
'ArcanistBrowseWorkflow' => 'browse/workflow/ArcanistBrowseWorkflow.php',
'ArcanistBuildBuildplanHardpointQuery' => 'ref/build/ArcanistBuildBuildplanHardpointQuery.php',
'ArcanistBuildPlanRef' => 'ref/buildplan/ArcanistBuildPlanRef.php',
'ArcanistBuildPlanSymbolRef' => 'ref/buildplan/ArcanistBuildPlanSymbolRef.php',
'ArcanistBuildRef' => 'ref/build/ArcanistBuildRef.php',
'ArcanistBuildSymbolRef' => 'ref/build/ArcanistBuildSymbolRef.php',
'ArcanistBuildableBuildsHardpointQuery' => 'ref/buildable/ArcanistBuildableBuildsHardpointQuery.php',
'ArcanistBuildableRef' => 'ref/buildable/ArcanistBuildableRef.php',
'ArcanistBuildableSymbolRef' => 'ref/buildable/ArcanistBuildableSymbolRef.php',
'ArcanistBundle' => 'parser/ArcanistBundle.php',
'ArcanistBundleTestCase' => 'parser/__tests__/ArcanistBundleTestCase.php',
'ArcanistCSSLintLinter' => 'lint/linter/ArcanistCSSLintLinter.php',
'ArcanistCSSLintLinterTestCase' => 'lint/linter/__tests__/ArcanistCSSLintLinterTestCase.php',
'ArcanistCSharpLinter' => 'lint/linter/ArcanistCSharpLinter.php',
'ArcanistCallConduitWorkflow' => 'workflow/ArcanistCallConduitWorkflow.php',
'ArcanistCallParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCallParenthesesXHPASTLinterRule.php',
'ArcanistCallParenthesesXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCallParenthesesXHPASTLinterRuleTestCase.php',
'ArcanistCallTimePassByReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCallTimePassByReferenceXHPASTLinterRule.php',
'ArcanistCallTimePassByReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCallTimePassByReferenceXHPASTLinterRuleTestCase.php',
'ArcanistCapabilityNotSupportedException' => 'workflow/exception/ArcanistCapabilityNotSupportedException.php',
'ArcanistCastSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCastSpacingXHPASTLinterRule.php',
'ArcanistCastSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCastSpacingXHPASTLinterRuleTestCase.php',
'ArcanistCheckstyleXMLLintRenderer' => 'lint/renderer/ArcanistCheckstyleXMLLintRenderer.php',
'ArcanistChmodLinter' => 'lint/linter/ArcanistChmodLinter.php',
'ArcanistChmodLinterTestCase' => 'lint/linter/__tests__/ArcanistChmodLinterTestCase.php',
'ArcanistClassExtendsObjectXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistClassExtendsObjectXHPASTLinterRule.php',
'ArcanistClassExtendsObjectXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistClassExtendsObjectXHPASTLinterRuleTestCase.php',
'ArcanistClassFilenameMismatchXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistClassFilenameMismatchXHPASTLinterRule.php',
'ArcanistClassMustBeDeclaredAbstractXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistClassMustBeDeclaredAbstractXHPASTLinterRule.php',
'ArcanistClassMustBeDeclaredAbstractXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistClassMustBeDeclaredAbstractXHPASTLinterRuleTestCase.php',
'ArcanistClassNameLiteralXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistClassNameLiteralXHPASTLinterRule.php',
'ArcanistClassNameLiteralXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistClassNameLiteralXHPASTLinterRuleTestCase.php',
'ArcanistCloseRevisionWorkflow' => 'workflow/ArcanistCloseRevisionWorkflow.php',
'ArcanistClosureLinter' => 'lint/linter/ArcanistClosureLinter.php',
'ArcanistClosureLinterTestCase' => 'lint/linter/__tests__/ArcanistClosureLinterTestCase.php',
'ArcanistCoffeeLintLinter' => 'lint/linter/ArcanistCoffeeLintLinter.php',
'ArcanistCoffeeLintLinterTestCase' => 'lint/linter/__tests__/ArcanistCoffeeLintLinterTestCase.php',
'ArcanistCommand' => 'toolset/command/ArcanistCommand.php',
'ArcanistCommentRemover' => 'parser/ArcanistCommentRemover.php',
'ArcanistCommentRemoverTestCase' => 'parser/__tests__/ArcanistCommentRemoverTestCase.php',
'ArcanistCommentSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php',
'ArcanistCommentStyleXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php',
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCommentStyleXHPASTLinterRuleTestCase.php',
'ArcanistCommitGraph' => 'repository/graph/ArcanistCommitGraph.php',
'ArcanistCommitGraphPartition' => 'repository/graph/ArcanistCommitGraphPartition.php',
'ArcanistCommitGraphPartitionQuery' => 'repository/graph/ArcanistCommitGraphPartitionQuery.php',
'ArcanistCommitGraphQuery' => 'repository/graph/query/ArcanistCommitGraphQuery.php',
'ArcanistCommitGraphSet' => 'repository/graph/ArcanistCommitGraphSet.php',
'ArcanistCommitGraphSetQuery' => 'repository/graph/ArcanistCommitGraphSetQuery.php',
'ArcanistCommitGraphSetTreeView' => 'repository/graph/view/ArcanistCommitGraphSetTreeView.php',
'ArcanistCommitGraphSetView' => 'repository/graph/view/ArcanistCommitGraphSetView.php',
'ArcanistCommitGraphTestCase' => 'repository/graph/__tests__/ArcanistCommitGraphTestCase.php',
'ArcanistCommitNode' => 'repository/graph/ArcanistCommitNode.php',
'ArcanistCommitRef' => 'ref/commit/ArcanistCommitRef.php',
'ArcanistCommitSymbolRef' => 'ref/commit/ArcanistCommitSymbolRef.php',
'ArcanistCommitSymbolRefInspector' => 'ref/commit/ArcanistCommitSymbolRefInspector.php',
'ArcanistCommitUpstreamHardpointQuery' => 'query/ArcanistCommitUpstreamHardpointQuery.php',
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
'ArcanistComposerLinter' => 'lint/linter/ArcanistComposerLinter.php',
'ArcanistComprehensiveLintEngine' => 'lint/engine/ArcanistComprehensiveLintEngine.php',
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistConcatenationOperatorXHPASTLinterRule.php',
'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistConcatenationOperatorXHPASTLinterRuleTestCase.php',
'ArcanistConduitAuthenticationException' => 'exception/ArcanistConduitAuthenticationException.php',
'ArcanistConduitCallFuture' => 'conduit/ArcanistConduitCallFuture.php',
'ArcanistConduitEngine' => 'conduit/ArcanistConduitEngine.php',
'ArcanistConduitException' => 'conduit/ArcanistConduitException.php',
'ArcanistConfigOption' => 'config/option/ArcanistConfigOption.php',
'ArcanistConfiguration' => 'configuration/ArcanistConfiguration.php',
'ArcanistConfigurationDrivenLintEngine' => 'lint/engine/ArcanistConfigurationDrivenLintEngine.php',
'ArcanistConfigurationDrivenUnitTestEngine' => 'unit/engine/ArcanistConfigurationDrivenUnitTestEngine.php',
'ArcanistConfigurationEngine' => 'config/ArcanistConfigurationEngine.php',
'ArcanistConfigurationEngineExtension' => 'config/ArcanistConfigurationEngineExtension.php',
'ArcanistConfigurationManager' => 'configuration/ArcanistConfigurationManager.php',
'ArcanistConfigurationSource' => 'config/source/ArcanistConfigurationSource.php',
'ArcanistConfigurationSourceList' => 'config/ArcanistConfigurationSourceList.php',
'ArcanistConfigurationSourceValue' => 'config/ArcanistConfigurationSourceValue.php',
'ArcanistConsoleLintRenderer' => 'lint/renderer/ArcanistConsoleLintRenderer.php',
'ArcanistConsoleLintRendererTestCase' => 'lint/renderer/__tests__/ArcanistConsoleLintRendererTestCase.php',
'ArcanistConstructorParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistConstructorParenthesesXHPASTLinterRule.php',
'ArcanistConstructorParenthesesXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistConstructorParenthesesXHPASTLinterRuleTestCase.php',
'ArcanistContinueInsideSwitchXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistContinueInsideSwitchXHPASTLinterRule.php',
'ArcanistContinueInsideSwitchXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistContinueInsideSwitchXHPASTLinterRuleTestCase.php',
'ArcanistControlStatementSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistControlStatementSpacingXHPASTLinterRule.php',
'ArcanistControlStatementSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistControlStatementSpacingXHPASTLinterRuleTestCase.php',
'ArcanistCoverWorkflow' => 'workflow/ArcanistCoverWorkflow.php',
'ArcanistCppcheckLinter' => 'lint/linter/ArcanistCppcheckLinter.php',
'ArcanistCppcheckLinterTestCase' => 'lint/linter/__tests__/ArcanistCppcheckLinterTestCase.php',
'ArcanistCpplintLinter' => 'lint/linter/ArcanistCpplintLinter.php',
'ArcanistCpplintLinterTestCase' => 'lint/linter/__tests__/ArcanistCpplintLinterTestCase.php',
'ArcanistCurlyBraceArrayIndexXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCurlyBraceArrayIndexXHPASTLinterRule.php',
'ArcanistCurlyBraceArrayIndexXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCurlyBraceArrayIndexXHPASTLinterRuleTestCase.php',
'ArcanistDeclarationParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDeclarationParenthesesXHPASTLinterRule.php',
'ArcanistDeclarationParenthesesXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDeclarationParenthesesXHPASTLinterRuleTestCase.php',
'ArcanistDefaultParametersXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDefaultParametersXHPASTLinterRule.php',
'ArcanistDefaultParametersXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDefaultParametersXHPASTLinterRuleTestCase.php',
'ArcanistDefaultsConfigurationSource' => 'config/source/ArcanistDefaultsConfigurationSource.php',
'ArcanistDeprecationXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDeprecationXHPASTLinterRule.php',
'ArcanistDeprecationXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDeprecationXHPASTLinterRuleTestCase.php',
'ArcanistDictionaryConfigurationSource' => 'config/source/ArcanistDictionaryConfigurationSource.php',
'ArcanistDiffByteSizeException' => 'exception/ArcanistDiffByteSizeException.php',
'ArcanistDiffChange' => 'parser/diff/ArcanistDiffChange.php',
'ArcanistDiffChangeType' => 'parser/diff/ArcanistDiffChangeType.php',
'ArcanistDiffHunk' => 'parser/diff/ArcanistDiffHunk.php',
'ArcanistDiffParser' => 'parser/ArcanistDiffParser.php',
'ArcanistDiffParserTestCase' => 'parser/__tests__/ArcanistDiffParserTestCase.php',
'ArcanistDiffUtils' => 'difference/ArcanistDiffUtils.php',
'ArcanistDiffUtilsTestCase' => 'difference/__tests__/ArcanistDiffUtilsTestCase.php',
'ArcanistDiffVectorNode' => 'difference/ArcanistDiffVectorNode.php',
'ArcanistDiffVectorTree' => 'difference/ArcanistDiffVectorTree.php',
'ArcanistDiffWorkflow' => 'workflow/ArcanistDiffWorkflow.php',
'ArcanistDifferentialCommitMessage' => 'differential/ArcanistDifferentialCommitMessage.php',
'ArcanistDifferentialCommitMessageParserException' => 'differential/ArcanistDifferentialCommitMessageParserException.php',
'ArcanistDifferentialDependencyGraph' => 'differential/ArcanistDifferentialDependencyGraph.php',
'ArcanistDifferentialRevisionHash' => 'differential/constants/ArcanistDifferentialRevisionHash.php',
'ArcanistDifferentialRevisionStatus' => 'differential/constants/ArcanistDifferentialRevisionStatus.php',
'ArcanistDoubleQuoteXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDoubleQuoteXHPASTLinterRule.php',
'ArcanistDoubleQuoteXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDoubleQuoteXHPASTLinterRuleTestCase.php',
'ArcanistDownloadWorkflow' => 'workflow/ArcanistDownloadWorkflow.php',
'ArcanistDuplicateKeysInArrayXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDuplicateKeysInArrayXHPASTLinterRule.php',
'ArcanistDuplicateKeysInArrayXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDuplicateKeysInArrayXHPASTLinterRuleTestCase.php',
'ArcanistDuplicateSwitchCaseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDuplicateSwitchCaseXHPASTLinterRule.php',
'ArcanistDuplicateSwitchCaseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDuplicateSwitchCaseXHPASTLinterRuleTestCase.php',
'ArcanistDynamicDefineXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDynamicDefineXHPASTLinterRule.php',
'ArcanistDynamicDefineXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDynamicDefineXHPASTLinterRuleTestCase.php',
'ArcanistEachUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistEachUseXHPASTLinterRule.php',
'ArcanistEachUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistEachUseXHPASTLinterRuleTestCase.php',
'ArcanistElseIfUsageXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistElseIfUsageXHPASTLinterRule.php',
'ArcanistElseIfUsageXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistElseIfUsageXHPASTLinterRuleTestCase.php',
'ArcanistEmptyFileXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistEmptyFileXHPASTLinterRule.php',
'ArcanistEmptyStatementXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistEmptyStatementXHPASTLinterRule.php',
'ArcanistEmptyStatementXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistEmptyStatementXHPASTLinterRuleTestCase.php',
'ArcanistEventType' => 'events/constant/ArcanistEventType.php',
'ArcanistExitExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistExitExpressionXHPASTLinterRule.php',
'ArcanistExitExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistExitExpressionXHPASTLinterRuleTestCase.php',
'ArcanistExportWorkflow' => 'workflow/ArcanistExportWorkflow.php',
'ArcanistExternalLinter' => 'lint/linter/ArcanistExternalLinter.php',
'ArcanistExternalLinterTestCase' => 'lint/linter/__tests__/ArcanistExternalLinterTestCase.php',
'ArcanistExtractUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistExtractUseXHPASTLinterRule.php',
'ArcanistExtractUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistExtractUseXHPASTLinterRuleTestCase.php',
'ArcanistFileConfigurationSource' => 'config/source/ArcanistFileConfigurationSource.php',
'ArcanistFileDataRef' => 'upload/ArcanistFileDataRef.php',
'ArcanistFileRef' => 'ref/file/ArcanistFileRef.php',
'ArcanistFileSymbolRef' => 'ref/file/ArcanistFileSymbolRef.php',
'ArcanistFileUploader' => 'upload/ArcanistFileUploader.php',
'ArcanistFilenameLinter' => 'lint/linter/ArcanistFilenameLinter.php',
'ArcanistFilenameLinterTestCase' => 'lint/linter/__tests__/ArcanistFilenameLinterTestCase.php',
'ArcanistFilesystemAPI' => 'repository/api/ArcanistFilesystemAPI.php',
'ArcanistFilesystemConfigurationSource' => 'config/source/ArcanistFilesystemConfigurationSource.php',
'ArcanistFilesystemWorkingCopy' => 'workingcopy/ArcanistFilesystemWorkingCopy.php',
'ArcanistFlake8Linter' => 'lint/linter/ArcanistFlake8Linter.php',
'ArcanistFlake8LinterTestCase' => 'lint/linter/__tests__/ArcanistFlake8LinterTestCase.php',
'ArcanistFormattedStringXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php',
'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistFormattedStringXHPASTLinterRuleTestCase.php',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule.php',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase.php',
'ArcanistFutureLinter' => 'lint/linter/ArcanistFutureLinter.php',
'ArcanistGeneratedLinter' => 'lint/linter/ArcanistGeneratedLinter.php',
'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php',
'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php',
'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php',
'ArcanistGitCommitGraphQuery' => 'repository/graph/query/ArcanistGitCommitGraphQuery.php',
'ArcanistGitCommitMessageHardpointQuery' => 'query/ArcanistGitCommitMessageHardpointQuery.php',
'ArcanistGitCommitSymbolCommitHardpointQuery' => 'ref/commit/ArcanistGitCommitSymbolCommitHardpointQuery.php',
'ArcanistGitLandEngine' => 'land/engine/ArcanistGitLandEngine.php',
'ArcanistGitLocalState' => 'repository/state/ArcanistGitLocalState.php',
'ArcanistGitRawCommit' => 'repository/raw/ArcanistGitRawCommit.php',
'ArcanistGitRawCommitTestCase' => 'repository/raw/__tests__/ArcanistGitRawCommitTestCase.php',
'ArcanistGitRepositoryMarkerQuery' => 'repository/marker/ArcanistGitRepositoryMarkerQuery.php',
'ArcanistGitRepositoryRemoteQuery' => 'repository/remote/ArcanistGitRepositoryRemoteQuery.php',
'ArcanistGitUpstreamPath' => 'repository/api/ArcanistGitUpstreamPath.php',
'ArcanistGitWorkEngine' => 'work/ArcanistGitWorkEngine.php',
'ArcanistGitWorkingCopy' => 'workingcopy/ArcanistGitWorkingCopy.php',
'ArcanistGitWorkingCopyRevisionHardpointQuery' => 'query/ArcanistGitWorkingCopyRevisionHardpointQuery.php',
'ArcanistGlobalVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistGlobalVariableXHPASTLinterRule.php',
'ArcanistGlobalVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistGlobalVariableXHPASTLinterRuleTestCase.php',
'ArcanistGoLintLinter' => 'lint/linter/ArcanistGoLintLinter.php',
'ArcanistGoLintLinterTestCase' => 'lint/linter/__tests__/ArcanistGoLintLinterTestCase.php',
'ArcanistGoTestResultParser' => 'unit/parser/ArcanistGoTestResultParser.php',
'ArcanistGoTestResultParserTestCase' => 'unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php',
'ArcanistGridCell' => 'console/grid/ArcanistGridCell.php',
'ArcanistGridColumn' => 'console/grid/ArcanistGridColumn.php',
'ArcanistGridRow' => 'console/grid/ArcanistGridRow.php',
'ArcanistGridView' => 'console/grid/ArcanistGridView.php',
'ArcanistHLintLinter' => 'lint/linter/ArcanistHLintLinter.php',
'ArcanistHLintLinterTestCase' => 'lint/linter/__tests__/ArcanistHLintLinterTestCase.php',
'ArcanistHardpoint' => 'hardpoint/ArcanistHardpoint.php',
'ArcanistHardpointEngine' => 'hardpoint/ArcanistHardpointEngine.php',
'ArcanistHardpointFutureList' => 'hardpoint/ArcanistHardpointFutureList.php',
'ArcanistHardpointList' => 'hardpoint/ArcanistHardpointList.php',
'ArcanistHardpointObject' => 'hardpoint/ArcanistHardpointObject.php',
'ArcanistHardpointQuery' => 'hardpoint/ArcanistHardpointQuery.php',
'ArcanistHardpointRequest' => 'hardpoint/ArcanistHardpointRequest.php',
'ArcanistHardpointRequestList' => 'hardpoint/ArcanistHardpointRequestList.php',
'ArcanistHardpointTask' => 'hardpoint/ArcanistHardpointTask.php',
'ArcanistHardpointTaskResult' => 'hardpoint/ArcanistHardpointTaskResult.php',
'ArcanistHelpWorkflow' => 'toolset/workflow/ArcanistHelpWorkflow.php',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php',
'ArcanistHgClientChannel' => 'hgdaemon/ArcanistHgClientChannel.php',
'ArcanistHgProxyClient' => 'hgdaemon/ArcanistHgProxyClient.php',
'ArcanistHgProxyServer' => 'hgdaemon/ArcanistHgProxyServer.php',
'ArcanistHgServerChannel' => 'hgdaemon/ArcanistHgServerChannel.php',
'ArcanistHostMemorySnapshot' => 'filesystem/memory/ArcanistHostMemorySnapshot.php',
'ArcanistHostMemorySnapshotTestCase' => 'filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php',
'ArcanistImplicitConstructorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitConstructorXHPASTLinterRule.php',
'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitConstructorXHPASTLinterRuleTestCase.php',
'ArcanistImplicitFallthroughXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitFallthroughXHPASTLinterRule.php',
'ArcanistImplicitFallthroughXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitFallthroughXHPASTLinterRuleTestCase.php',
'ArcanistImplicitVisibilityXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitVisibilityXHPASTLinterRule.php',
'ArcanistImplicitVisibilityXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitVisibilityXHPASTLinterRuleTestCase.php',
'ArcanistImplodeArgumentOrderXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplodeArgumentOrderXHPASTLinterRule.php',
'ArcanistImplodeArgumentOrderXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplodeArgumentOrderXHPASTLinterRuleTestCase.php',
'ArcanistInlineHTMLXHPASTLinterRule' => 'lint/linter/ArcanistInlineHTMLXHPASTLinterRule.php',
'ArcanistInlineHTMLXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInlineHTMLXHPASTLinterRuleTestCase.php',
'ArcanistInnerFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInnerFunctionXHPASTLinterRule.php',
'ArcanistInnerFunctionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInnerFunctionXHPASTLinterRuleTestCase.php',
'ArcanistInspectWorkflow' => 'workflow/ArcanistInspectWorkflow.php',
'ArcanistInstallCertificateWorkflow' => 'workflow/ArcanistInstallCertificateWorkflow.php',
'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInstanceOfOperatorXHPASTLinterRule.php',
'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInstanceofOperatorXHPASTLinterRuleTestCase.php',
'ArcanistInterfaceAbstractMethodXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInterfaceAbstractMethodXHPASTLinterRule.php',
'ArcanistInterfaceAbstractMethodXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInterfaceAbstractMethodXHPASTLinterRuleTestCase.php',
'ArcanistInterfaceMethodBodyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInterfaceMethodBodyXHPASTLinterRule.php',
'ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase.php',
'ArcanistInvalidDefaultParameterXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInvalidDefaultParameterXHPASTLinterRule.php',
'ArcanistInvalidDefaultParameterXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInvalidDefaultParameterXHPASTLinterRuleTestCase.php',
'ArcanistInvalidModifiersXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInvalidModifiersXHPASTLinterRule.php',
'ArcanistInvalidModifiersXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInvalidModifiersXHPASTLinterRuleTestCase.php',
'ArcanistInvalidOctalNumericScalarXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInvalidOctalNumericScalarXHPASTLinterRule.php',
'ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase.php',
'ArcanistIsAShouldBeInstanceOfXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistIsAShouldBeInstanceOfXHPASTLinterRule.php',
'ArcanistIsAShouldBeInstanceOfXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistIsAShouldBeInstanceOfXHPASTLinterRuleTestCase.php',
'ArcanistJSHintLinter' => 'lint/linter/ArcanistJSHintLinter.php',
'ArcanistJSHintLinterTestCase' => 'lint/linter/__tests__/ArcanistJSHintLinterTestCase.php',
'ArcanistJSONLintLinter' => 'lint/linter/ArcanistJSONLintLinter.php',
'ArcanistJSONLintRenderer' => 'lint/renderer/ArcanistJSONLintRenderer.php',
'ArcanistJSONLinter' => 'lint/linter/ArcanistJSONLinter.php',
'ArcanistJSONLinterTestCase' => 'lint/linter/__tests__/ArcanistJSONLinterTestCase.php',
'ArcanistJscsLinter' => 'lint/linter/ArcanistJscsLinter.php',
'ArcanistJscsLinterTestCase' => 'lint/linter/__tests__/ArcanistJscsLinterTestCase.php',
'ArcanistKeywordCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistKeywordCasingXHPASTLinterRule.php',
'ArcanistKeywordCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistKeywordCasingXHPASTLinterRuleTestCase.php',
'ArcanistLambdaFuncFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistLambdaFuncFunctionXHPASTLinterRule.php',
'ArcanistLambdaFuncFunctionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistLambdaFuncFunctionXHPASTLinterRuleTestCase.php',
'ArcanistLandCommit' => 'land/ArcanistLandCommit.php',
'ArcanistLandCommitSet' => 'land/ArcanistLandCommitSet.php',
'ArcanistLandEngine' => 'land/engine/ArcanistLandEngine.php',
'ArcanistLandPushFailureException' => 'land/exception/ArcanistLandPushFailureException.php',
'ArcanistLandSymbol' => 'land/ArcanistLandSymbol.php',
'ArcanistLandTarget' => 'land/ArcanistLandTarget.php',
'ArcanistLandWorkflow' => 'workflow/ArcanistLandWorkflow.php',
'ArcanistLanguageConstructParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistLanguageConstructParenthesesXHPASTLinterRule.php',
'ArcanistLanguageConstructParenthesesXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistLanguageConstructParenthesesXHPASTLinterRuleTestCase.php',
'ArcanistLesscLinter' => 'lint/linter/ArcanistLesscLinter.php',
'ArcanistLesscLinterTestCase' => 'lint/linter/__tests__/ArcanistLesscLinterTestCase.php',
'ArcanistLiberateWorkflow' => 'workflow/ArcanistLiberateWorkflow.php',
'ArcanistLintEngine' => 'lint/engine/ArcanistLintEngine.php',
'ArcanistLintMessage' => 'lint/ArcanistLintMessage.php',
'ArcanistLintMessageTestCase' => 'lint/__tests__/ArcanistLintMessageTestCase.php',
'ArcanistLintPatcher' => 'lint/ArcanistLintPatcher.php',
'ArcanistLintRenderer' => 'lint/renderer/ArcanistLintRenderer.php',
'ArcanistLintResult' => 'lint/ArcanistLintResult.php',
'ArcanistLintSeverity' => 'lint/ArcanistLintSeverity.php',
'ArcanistLintWorkflow' => 'workflow/ArcanistLintWorkflow.php',
'ArcanistLinter' => 'lint/linter/ArcanistLinter.php',
'ArcanistLinterStandard' => 'lint/linter/standards/ArcanistLinterStandard.php',
'ArcanistLinterStandardTestCase' => 'lint/linter/standards/__tests__/ArcanistLinterStandardTestCase.php',
'ArcanistLinterTestCase' => 'lint/linter/__tests__/ArcanistLinterTestCase.php',
'ArcanistLintersWorkflow' => 'workflow/ArcanistLintersWorkflow.php',
'ArcanistListAssignmentXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistListAssignmentXHPASTLinterRule.php',
'ArcanistListAssignmentXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistListAssignmentXHPASTLinterRuleTestCase.php',
'ArcanistListConfigOption' => 'config/option/ArcanistListConfigOption.php',
'ArcanistListWorkflow' => 'workflow/ArcanistListWorkflow.php',
'ArcanistLocalConfigurationSource' => 'config/source/ArcanistLocalConfigurationSource.php',
'ArcanistLogEngine' => 'log/ArcanistLogEngine.php',
'ArcanistLogMessage' => 'log/ArcanistLogMessage.php',
'ArcanistLogicalOperatorsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistLogicalOperatorsXHPASTLinterRule.php',
'ArcanistLogicalOperatorsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistLogicalOperatorsXHPASTLinterRuleTestCase.php',
'ArcanistLookWorkflow' => 'workflow/ArcanistLookWorkflow.php',
'ArcanistLowercaseFunctionsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistLowercaseFunctionsXHPASTLinterRule.php',
'ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase.php',
'ArcanistMarkerRef' => 'repository/marker/ArcanistMarkerRef.php',
'ArcanistMarkersWorkflow' => 'workflow/ArcanistMarkersWorkflow.php',
'ArcanistMercurialAPI' => 'repository/api/ArcanistMercurialAPI.php',
'ArcanistMercurialCommitGraphQuery' => 'repository/graph/query/ArcanistMercurialCommitGraphQuery.php',
'ArcanistMercurialCommitMessageHardpointQuery' => 'query/ArcanistMercurialCommitMessageHardpointQuery.php',
'ArcanistMercurialCommitSymbolCommitHardpointQuery' => 'ref/commit/ArcanistMercurialCommitSymbolCommitHardpointQuery.php',
'ArcanistMercurialLandEngine' => 'land/engine/ArcanistMercurialLandEngine.php',
'ArcanistMercurialLocalState' => 'repository/state/ArcanistMercurialLocalState.php',
'ArcanistMercurialParser' => 'repository/parser/ArcanistMercurialParser.php',
'ArcanistMercurialParserTestCase' => 'repository/parser/__tests__/ArcanistMercurialParserTestCase.php',
'ArcanistMercurialRepositoryMarkerQuery' => 'repository/marker/ArcanistMercurialRepositoryMarkerQuery.php',
'ArcanistMercurialRepositoryRemoteQuery' => 'repository/remote/ArcanistMercurialRepositoryRemoteQuery.php',
'ArcanistMercurialWorkEngine' => 'work/ArcanistMercurialWorkEngine.php',
'ArcanistMercurialWorkingCopy' => 'workingcopy/ArcanistMercurialWorkingCopy.php',
'ArcanistMercurialWorkingCopyRevisionHardpointQuery' => 'query/ArcanistMercurialWorkingCopyRevisionHardpointQuery.php',
'ArcanistMergeConflictLinter' => 'lint/linter/ArcanistMergeConflictLinter.php',
'ArcanistMergeConflictLinterTestCase' => 'lint/linter/__tests__/ArcanistMergeConflictLinterTestCase.php',
'ArcanistMessageRevisionHardpointQuery' => 'query/ArcanistMessageRevisionHardpointQuery.php',
'ArcanistMissingArgumentTerminatorException' => 'exception/ArcanistMissingArgumentTerminatorException.php',
'ArcanistMissingLinterException' => 'lint/linter/exception/ArcanistMissingLinterException.php',
'ArcanistModifierOrderingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistModifierOrderingXHPASTLinterRule.php',
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistModifierOrderingXHPASTLinterRuleTestCase.php',
'ArcanistMultiSourceConfigOption' => 'config/option/ArcanistMultiSourceConfigOption.php',
'ArcanistNamespaceFirstStatementXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNamespaceFirstStatementXHPASTLinterRule.php',
'ArcanistNamespaceFirstStatementXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNamespaceFirstStatementXHPASTLinterRuleTestCase.php',
'ArcanistNamingConventionsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNamingConventionsXHPASTLinterRule.php',
'ArcanistNamingConventionsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNamingConventionsXHPASTLinterRuleTestCase.php',
'ArcanistNestedNamespacesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNestedNamespacesXHPASTLinterRule.php',
'ArcanistNestedNamespacesXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNestedNamespacesXHPASTLinterRuleTestCase.php',
'ArcanistNewlineAfterOpenTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNewlineAfterOpenTagXHPASTLinterRule.php',
'ArcanistNewlineAfterOpenTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNewlineAfterOpenTagXHPASTLinterRuleTestCase.php',
'ArcanistNoEffectException' => 'exception/usage/ArcanistNoEffectException.php',
'ArcanistNoEngineException' => 'exception/usage/ArcanistNoEngineException.php',
'ArcanistNoLintLinter' => 'lint/linter/ArcanistNoLintLinter.php',
'ArcanistNoLintLinterTestCase' => 'lint/linter/__tests__/ArcanistNoLintLinterTestCase.php',
'ArcanistNoParentScopeXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNoParentScopeXHPASTLinterRule.php',
'ArcanistNoParentScopeXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNoParentScopeXHPASTLinterRuleTestCase.php',
'ArcanistNoURIConduitException' => 'conduit/ArcanistNoURIConduitException.php',
'ArcanistNonblockingGuard' => 'utils/ArcanistNonblockingGuard.php',
'ArcanistNoneLintRenderer' => 'lint/renderer/ArcanistNoneLintRenderer.php',
'ArcanistObjectListHardpoint' => 'hardpoint/ArcanistObjectListHardpoint.php',
'ArcanistObjectOperatorSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistObjectOperatorSpacingXHPASTLinterRule.php',
'ArcanistObjectOperatorSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistObjectOperatorSpacingXHPASTLinterRuleTestCase.php',
'ArcanistPEP8Linter' => 'lint/linter/ArcanistPEP8Linter.php',
'ArcanistPEP8LinterTestCase' => 'lint/linter/__tests__/ArcanistPEP8LinterTestCase.php',
'ArcanistPHPCloseTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPCloseTagXHPASTLinterRule.php',
'ArcanistPHPCloseTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPCloseTagXHPASTLinterRuleTestCase.php',
'ArcanistPHPCompatibilityXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php',
'ArcanistPHPCompatibilityXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPCompatibilityXHPASTLinterRuleTestCase.php',
'ArcanistPHPEchoTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPEchoTagXHPASTLinterRule.php',
'ArcanistPHPEchoTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPEchoTagXHPASTLinterRuleTestCase.php',
'ArcanistPHPOpenTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPOpenTagXHPASTLinterRule.php',
'ArcanistPHPOpenTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPOpenTagXHPASTLinterRuleTestCase.php',
'ArcanistPHPShortTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPShortTagXHPASTLinterRule.php',
'ArcanistPHPShortTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPShortTagXHPASTLinterRuleTestCase.php',
'ArcanistPaamayimNekudotayimSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPaamayimNekudotayimSpacingXHPASTLinterRule.php',
'ArcanistPaamayimNekudotayimSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPaamayimNekudotayimSpacingXHPASTLinterRuleTestCase.php',
'ArcanistParentMemberReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParentMemberReferenceXHPASTLinterRule.php',
'ArcanistParentMemberReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParentMemberReferenceXHPASTLinterRuleTestCase.php',
'ArcanistParenthesesSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParenthesesSpacingXHPASTLinterRule.php',
'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParenthesesSpacingXHPASTLinterRuleTestCase.php',
'ArcanistParseStrUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParseStrUseXHPASTLinterRule.php',
'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParseStrUseXHPASTLinterRuleTestCase.php',
'ArcanistPartialCatchXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPartialCatchXHPASTLinterRule.php',
'ArcanistPartialCatchXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPartialCatchXHPASTLinterRuleTestCase.php',
'ArcanistPasteRef' => 'ref/paste/ArcanistPasteRef.php',
'ArcanistPasteSymbolRef' => 'ref/paste/ArcanistPasteSymbolRef.php',
'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php',
'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php',
'ArcanistPhpLinter' => 'lint/linter/ArcanistPhpLinter.php',
'ArcanistPhpLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpLinterTestCase.php',
'ArcanistPhpcsLinter' => 'lint/linter/ArcanistPhpcsLinter.php',
'ArcanistPhpcsLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpcsLinterTestCase.php',
'ArcanistPhpunitTestResultParser' => 'unit/parser/ArcanistPhpunitTestResultParser.php',
'ArcanistPhutilLibraryLinter' => 'lint/linter/ArcanistPhutilLibraryLinter.php',
'ArcanistPhutilWorkflow' => 'toolset/ArcanistPhutilWorkflow.php',
'ArcanistPhutilXHPASTLinterStandard' => 'lint/linter/standards/phutil/ArcanistPhutilXHPASTLinterStandard.php',
'ArcanistPlusOperatorOnStringsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPlusOperatorOnStringsXHPASTLinterRule.php',
'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase.php',
'ArcanistProjectConfigurationSource' => 'config/source/ArcanistProjectConfigurationSource.php',
'ArcanistPrompt' => 'toolset/ArcanistPrompt.php',
'ArcanistPromptResponse' => 'toolset/ArcanistPromptResponse.php',
'ArcanistPromptsConfigOption' => 'config/option/ArcanistPromptsConfigOption.php',
'ArcanistPromptsWorkflow' => 'toolset/workflow/ArcanistPromptsWorkflow.php',
'ArcanistPublicPropertyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPublicPropertyXHPASTLinterRule.php',
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPublicPropertyXHPASTLinterRuleTestCase.php',
'ArcanistPuppetLintLinter' => 'lint/linter/ArcanistPuppetLintLinter.php',
'ArcanistPuppetLintLinterTestCase' => 'lint/linter/__tests__/ArcanistPuppetLintLinterTestCase.php',
'ArcanistPyFlakesLinter' => 'lint/linter/ArcanistPyFlakesLinter.php',
'ArcanistPyFlakesLinterTestCase' => 'lint/linter/__tests__/ArcanistPyFlakesLinterTestCase.php',
'ArcanistPyLintLinter' => 'lint/linter/ArcanistPyLintLinter.php',
'ArcanistPyLintLinterTestCase' => 'lint/linter/__tests__/ArcanistPyLintLinterTestCase.php',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase.php',
'ArcanistRef' => 'ref/ArcanistRef.php',
'ArcanistRefInspector' => 'inspector/ArcanistRefInspector.php',
'ArcanistRefView' => 'ref/ArcanistRefView.php',
'ArcanistRemoteRef' => 'repository/remote/ArcanistRemoteRef.php',
'ArcanistRemoteRefInspector' => 'repository/remote/ArcanistRemoteRefInspector.php',
'ArcanistRemoteRepositoryRefsHardpointQuery' => 'repository/remote/ArcanistRemoteRepositoryRefsHardpointQuery.php',
'ArcanistRepositoryAPI' => 'repository/api/ArcanistRepositoryAPI.php',
'ArcanistRepositoryAPIMiscTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIMiscTestCase.php',
'ArcanistRepositoryAPIStateTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php',
'ArcanistRepositoryLocalState' => 'repository/state/ArcanistRepositoryLocalState.php',
'ArcanistRepositoryMarkerQuery' => 'repository/marker/ArcanistRepositoryMarkerQuery.php',
'ArcanistRepositoryQuery' => 'repository/query/ArcanistRepositoryQuery.php',
'ArcanistRepositoryRef' => 'ref/ArcanistRepositoryRef.php',
'ArcanistRepositoryRemoteQuery' => 'repository/remote/ArcanistRepositoryRemoteQuery.php',
'ArcanistRepositoryURINormalizer' => 'repository/remote/ArcanistRepositoryURINormalizer.php',
'ArcanistRepositoryURINormalizerTestCase' => 'repository/remote/__tests__/ArcanistRepositoryURINormalizerTestCase.php',
'ArcanistReusedAsIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedAsIteratorXHPASTLinterRule.php',
'ArcanistReusedAsIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedAsIteratorXHPASTLinterRuleTestCase.php',
'ArcanistReusedIteratorReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorReferenceXHPASTLinterRule.php',
'ArcanistReusedIteratorReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedIteratorReferenceXHPASTLinterRuleTestCase.php',
'ArcanistReusedIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorXHPASTLinterRule.php',
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedIteratorXHPASTLinterRuleTestCase.php',
'ArcanistRevisionAuthorHardpointQuery' => 'ref/revision/ArcanistRevisionAuthorHardpointQuery.php',
'ArcanistRevisionBuildableHardpointQuery' => 'ref/revision/ArcanistRevisionBuildableHardpointQuery.php',
'ArcanistRevisionCommitMessageHardpointQuery' => 'ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php',
'ArcanistRevisionParentRevisionsHardpointQuery' => 'ref/revision/ArcanistRevisionParentRevisionsHardpointQuery.php',
'ArcanistRevisionRef' => 'ref/revision/ArcanistRevisionRef.php',
'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php',
'ArcanistRevisionSymbolRef' => 'ref/revision/ArcanistRevisionSymbolRef.php',
'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
'ArcanistRubyLinterTestCase' => 'lint/linter/__tests__/ArcanistRubyLinterTestCase.php',
'ArcanistRuntime' => 'runtime/ArcanistRuntime.php',
'ArcanistRuntimeConfigurationSource' => 'config/source/ArcanistRuntimeConfigurationSource.php',
'ArcanistRuntimeHardpointQuery' => 'toolset/query/ArcanistRuntimeHardpointQuery.php',
'ArcanistScalarHardpoint' => 'hardpoint/ArcanistScalarHardpoint.php',
'ArcanistScriptAndRegexLinter' => 'lint/linter/ArcanistScriptAndRegexLinter.php',
'ArcanistSelfClassReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSelfClassReferenceXHPASTLinterRule.php',
'ArcanistSelfClassReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSelfClassReferenceXHPASTLinterRuleTestCase.php',
'ArcanistSelfMemberReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSelfMemberReferenceXHPASTLinterRule.php',
'ArcanistSelfMemberReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSelfMemberReferenceXHPASTLinterRuleTestCase.php',
'ArcanistSemicolonSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSemicolonSpacingXHPASTLinterRule.php',
'ArcanistSemicolonSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSemicolonSpacingXHPASTLinterRuleTestCase.php',
'ArcanistSetConfigWorkflow' => 'workflow/ArcanistSetConfigWorkflow.php',
'ArcanistSetting' => 'configuration/ArcanistSetting.php',
'ArcanistSettings' => 'configuration/ArcanistSettings.php',
'ArcanistShellCompleteWorkflow' => 'toolset/workflow/ArcanistShellCompleteWorkflow.php',
'ArcanistSimpleCommitGraphQuery' => 'repository/graph/query/ArcanistSimpleCommitGraphQuery.php',
'ArcanistSimpleSymbolHardpointQuery' => 'ref/simple/ArcanistSimpleSymbolHardpointQuery.php',
'ArcanistSimpleSymbolRef' => 'ref/simple/ArcanistSimpleSymbolRef.php',
'ArcanistSimpleSymbolRefInspector' => 'ref/simple/ArcanistSimpleSymbolRefInspector.php',
'ArcanistSingleLintEngine' => 'lint/engine/ArcanistSingleLintEngine.php',
'ArcanistSingleSourceConfigOption' => 'config/option/ArcanistSingleSourceConfigOption.php',
'ArcanistSlownessXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSlownessXHPASTLinterRule.php',
'ArcanistSlownessXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSlownessXHPASTLinterRuleTestCase.php',
'ArcanistSpellingLinter' => 'lint/linter/ArcanistSpellingLinter.php',
'ArcanistSpellingLinterTestCase' => 'lint/linter/__tests__/ArcanistSpellingLinterTestCase.php',
'ArcanistStaticThisXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistStaticThisXHPASTLinterRule.php',
'ArcanistStaticThisXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistStaticThisXHPASTLinterRuleTestCase.php',
'ArcanistStringConfigOption' => 'config/option/ArcanistStringConfigOption.php',
'ArcanistStringListConfigOption' => 'config/option/ArcanistStringListConfigOption.php',
'ArcanistSubversionAPI' => 'repository/api/ArcanistSubversionAPI.php',
'ArcanistSubversionWorkingCopy' => 'workingcopy/ArcanistSubversionWorkingCopy.php',
'ArcanistSummaryLintRenderer' => 'lint/renderer/ArcanistSummaryLintRenderer.php',
'ArcanistSymbolEngine' => 'ref/symbol/ArcanistSymbolEngine.php',
'ArcanistSymbolRef' => 'ref/symbol/ArcanistSymbolRef.php',
'ArcanistSyntaxErrorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSyntaxErrorXHPASTLinterRule.php',
'ArcanistSystemConfigurationSource' => 'config/source/ArcanistSystemConfigurationSource.php',
'ArcanistTaskRef' => 'ref/task/ArcanistTaskRef.php',
'ArcanistTaskSymbolRef' => 'ref/task/ArcanistTaskSymbolRef.php',
'ArcanistTasksWorkflow' => 'workflow/ArcanistTasksWorkflow.php',
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTautologicalExpressionXHPASTLinterRule.php',
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTautologicalExpressionXHPASTLinterRuleTestCase.php',
'ArcanistTerminalStringInterface' => 'xsprintf/ArcanistTerminalStringInterface.php',
'ArcanistTestResultParser' => 'unit/parser/ArcanistTestResultParser.php',
'ArcanistTestXHPASTLintSwitchHook' => 'lint/linter/__tests__/ArcanistTestXHPASTLintSwitchHook.php',
'ArcanistTextLinter' => 'lint/linter/ArcanistTextLinter.php',
'ArcanistTextLinterTestCase' => 'lint/linter/__tests__/ArcanistTextLinterTestCase.php',
'ArcanistThisReassignmentXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistThisReassignmentXHPASTLinterRule.php',
'ArcanistThisReassignmentXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistThisReassignmentXHPASTLinterRuleTestCase.php',
'ArcanistToStringExceptionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistToStringExceptionXHPASTLinterRule.php',
'ArcanistToStringExceptionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistToStringExceptionXHPASTLinterRuleTestCase.php',
'ArcanistTodoCommentXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTodoCommentXHPASTLinterRule.php',
'ArcanistTodoCommentXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTodoCommentXHPASTLinterRuleTestCase.php',
'ArcanistTodoWorkflow' => 'workflow/ArcanistTodoWorkflow.php',
'ArcanistToolset' => 'toolset/ArcanistToolset.php',
'ArcanistUSEnglishTranslation' => 'internationalization/ArcanistUSEnglishTranslation.php',
'ArcanistUnableToParseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnableToParseXHPASTLinterRule.php',
'ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule.php',
'ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRuleTestCase.php',
'ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRule.php',
'ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRuleTestCase.php',
'ArcanistUndeclaredVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUndeclaredVariableXHPASTLinterRule.php',
'ArcanistUndeclaredVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUndeclaredVariableXHPASTLinterRuleTestCase.php',
'ArcanistUnexpectedReturnValueXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnexpectedReturnValueXHPASTLinterRule.php',
'ArcanistUnexpectedReturnValueXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnexpectedReturnValueXHPASTLinterRuleTestCase.php',
'ArcanistUnitConsoleRenderer' => 'unit/renderer/ArcanistUnitConsoleRenderer.php',
'ArcanistUnitRenderer' => 'unit/renderer/ArcanistUnitRenderer.php',
'ArcanistUnitTestEngine' => 'unit/engine/ArcanistUnitTestEngine.php',
'ArcanistUnitTestResult' => 'unit/ArcanistUnitTestResult.php',
'ArcanistUnitTestResultTestCase' => 'unit/__tests__/ArcanistUnitTestResultTestCase.php',
'ArcanistUnitTestableLintEngine' => 'lint/engine/ArcanistUnitTestableLintEngine.php',
'ArcanistUnitWorkflow' => 'workflow/ArcanistUnitWorkflow.php',
'ArcanistUnnecessaryFinalModifierXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnnecessaryFinalModifierXHPASTLinterRule.php',
'ArcanistUnnecessaryFinalModifierXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnnecessaryFinalModifierXHPASTLinterRuleTestCase.php',
'ArcanistUnnecessarySemicolonXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnnecessarySemicolonXHPASTLinterRule.php',
'ArcanistUnnecessarySymbolAliasXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnnecessarySymbolAliasXHPASTLinterRule.php',
'ArcanistUnnecessarySymbolAliasXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnnecessarySymbolAliasXHPASTLinterRuleTestCase.php',
'ArcanistUnsafeDynamicStringXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnsafeDynamicStringXHPASTLinterRule.php',
'ArcanistUnsafeDynamicStringXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnsafeDynamicStringXHPASTLinterRuleTestCase.php',
'ArcanistUpgradeWorkflow' => 'workflow/ArcanistUpgradeWorkflow.php',
'ArcanistUploadWorkflow' => 'workflow/ArcanistUploadWorkflow.php',
'ArcanistUsageException' => 'exception/ArcanistUsageException.php',
'ArcanistUseStatementNamespacePrefixXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUseStatementNamespacePrefixXHPASTLinterRule.php',
'ArcanistUseStatementNamespacePrefixXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUseStatementNamespacePrefixXHPASTLinterRuleTestCase.php',
'ArcanistUselessOverridingMethodXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUselessOverridingMethodXHPASTLinterRule.php',
'ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase.php',
'ArcanistUserAbortException' => 'exception/usage/ArcanistUserAbortException.php',
'ArcanistUserConfigurationSource' => 'config/source/ArcanistUserConfigurationSource.php',
'ArcanistUserRef' => 'ref/user/ArcanistUserRef.php',
'ArcanistUserSymbolHardpointQuery' => 'ref/user/ArcanistUserSymbolHardpointQuery.php',
'ArcanistUserSymbolRef' => 'ref/user/ArcanistUserSymbolRef.php',
'ArcanistUserSymbolRefInspector' => 'ref/user/ArcanistUserSymbolRefInspector.php',
'ArcanistVariableReferenceSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistVariableReferenceSpacingXHPASTLinterRule.php',
'ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase.php',
'ArcanistVariableVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistVariableVariableXHPASTLinterRule.php',
'ArcanistVariableVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistVariableVariableXHPASTLinterRuleTestCase.php',
'ArcanistVectorHardpoint' => 'hardpoint/ArcanistVectorHardpoint.php',
'ArcanistVersionWorkflow' => 'toolset/workflow/ArcanistVersionWorkflow.php',
'ArcanistWeldWorkflow' => 'workflow/ArcanistWeldWorkflow.php',
'ArcanistWhichWorkflow' => 'workflow/ArcanistWhichWorkflow.php',
'ArcanistWildConfigOption' => 'config/option/ArcanistWildConfigOption.php',
'ArcanistWorkEngine' => 'work/ArcanistWorkEngine.php',
'ArcanistWorkWorkflow' => 'workflow/ArcanistWorkWorkflow.php',
'ArcanistWorkflow' => 'workflow/ArcanistWorkflow.php',
'ArcanistWorkflowArgument' => 'toolset/ArcanistWorkflowArgument.php',
'ArcanistWorkflowEngine' => 'engine/ArcanistWorkflowEngine.php',
'ArcanistWorkflowGitHardpointQuery' => 'query/ArcanistWorkflowGitHardpointQuery.php',
'ArcanistWorkflowInformation' => 'toolset/ArcanistWorkflowInformation.php',
'ArcanistWorkflowMercurialHardpointQuery' => 'query/ArcanistWorkflowMercurialHardpointQuery.php',
'ArcanistWorkingCopy' => 'workingcopy/ArcanistWorkingCopy.php',
'ArcanistWorkingCopyConfigurationSource' => 'config/source/ArcanistWorkingCopyConfigurationSource.php',
'ArcanistWorkingCopyIdentity' => 'workingcopyidentity/ArcanistWorkingCopyIdentity.php',
'ArcanistWorkingCopyPath' => 'workingcopy/ArcanistWorkingCopyPath.php',
'ArcanistWorkingCopyStateRef' => 'ref/ArcanistWorkingCopyStateRef.php',
'ArcanistWorkingCopyStateRefInspector' => 'inspector/ArcanistWorkingCopyStateRefInspector.php',
'ArcanistXHPASTLintNamingHook' => 'lint/linter/xhpast/ArcanistXHPASTLintNamingHook.php',
'ArcanistXHPASTLintNamingHookTestCase' => 'lint/linter/xhpast/__tests__/ArcanistXHPASTLintNamingHookTestCase.php',
'ArcanistXHPASTLintSwitchHook' => 'lint/linter/xhpast/ArcanistXHPASTLintSwitchHook.php',
'ArcanistXHPASTLinter' => 'lint/linter/ArcanistXHPASTLinter.php',
'ArcanistXHPASTLinterRule' => 'lint/linter/xhpast/ArcanistXHPASTLinterRule.php',
'ArcanistXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistXHPASTLinterRuleTestCase.php',
'ArcanistXHPASTLinterTestCase' => 'lint/linter/__tests__/ArcanistXHPASTLinterTestCase.php',
'ArcanistXMLLinter' => 'lint/linter/ArcanistXMLLinter.php',
'ArcanistXMLLinterTestCase' => 'lint/linter/__tests__/ArcanistXMLLinterTestCase.php',
'ArcanistXUnitTestResultParser' => 'unit/parser/ArcanistXUnitTestResultParser.php',
'BaseHTTPFuture' => 'future/http/BaseHTTPFuture.php',
'CSharpToolsTestEngine' => 'unit/engine/CSharpToolsTestEngine.php',
'CaseInsensitiveArray' => 'utils/CaseInsensitiveArray.php',
'CaseInsensitiveArrayTestCase' => 'utils/__tests__/CaseInsensitiveArrayTestCase.php',
'CommandException' => 'future/exec/CommandException.php',
'ConduitClient' => 'conduit/ConduitClient.php',
'ConduitClientException' => 'conduit/ConduitClientException.php',
'ConduitClientTestCase' => 'conduit/__tests__/ConduitClientTestCase.php',
'ConduitFuture' => 'conduit/ConduitFuture.php',
'ConduitSearchFuture' => 'conduit/ConduitSearchFuture.php',
'ExecFuture' => 'future/exec/ExecFuture.php',
'ExecFutureTestCase' => 'future/exec/__tests__/ExecFutureTestCase.php',
'ExecPassthruTestCase' => 'future/exec/__tests__/ExecPassthruTestCase.php',
'FileFinder' => 'filesystem/FileFinder.php',
'FileFinderTestCase' => 'filesystem/__tests__/FileFinderTestCase.php',
'FileList' => 'filesystem/FileList.php',
'Filesystem' => 'filesystem/Filesystem.php',
'FilesystemException' => 'filesystem/FilesystemException.php',
'FilesystemTestCase' => 'filesystem/__tests__/FilesystemTestCase.php',
'Future' => 'future/Future.php',
'FutureAgent' => 'conduit/FutureAgent.php',
'FutureIterator' => 'future/FutureIterator.php',
'FutureIteratorTestCase' => 'future/__tests__/FutureIteratorTestCase.php',
'FuturePool' => 'future/FuturePool.php',
'FutureProxy' => 'future/FutureProxy.php',
'HTTPFuture' => 'future/http/HTTPFuture.php',
'HTTPFutureCURLResponseStatus' => 'future/http/status/HTTPFutureCURLResponseStatus.php',
'HTTPFutureCertificateResponseStatus' => 'future/http/status/HTTPFutureCertificateResponseStatus.php',
'HTTPFutureHTTPResponseStatus' => 'future/http/status/HTTPFutureHTTPResponseStatus.php',
'HTTPFutureParseResponseStatus' => 'future/http/status/HTTPFutureParseResponseStatus.php',
'HTTPFutureResponseStatus' => 'future/http/status/HTTPFutureResponseStatus.php',
'HTTPFutureTransportResponseStatus' => 'future/http/status/HTTPFutureTransportResponseStatus.php',
'HTTPSFuture' => 'future/http/HTTPSFuture.php',
'ImmediateFuture' => 'future/ImmediateFuture.php',
'LibphutilUSEnglishTranslation' => 'internationalization/translation/LibphutilUSEnglishTranslation.php',
'LinesOfALarge' => 'filesystem/linesofalarge/LinesOfALarge.php',
'LinesOfALargeExecFuture' => 'filesystem/linesofalarge/LinesOfALargeExecFuture.php',
'LinesOfALargeExecFutureTestCase' => 'filesystem/linesofalarge/__tests__/LinesOfALargeExecFutureTestCase.php',
'LinesOfALargeFile' => 'filesystem/linesofalarge/LinesOfALargeFile.php',
'LinesOfALargeFileTestCase' => 'filesystem/linesofalarge/__tests__/LinesOfALargeFileTestCase.php',
'MFilterTestHelper' => 'utils/__tests__/MFilterTestHelper.php',
'MethodCallFuture' => 'future/MethodCallFuture.php',
'MethodCallFutureTestCase' => 'future/__tests__/MethodCallFutureTestCase.php',
'NoseTestEngine' => 'unit/engine/NoseTestEngine.php',
'PHPASTParserTestCase' => 'parser/xhpast/__tests__/PHPASTParserTestCase.php',
'PhageAction' => 'phage/action/PhageAction.php',
'PhageAgentAction' => 'phage/action/PhageAgentAction.php',
'PhageAgentBootloader' => 'phage/bootloader/PhageAgentBootloader.php',
'PhageAgentTestCase' => 'phage/__tests__/PhageAgentTestCase.php',
'PhageExecWorkflow' => 'phage/workflow/PhageExecWorkflow.php',
'PhageExecuteAction' => 'phage/action/PhageExecuteAction.php',
'PhageLocalAction' => 'phage/action/PhageLocalAction.php',
'PhagePHPAgent' => 'phage/agent/PhagePHPAgent.php',
'PhagePHPAgentBootloader' => 'phage/bootloader/PhagePHPAgentBootloader.php',
'PhagePlanAction' => 'phage/action/PhagePlanAction.php',
'PhageToolset' => 'phage/toolset/PhageToolset.php',
'PhageWorkflow' => 'phage/workflow/PhageWorkflow.php',
'Phobject' => 'object/Phobject.php',
'PhobjectTestCase' => 'object/__tests__/PhobjectTestCase.php',
'PhpunitTestEngine' => 'unit/engine/PhpunitTestEngine.php',
'PhpunitTestEngineTestCase' => 'unit/engine/__tests__/PhpunitTestEngineTestCase.php',
'PhutilAWSCloudFormationFuture' => 'future/aws/PhutilAWSCloudFormationFuture.php',
'PhutilAWSCloudWatchFuture' => 'future/aws/PhutilAWSCloudWatchFuture.php',
'PhutilAWSEC2Future' => 'future/aws/PhutilAWSEC2Future.php',
'PhutilAWSException' => 'future/aws/PhutilAWSException.php',
'PhutilAWSFuture' => 'future/aws/PhutilAWSFuture.php',
'PhutilAWSManagementWorkflow' => 'future/aws/management/PhutilAWSManagementWorkflow.php',
'PhutilAWSS3DeleteManagementWorkflow' => 'future/aws/management/PhutilAWSS3DeleteManagementWorkflow.php',
'PhutilAWSS3Future' => 'future/aws/PhutilAWSS3Future.php',
'PhutilAWSS3GetManagementWorkflow' => 'future/aws/management/PhutilAWSS3GetManagementWorkflow.php',
'PhutilAWSS3ManagementWorkflow' => 'future/aws/management/PhutilAWSS3ManagementWorkflow.php',
'PhutilAWSS3PutManagementWorkflow' => 'future/aws/management/PhutilAWSS3PutManagementWorkflow.php',
'PhutilAWSv4Signature' => 'future/aws/PhutilAWSv4Signature.php',
'PhutilAWSv4SignatureTestCase' => 'future/aws/__tests__/PhutilAWSv4SignatureTestCase.php',
'PhutilAggregateException' => 'error/PhutilAggregateException.php',
'PhutilAllCapsEnglishLocale' => 'internationalization/locales/PhutilAllCapsEnglishLocale.php',
'PhutilArgumentParser' => 'parser/argument/PhutilArgumentParser.php',
'PhutilArgumentParserException' => 'parser/argument/exception/PhutilArgumentParserException.php',
'PhutilArgumentParserTestCase' => 'parser/argument/__tests__/PhutilArgumentParserTestCase.php',
'PhutilArgumentSpecification' => 'parser/argument/PhutilArgumentSpecification.php',
'PhutilArgumentSpecificationException' => 'parser/argument/exception/PhutilArgumentSpecificationException.php',
'PhutilArgumentSpecificationTestCase' => 'parser/argument/__tests__/PhutilArgumentSpecificationTestCase.php',
'PhutilArgumentSpellingCorrector' => 'parser/argument/PhutilArgumentSpellingCorrector.php',
'PhutilArgumentSpellingCorrectorTestCase' => 'parser/argument/__tests__/PhutilArgumentSpellingCorrectorTestCase.php',
'PhutilArgumentUsageException' => 'parser/argument/exception/PhutilArgumentUsageException.php',
'PhutilArgumentWorkflow' => 'parser/argument/workflow/PhutilArgumentWorkflow.php',
'PhutilArray' => 'utils/PhutilArray.php',
'PhutilArrayCheck' => 'utils/PhutilArrayCheck.php',
'PhutilArrayTestCase' => 'utils/__tests__/PhutilArrayTestCase.php',
'PhutilArrayWithDefaultValue' => 'utils/PhutilArrayWithDefaultValue.php',
'PhutilAsanaFuture' => 'future/asana/PhutilAsanaFuture.php',
'PhutilBacktraceSignalHandler' => 'future/exec/PhutilBacktraceSignalHandler.php',
'PhutilBallOfPHP' => 'phage/util/PhutilBallOfPHP.php',
'PhutilBinaryAnalyzer' => 'filesystem/binary/PhutilBinaryAnalyzer.php',
'PhutilBinaryAnalyzerTestCase' => 'filesystem/binary/__tests__/PhutilBinaryAnalyzerTestCase.php',
'PhutilBootloader' => 'init/lib/PhutilBootloader.php',
'PhutilBootloaderException' => 'init/lib/PhutilBootloaderException.php',
'PhutilBritishEnglishLocale' => 'internationalization/locales/PhutilBritishEnglishLocale.php',
'PhutilBufferedIterator' => 'utils/PhutilBufferedIterator.php',
'PhutilBufferedIteratorTestCase' => 'utils/__tests__/PhutilBufferedIteratorTestCase.php',
'PhutilBugtraqParser' => 'parser/PhutilBugtraqParser.php',
'PhutilBugtraqParserTestCase' => 'parser/__tests__/PhutilBugtraqParserTestCase.php',
'PhutilCIDRBlock' => 'ip/PhutilCIDRBlock.php',
'PhutilCIDRList' => 'ip/PhutilCIDRList.php',
'PhutilCallbackFilterIterator' => 'utils/PhutilCallbackFilterIterator.php',
'PhutilCallbackSignalHandler' => 'future/exec/PhutilCallbackSignalHandler.php',
'PhutilChannel' => 'channel/PhutilChannel.php',
'PhutilChannelChannel' => 'channel/PhutilChannelChannel.php',
'PhutilChannelTestCase' => 'channel/__tests__/PhutilChannelTestCase.php',
'PhutilChunkedIterator' => 'utils/PhutilChunkedIterator.php',
'PhutilChunkedIteratorTestCase' => 'utils/__tests__/PhutilChunkedIteratorTestCase.php',
'PhutilClassMapQuery' => 'symbols/PhutilClassMapQuery.php',
'PhutilCloudWatchMetric' => 'future/aws/PhutilCloudWatchMetric.php',
'PhutilCommandString' => 'xsprintf/PhutilCommandString.php',
'PhutilConsole' => 'console/PhutilConsole.php',
'PhutilConsoleBlock' => 'console/view/PhutilConsoleBlock.php',
'PhutilConsoleError' => 'console/view/PhutilConsoleError.php',
'PhutilConsoleFormatter' => 'console/PhutilConsoleFormatter.php',
'PhutilConsoleInfo' => 'console/view/PhutilConsoleInfo.php',
'PhutilConsoleList' => 'console/view/PhutilConsoleList.php',
'PhutilConsoleLogLine' => 'console/view/PhutilConsoleLogLine.php',
'PhutilConsoleMessage' => 'console/PhutilConsoleMessage.php',
'PhutilConsoleMetrics' => 'console/PhutilConsoleMetrics.php',
'PhutilConsoleMetricsSignalHandler' => 'future/exec/PhutilConsoleMetricsSignalHandler.php',
'PhutilConsoleProgressBar' => 'console/PhutilConsoleProgressBar.php',
'PhutilConsoleProgressSink' => 'progress/PhutilConsoleProgressSink.php',
'PhutilConsoleServer' => 'console/PhutilConsoleServer.php',
'PhutilConsoleServerChannel' => 'console/PhutilConsoleServerChannel.php',
'PhutilConsoleSkip' => 'console/view/PhutilConsoleSkip.php',
'PhutilConsoleStdinNotInteractiveException' => 'console/PhutilConsoleStdinNotInteractiveException.php',
'PhutilConsoleTable' => 'console/view/PhutilConsoleTable.php',
'PhutilConsoleView' => 'console/view/PhutilConsoleView.php',
'PhutilConsoleWarning' => 'console/view/PhutilConsoleWarning.php',
'PhutilConsoleWrapTestCase' => 'console/__tests__/PhutilConsoleWrapTestCase.php',
'PhutilCowsay' => 'utils/PhutilCowsay.php',
'PhutilCowsayTestCase' => 'utils/__tests__/PhutilCowsayTestCase.php',
'PhutilCsprintfTestCase' => 'xsprintf/__tests__/PhutilCsprintfTestCase.php',
'PhutilCzechLocale' => 'internationalization/locales/PhutilCzechLocale.php',
'PhutilDOMNode' => 'parser/html/PhutilDOMNode.php',
'PhutilDeferredLog' => 'filesystem/PhutilDeferredLog.php',
'PhutilDeferredLogTestCase' => 'filesystem/__tests__/PhutilDeferredLogTestCase.php',
'PhutilDiffBinaryAnalyzer' => 'filesystem/binary/PhutilDiffBinaryAnalyzer.php',
'PhutilDirectedScalarGraph' => 'utils/PhutilDirectedScalarGraph.php',
'PhutilDirectoryFixture' => 'filesystem/PhutilDirectoryFixture.php',
'PhutilDocblockParser' => 'parser/PhutilDocblockParser.php',
'PhutilDocblockParserTestCase' => 'parser/__tests__/PhutilDocblockParserTestCase.php',
'PhutilEditDistanceMatrix' => 'utils/PhutilEditDistanceMatrix.php',
'PhutilEditDistanceMatrixTestCase' => 'utils/__tests__/PhutilEditDistanceMatrixTestCase.php',
'PhutilEditorConfig' => 'parser/PhutilEditorConfig.php',
'PhutilEditorConfigTestCase' => 'parser/__tests__/PhutilEditorConfigTestCase.php',
'PhutilEmailAddress' => 'parser/PhutilEmailAddress.php',
'PhutilEmailAddressTestCase' => 'parser/__tests__/PhutilEmailAddressTestCase.php',
'PhutilEmojiLocale' => 'internationalization/locales/PhutilEmojiLocale.php',
'PhutilEnglishCanadaLocale' => 'internationalization/locales/PhutilEnglishCanadaLocale.php',
'PhutilErrorHandler' => 'error/PhutilErrorHandler.php',
'PhutilErrorHandlerTestCase' => 'error/__tests__/PhutilErrorHandlerTestCase.php',
'PhutilErrorLog' => 'filesystem/PhutilErrorLog.php',
'PhutilErrorTrap' => 'error/PhutilErrorTrap.php',
'PhutilEvent' => 'events/PhutilEvent.php',
'PhutilEventConstants' => 'events/constant/PhutilEventConstants.php',
'PhutilEventEngine' => 'events/PhutilEventEngine.php',
'PhutilEventListener' => 'events/PhutilEventListener.php',
'PhutilEventType' => 'events/constant/PhutilEventType.php',
'PhutilExampleBufferedIterator' => 'utils/PhutilExampleBufferedIterator.php',
'PhutilExecChannel' => 'channel/PhutilExecChannel.php',
'PhutilExecPassthru' => 'future/exec/PhutilExecPassthru.php',
'PhutilExecutableFuture' => 'future/exec/PhutilExecutableFuture.php',
'PhutilExecutionEnvironment' => 'utils/PhutilExecutionEnvironment.php',
'PhutilFileLock' => 'filesystem/PhutilFileLock.php',
'PhutilFileLockTestCase' => 'filesystem/__tests__/PhutilFileLockTestCase.php',
'PhutilFrenchLocale' => 'internationalization/locales/PhutilFrenchLocale.php',
'PhutilGermanLocale' => 'internationalization/locales/PhutilGermanLocale.php',
'PhutilGitBinaryAnalyzer' => 'filesystem/binary/PhutilGitBinaryAnalyzer.php',
'PhutilGitHubFuture' => 'future/github/PhutilGitHubFuture.php',
'PhutilGitHubResponse' => 'future/github/PhutilGitHubResponse.php',
'PhutilGitURI' => 'parser/PhutilGitURI.php',
'PhutilGitURITestCase' => 'parser/__tests__/PhutilGitURITestCase.php',
'PhutilGitsprintfTestCase' => 'xsprintf/__tests__/PhutilGitsprintfTestCase.php',
'PhutilHTMLParser' => 'parser/html/PhutilHTMLParser.php',
'PhutilHTMLParserTestCase' => 'parser/html/__tests__/PhutilHTMLParserTestCase.php',
'PhutilHTTPEngineExtension' => 'future/http/PhutilHTTPEngineExtension.php',
'PhutilHTTPResponse' => 'parser/http/PhutilHTTPResponse.php',
'PhutilHTTPResponseParser' => 'parser/http/PhutilHTTPResponseParser.php',
'PhutilHTTPResponseParserTestCase' => 'parser/http/__tests__/PhutilHTTPResponseParserTestCase.php',
'PhutilHashingIterator' => 'utils/PhutilHashingIterator.php',
'PhutilHashingIteratorTestCase' => 'utils/__tests__/PhutilHashingIteratorTestCase.php',
'PhutilHelpArgumentWorkflow' => 'parser/argument/workflow/PhutilHelpArgumentWorkflow.php',
'PhutilHgsprintfTestCase' => 'xsprintf/__tests__/PhutilHgsprintfTestCase.php',
'PhutilINIParserException' => 'parser/exception/PhutilINIParserException.php',
'PhutilIPAddress' => 'ip/PhutilIPAddress.php',
'PhutilIPAddressTestCase' => 'ip/__tests__/PhutilIPAddressTestCase.php',
'PhutilIPv4Address' => 'ip/PhutilIPv4Address.php',
'PhutilIPv6Address' => 'ip/PhutilIPv6Address.php',
'PhutilInteractiveEditor' => 'console/PhutilInteractiveEditor.php',
'PhutilInvalidRuleParserGeneratorException' => 'parser/generator/exception/PhutilInvalidRuleParserGeneratorException.php',
'PhutilInvalidStateException' => 'exception/PhutilInvalidStateException.php',
'PhutilInvalidStateExceptionTestCase' => 'exception/__tests__/PhutilInvalidStateExceptionTestCase.php',
'PhutilIrreducibleRuleParserGeneratorException' => 'parser/generator/exception/PhutilIrreducibleRuleParserGeneratorException.php',
'PhutilJSON' => 'parser/PhutilJSON.php',
'PhutilJSONFragmentLexer' => 'lexer/PhutilJSONFragmentLexer.php',
'PhutilJSONParser' => 'parser/PhutilJSONParser.php',
'PhutilJSONParserException' => 'parser/exception/PhutilJSONParserException.php',
'PhutilJSONParserTestCase' => 'parser/__tests__/PhutilJSONParserTestCase.php',
'PhutilJSONProtocolChannel' => 'channel/PhutilJSONProtocolChannel.php',
'PhutilJSONProtocolChannelTestCase' => 'channel/__tests__/PhutilJSONProtocolChannelTestCase.php',
'PhutilJSONTestCase' => 'parser/__tests__/PhutilJSONTestCase.php',
'PhutilJavaFragmentLexer' => 'lexer/PhutilJavaFragmentLexer.php',
'PhutilKoreanLocale' => 'internationalization/locales/PhutilKoreanLocale.php',
'PhutilLanguageGuesser' => 'parser/PhutilLanguageGuesser.php',
'PhutilLanguageGuesserTestCase' => 'parser/__tests__/PhutilLanguageGuesserTestCase.php',
'PhutilLexer' => 'lexer/PhutilLexer.php',
'PhutilLibraryConflictException' => 'init/lib/PhutilLibraryConflictException.php',
'PhutilLibraryMapBuilder' => 'moduleutils/PhutilLibraryMapBuilder.php',
'PhutilLibraryTestCase' => '__tests__/PhutilLibraryTestCase.php',
'PhutilLocale' => 'internationalization/PhutilLocale.php',
'PhutilLocaleTestCase' => 'internationalization/__tests__/PhutilLocaleTestCase.php',
'PhutilLock' => 'filesystem/PhutilLock.php',
'PhutilLockException' => 'filesystem/PhutilLockException.php',
'PhutilLogFileChannel' => 'channel/PhutilLogFileChannel.php',
'PhutilLunarPhase' => 'utils/PhutilLunarPhase.php',
'PhutilLunarPhaseTestCase' => 'utils/__tests__/PhutilLunarPhaseTestCase.php',
'PhutilMercurialBinaryAnalyzer' => 'filesystem/binary/PhutilMercurialBinaryAnalyzer.php',
'PhutilMethodNotImplementedException' => 'error/PhutilMethodNotImplementedException.php',
'PhutilMetricsChannel' => 'channel/PhutilMetricsChannel.php',
'PhutilMissingSymbolException' => 'init/lib/PhutilMissingSymbolException.php',
'PhutilModuleUtilsTestCase' => 'init/lib/__tests__/PhutilModuleUtilsTestCase.php',
'PhutilNumber' => 'internationalization/PhutilNumber.php',
'PhutilOAuth1Future' => 'future/oauth/PhutilOAuth1Future.php',
'PhutilOAuth1FutureTestCase' => 'future/oauth/__tests__/PhutilOAuth1FutureTestCase.php',
'PhutilOpaqueEnvelope' => 'error/PhutilOpaqueEnvelope.php',
'PhutilOpaqueEnvelopeKey' => 'error/PhutilOpaqueEnvelopeKey.php',
'PhutilOpaqueEnvelopeTestCase' => 'error/__tests__/PhutilOpaqueEnvelopeTestCase.php',
'PhutilPHPFragmentLexer' => 'lexer/PhutilPHPFragmentLexer.php',
'PhutilPHPFragmentLexerTestCase' => 'lexer/__tests__/PhutilPHPFragmentLexerTestCase.php',
'PhutilPHPObjectProtocolChannel' => 'channel/PhutilPHPObjectProtocolChannel.php',
'PhutilPHPObjectProtocolChannelTestCase' => 'channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php',
'PhutilParserGenerator' => 'parser/PhutilParserGenerator.php',
'PhutilParserGeneratorException' => 'parser/generator/exception/PhutilParserGeneratorException.php',
'PhutilParserGeneratorTestCase' => 'parser/__tests__/PhutilParserGeneratorTestCase.php',
'PhutilPayPalAPIFuture' => 'future/paypal/PhutilPayPalAPIFuture.php',
'PhutilPerson' => 'internationalization/PhutilPerson.php',
'PhutilPersonTest' => 'internationalization/__tests__/PhutilPersonTest.php',
'PhutilPhtTestCase' => 'internationalization/__tests__/PhutilPhtTestCase.php',
'PhutilPirateEnglishLocale' => 'internationalization/locales/PhutilPirateEnglishLocale.php',
'PhutilPortugueseBrazilLocale' => 'internationalization/locales/PhutilPortugueseBrazilLocale.php',
'PhutilPortuguesePortugalLocale' => 'internationalization/locales/PhutilPortuguesePortugalLocale.php',
'PhutilPostmarkFuture' => 'future/postmark/PhutilPostmarkFuture.php',
'PhutilPregsprintfTestCase' => 'xsprintf/__tests__/PhutilPregsprintfTestCase.php',
'PhutilProcessQuery' => 'filesystem/PhutilProcessQuery.php',
'PhutilProcessRef' => 'filesystem/PhutilProcessRef.php',
'PhutilProcessRefTestCase' => 'filesystem/__tests__/PhutilProcessRefTestCase.php',
'PhutilProgressSink' => 'progress/PhutilProgressSink.php',
'PhutilProtocolChannel' => 'channel/PhutilProtocolChannel.php',
'PhutilProxyException' => 'error/PhutilProxyException.php',
'PhutilProxyIterator' => 'utils/PhutilProxyIterator.php',
'PhutilPygmentizeBinaryAnalyzer' => 'filesystem/binary/PhutilPygmentizeBinaryAnalyzer.php',
'PhutilPythonFragmentLexer' => 'lexer/PhutilPythonFragmentLexer.php',
'PhutilQueryStringParser' => 'parser/PhutilQueryStringParser.php',
'PhutilQueryStringParserTestCase' => 'parser/__tests__/PhutilQueryStringParserTestCase.php',
'PhutilRawEnglishLocale' => 'internationalization/locales/PhutilRawEnglishLocale.php',
'PhutilReadableSerializer' => 'readableserializer/PhutilReadableSerializer.php',
'PhutilReadableSerializerTestCase' => 'readableserializer/__tests__/PhutilReadableSerializerTestCase.php',
'PhutilRegexException' => 'exception/PhutilRegexException.php',
'PhutilRope' => 'utils/PhutilRope.php',
'PhutilRopeTestCase' => 'utils/__tests__/PhutilRopeTestCase.php',
'PhutilServiceProfiler' => 'serviceprofiler/PhutilServiceProfiler.php',
'PhutilShellLexer' => 'lexer/PhutilShellLexer.php',
'PhutilShellLexerTestCase' => 'lexer/__tests__/PhutilShellLexerTestCase.php',
'PhutilSignalHandler' => 'future/exec/PhutilSignalHandler.php',
'PhutilSignalRouter' => 'future/exec/PhutilSignalRouter.php',
'PhutilSimpleOptions' => 'parser/PhutilSimpleOptions.php',
'PhutilSimpleOptionsLexer' => 'lexer/PhutilSimpleOptionsLexer.php',
'PhutilSimpleOptionsLexerTestCase' => 'lexer/__tests__/PhutilSimpleOptionsLexerTestCase.php',
'PhutilSimpleOptionsTestCase' => 'parser/__tests__/PhutilSimpleOptionsTestCase.php',
'PhutilSimplifiedChineseLocale' => 'internationalization/locales/PhutilSimplifiedChineseLocale.php',
'PhutilSlackFuture' => 'future/slack/PhutilSlackFuture.php',
'PhutilSocketChannel' => 'channel/PhutilSocketChannel.php',
'PhutilSortVector' => 'utils/PhutilSortVector.php',
'PhutilSpanishSpainLocale' => 'internationalization/locales/PhutilSpanishSpainLocale.php',
'PhutilStreamIterator' => 'utils/PhutilStreamIterator.php',
'PhutilSubversionBinaryAnalyzer' => 'filesystem/binary/PhutilSubversionBinaryAnalyzer.php',
'PhutilSymbolLoader' => 'symbols/PhutilSymbolLoader.php',
'PhutilSystem' => 'utils/PhutilSystem.php',
'PhutilSystemTestCase' => 'utils/__tests__/PhutilSystemTestCase.php',
'PhutilTerminalString' => 'xsprintf/PhutilTerminalString.php',
'PhutilTestCase' => 'unit/engine/phutil/PhutilTestCase.php',
'PhutilTestCaseTestCase' => 'unit/engine/phutil/testcase/PhutilTestCaseTestCase.php',
'PhutilTestPhobject' => 'object/__tests__/PhutilTestPhobject.php',
'PhutilTestSkippedException' => 'unit/engine/phutil/testcase/PhutilTestSkippedException.php',
'PhutilTestTerminatedException' => 'unit/engine/phutil/testcase/PhutilTestTerminatedException.php',
'PhutilTraditionalChineseLocale' => 'internationalization/locales/PhutilTraditionalChineseLocale.php',
'PhutilTranslation' => 'internationalization/PhutilTranslation.php',
'PhutilTranslationTestCase' => 'internationalization/__tests__/PhutilTranslationTestCase.php',
'PhutilTranslator' => 'internationalization/PhutilTranslator.php',
'PhutilTranslatorTestCase' => 'internationalization/__tests__/PhutilTranslatorTestCase.php',
'PhutilTsprintfTestCase' => 'xsprintf/__tests__/PhutilTsprintfTestCase.php',
'PhutilTwitchFuture' => 'future/twitch/PhutilTwitchFuture.php',
'PhutilTypeCheckException' => 'parser/exception/PhutilTypeCheckException.php',
'PhutilTypeExtraParametersException' => 'parser/exception/PhutilTypeExtraParametersException.php',
'PhutilTypeLexer' => 'lexer/PhutilTypeLexer.php',
'PhutilTypeMissingParametersException' => 'parser/exception/PhutilTypeMissingParametersException.php',
'PhutilTypeSpec' => 'parser/PhutilTypeSpec.php',
'PhutilTypeSpecTestCase' => 'parser/__tests__/PhutilTypeSpecTestCase.php',
'PhutilURI' => 'parser/PhutilURI.php',
'PhutilURITestCase' => 'parser/__tests__/PhutilURITestCase.php',
'PhutilUSEnglishLocale' => 'internationalization/locales/PhutilUSEnglishLocale.php',
'PhutilUTF8StringTruncator' => 'utils/PhutilUTF8StringTruncator.php',
'PhutilUTF8TestCase' => 'utils/__tests__/PhutilUTF8TestCase.php',
'PhutilUnitTestEngine' => 'unit/engine/PhutilUnitTestEngine.php',
'PhutilUnitTestEngineTestCase' => 'unit/engine/__tests__/PhutilUnitTestEngineTestCase.php',
'PhutilUnknownSymbolParserGeneratorException' => 'parser/generator/exception/PhutilUnknownSymbolParserGeneratorException.php',
'PhutilUnreachableRuleParserGeneratorException' => 'parser/generator/exception/PhutilUnreachableRuleParserGeneratorException.php',
'PhutilUnreachableTerminalParserGeneratorException' => 'parser/generator/exception/PhutilUnreachableTerminalParserGeneratorException.php',
'PhutilUrisprintfTestCase' => 'xsprintf/__tests__/PhutilUrisprintfTestCase.php',
'PhutilUtilsTestCase' => 'utils/__tests__/PhutilUtilsTestCase.php',
'PhutilVeryWowEnglishLocale' => 'internationalization/locales/PhutilVeryWowEnglishLocale.php',
'PhutilWordPressFuture' => 'future/wordpress/PhutilWordPressFuture.php',
'PhutilXHPASTBinary' => 'parser/xhpast/bin/PhutilXHPASTBinary.php',
'PytestTestEngine' => 'unit/engine/PytestTestEngine.php',
'TempFile' => 'filesystem/TempFile.php',
'TestAbstractDirectedGraph' => 'utils/__tests__/TestAbstractDirectedGraph.php',
'XHPASTNode' => 'parser/xhpast/api/XHPASTNode.php',
'XHPASTNodeTestCase' => 'parser/xhpast/api/__tests__/XHPASTNodeTestCase.php',
'XHPASTSyntaxErrorException' => 'parser/xhpast/api/XHPASTSyntaxErrorException.php',
'XHPASTToken' => 'parser/xhpast/api/XHPASTToken.php',
'XHPASTTree' => 'parser/xhpast/api/XHPASTTree.php',
'XHPASTTreeTestCase' => 'parser/xhpast/api/__tests__/XHPASTTreeTestCase.php',
'XUnitTestEngine' => 'unit/engine/XUnitTestEngine.php',
'XUnitTestResultParserTestCase' => 'unit/parser/__tests__/XUnitTestResultParserTestCase.php',
'XsprintfUnknownConversionException' => 'xsprintf/exception/XsprintfUnknownConversionException.php',
),
'function' => array(
'__phutil_autoload' => 'init/init-library.php',
'array_fuse' => 'utils/utils.php',
'array_interleave' => 'utils/utils.php',
'array_mergev' => 'utils/utils.php',
'array_select_keys' => 'utils/utils.php',
'assert_instances_of' => 'utils/utils.php',
'assert_same_keys' => 'utils/utils.php',
'assert_stringlike' => 'utils/utils.php',
'coalesce' => 'utils/utils.php',
'csprintf' => 'xsprintf/csprintf.php',
'exec_manual' => 'future/exec/execx.php',
'execx' => 'future/exec/execx.php',
'gitsprintf' => 'xsprintf/gitsprintf.php',
'head' => 'utils/utils.php',
'head_key' => 'utils/utils.php',
'hgsprintf' => 'xsprintf/hgsprintf.php',
'id' => 'utils/utils.php',
'idx' => 'utils/utils.php',
'idxv' => 'utils/utils.php',
'ifilter' => 'utils/utils.php',
'igroup' => 'utils/utils.php',
'ipull' => 'utils/utils.php',
'isort' => 'utils/utils.php',
'jsprintf' => 'xsprintf/jsprintf.php',
'last' => 'utils/utils.php',
'last_key' => 'utils/utils.php',
'ldap_sprintf' => 'xsprintf/ldapsprintf.php',
'mfilter' => 'utils/utils.php',
'mgroup' => 'utils/utils.php',
'mpull' => 'utils/utils.php',
'msort' => 'utils/utils.php',
'msortv' => 'utils/utils.php',
'msortv_internal' => 'utils/utils.php',
'msortv_natural' => 'utils/utils.php',
'newv' => 'utils/utils.php',
'nonempty' => 'utils/utils.php',
'phlog' => 'error/phlog.php',
'pht' => 'internationalization/pht.php',
'phutil_build_http_querystring' => 'utils/utils.php',
'phutil_build_http_querystring_from_pairs' => 'utils/utils.php',
'phutil_censor_credentials' => 'utils/utils.php',
'phutil_console_confirm' => 'console/format.php',
'phutil_console_format' => 'console/format.php',
'phutil_console_get_terminal_width' => 'console/format.php',
'phutil_console_prompt' => 'console/format.php',
'phutil_console_require_tty' => 'console/format.php',
'phutil_console_select' => 'console/format.php',
'phutil_console_wrap' => 'console/format.php',
'phutil_count' => 'internationalization/pht.php',
'phutil_date_format' => 'utils/viewutils.php',
'phutil_decode_mime_header' => 'utils/utils.php',
'phutil_describe_type' => 'utils/utils.php',
'phutil_encode_log' => 'utils/utils.php',
'phutil_error_listener_example' => 'error/phlog.php',
'phutil_escape_uri' => 'utils/utils.php',
'phutil_escape_uri_path_component' => 'utils/utils.php',
'phutil_fnmatch' => 'utils/utils.php',
'phutil_format_bytes' => 'utils/viewutils.php',
'phutil_format_relative_time' => 'utils/viewutils.php',
'phutil_format_relative_time_detailed' => 'utils/viewutils.php',
'phutil_format_units_generic' => 'utils/viewutils.php',
'phutil_fwrite_nonblocking_stream' => 'utils/utils.php',
'phutil_get_current_library_name' => 'init/lib/moduleutils.php',
'phutil_get_library_name_for_root' => 'init/lib/moduleutils.php',
'phutil_get_library_root' => 'init/lib/moduleutils.php',
'phutil_get_library_root_for_path' => 'init/lib/moduleutils.php',
'phutil_get_signal_name' => 'future/exec/execx.php',
'phutil_get_system_locale' => 'utils/utf8.php',
'phutil_glue' => 'utils/utils.php',
'phutil_hashes_are_identical' => 'utils/utils.php',
'phutil_http_parameter_pair' => 'utils/utils.php',
'phutil_ini_decode' => 'utils/utils.php',
'phutil_is_hiphop_runtime' => 'utils/utils.php',
'phutil_is_interactive' => 'utils/utils.php',
'phutil_is_natural_list' => 'utils/utils.php',
'phutil_is_noninteractive' => 'utils/utils.php',
'phutil_is_system_locale_available' => 'utils/utf8.php',
'phutil_is_utf8' => 'utils/utf8.php',
'phutil_is_utf8_slowly' => 'utils/utf8.php',
'phutil_is_utf8_with_only_bmp_characters' => 'utils/utf8.php',
'phutil_is_windows' => 'utils/utils.php',
'phutil_json_decode' => 'utils/utils.php',
'phutil_json_encode' => 'utils/utils.php',
'phutil_load_library' => 'init/lib/moduleutils.php',
'phutil_loggable_string' => 'utils/utils.php',
'phutil_microseconds_since' => 'utils/utils.php',
+ 'phutil_nonempty_scalar' => 'utils/utils.php',
+ 'phutil_nonempty_string' => 'utils/utils.php',
+ 'phutil_nonempty_stringlike' => 'utils/utils.php',
'phutil_parse_bytes' => 'utils/viewutils.php',
'phutil_partition' => 'utils/utils.php',
'phutil_passthru' => 'future/exec/execx.php',
'phutil_person' => 'internationalization/pht.php',
'phutil_preg_match' => 'utils/utils.php',
'phutil_preg_match_all' => 'utils/utils.php',
'phutil_raise_preg_exception' => 'utils/utils.php',
'phutil_register_library' => 'init/lib/core.php',
'phutil_register_library_map' => 'init/lib/core.php',
'phutil_set_system_locale' => 'utils/utf8.php',
'phutil_split_lines' => 'utils/utils.php',
'phutil_string_cast' => 'utils/utils.php',
'phutil_unescape_uri_path_component' => 'utils/utils.php',
'phutil_units' => 'utils/utils.php',
'phutil_utf8_console_strlen' => 'utils/utf8.php',
'phutil_utf8_convert' => 'utils/utf8.php',
'phutil_utf8_encode_codepoint' => 'utils/utf8.php',
'phutil_utf8_hard_wrap' => 'utils/utf8.php',
'phutil_utf8_hard_wrap_html' => 'utils/utf8.php',
'phutil_utf8_is_cjk' => 'utils/utf8.php',
'phutil_utf8_is_combining_character' => 'utils/utf8.php',
'phutil_utf8_strlen' => 'utils/utf8.php',
'phutil_utf8_strtolower' => 'utils/utf8.php',
'phutil_utf8_strtoupper' => 'utils/utf8.php',
'phutil_utf8_strtr' => 'utils/utf8.php',
'phutil_utf8_ucwords' => 'utils/utf8.php',
'phutil_utf8ize' => 'utils/utf8.php',
'phutil_utf8v' => 'utils/utf8.php',
'phutil_utf8v_codepoints' => 'utils/utf8.php',
'phutil_utf8v_combine_characters' => 'utils/utf8.php',
'phutil_utf8v_combined' => 'utils/utf8.php',
'phutil_validate_json' => 'utils/utils.php',
'phutil_var_export' => 'utils/utils.php',
'ppull' => 'utils/utils.php',
'pregsprintf' => 'xsprintf/pregsprintf.php',
'tsprintf' => 'xsprintf/tsprintf.php',
'urisprintf' => 'xsprintf/urisprintf.php',
'vcsprintf' => 'xsprintf/csprintf.php',
'vjsprintf' => 'xsprintf/jsprintf.php',
'vurisprintf' => 'xsprintf/urisprintf.php',
'xhp_parser_node_constants' => 'parser/xhpast/parser_nodes.php',
'xhpast_parser_token_constants' => 'parser/xhpast/parser_tokens.php',
'xsprintf' => 'xsprintf/xsprintf.php',
'xsprintf_callback_example' => 'xsprintf/xsprintf.php',
'xsprintf_command' => 'xsprintf/csprintf.php',
'xsprintf_git' => 'xsprintf/gitsprintf.php',
'xsprintf_javascript' => 'xsprintf/jsprintf.php',
'xsprintf_ldap' => 'xsprintf/ldapsprintf.php',
'xsprintf_mercurial' => 'xsprintf/hgsprintf.php',
'xsprintf_regex' => 'xsprintf/pregsprintf.php',
'xsprintf_terminal' => 'xsprintf/tsprintf.php',
'xsprintf_uri' => 'xsprintf/urisprintf.php',
),
'xmap' => array(
'AASTNode' => 'Phobject',
'AASTNodeList' => array(
'Phobject',
'Countable',
'Iterator',
),
'AASTToken' => 'Phobject',
'AASTTree' => 'Phobject',
'AbstractDirectedGraph' => 'Phobject',
'AbstractDirectedGraphTestCase' => 'PhutilTestCase',
'ArcanistAbstractMethodBodyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistAbstractMethodBodyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistAbstractPrivateMethodXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistAbstractPrivateMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistAlias' => 'Phobject',
'ArcanistAliasEffect' => 'Phobject',
'ArcanistAliasEngine' => 'Phobject',
'ArcanistAliasFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistAliasFunctionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistAliasWorkflow' => 'ArcanistWorkflow',
'ArcanistAliasesConfigOption' => 'ArcanistMultiSourceConfigOption',
'ArcanistAmendWorkflow' => 'ArcanistArcWorkflow',
'ArcanistAnoidWorkflow' => 'ArcanistArcWorkflow',
'ArcanistArcConfigurationEngineExtension' => 'ArcanistConfigurationEngineExtension',
'ArcanistArcToolset' => 'ArcanistToolset',
'ArcanistArcWorkflow' => 'ArcanistWorkflow',
'ArcanistArrayCombineXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistArrayCombineXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistArrayIndexSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistArrayIndexSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistArraySeparatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistArraySeparatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistArrayValueXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistArrayValueXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistBaseCommitParser' => 'Phobject',
'ArcanistBaseCommitParserTestCase' => 'PhutilTestCase',
'ArcanistBaseXHPASTLinter' => 'ArcanistFutureLinter',
'ArcanistBinaryExpressionSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistBinaryExpressionSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistBinaryNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistBinaryNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistBlacklistedFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistBlacklistedFunctionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistBlindlyTrustHTTPEngineExtension' => 'PhutilHTTPEngineExtension',
'ArcanistBookmarksWorkflow' => 'ArcanistMarkersWorkflow',
'ArcanistBoolConfigOption' => 'ArcanistSingleSourceConfigOption',
'ArcanistBraceFormattingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistBranchesWorkflow' => 'ArcanistMarkersWorkflow',
'ArcanistBrowseCommitHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistBrowseCommitURIHardpointQuery' => 'ArcanistBrowseURIHardpointQuery',
'ArcanistBrowseObjectNameURIHardpointQuery' => 'ArcanistBrowseURIHardpointQuery',
'ArcanistBrowsePathURIHardpointQuery' => 'ArcanistBrowseURIHardpointQuery',
'ArcanistBrowseRef' => 'ArcanistRef',
'ArcanistBrowseRefInspector' => 'ArcanistRefInspector',
'ArcanistBrowseRevisionURIHardpointQuery' => 'ArcanistBrowseURIHardpointQuery',
'ArcanistBrowseURIHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistBrowseURIRef' => 'ArcanistRef',
'ArcanistBrowseWorkflow' => 'ArcanistArcWorkflow',
'ArcanistBuildBuildplanHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistBuildPlanRef' => 'ArcanistRef',
'ArcanistBuildPlanSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistBuildRef' => 'ArcanistRef',
'ArcanistBuildSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistBuildableBuildsHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistBuildableRef' => 'ArcanistRef',
'ArcanistBuildableSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistBundle' => 'Phobject',
'ArcanistBundleTestCase' => 'PhutilTestCase',
'ArcanistCSSLintLinter' => 'ArcanistExternalLinter',
'ArcanistCSSLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCSharpLinter' => 'ArcanistLinter',
'ArcanistCallConduitWorkflow' => 'ArcanistArcWorkflow',
'ArcanistCallParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCallParenthesesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCallTimePassByReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCallTimePassByReferenceXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCapabilityNotSupportedException' => 'Exception',
'ArcanistCastSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCastSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCheckstyleXMLLintRenderer' => 'ArcanistLintRenderer',
'ArcanistChmodLinter' => 'ArcanistLinter',
'ArcanistChmodLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistClassExtendsObjectXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistClassExtendsObjectXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistClassFilenameMismatchXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistClassMustBeDeclaredAbstractXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistClassMustBeDeclaredAbstractXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistClassNameLiteralXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistClassNameLiteralXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCloseRevisionWorkflow' => 'ArcanistWorkflow',
'ArcanistClosureLinter' => 'ArcanistExternalLinter',
'ArcanistClosureLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCoffeeLintLinter' => 'ArcanistExternalLinter',
'ArcanistCoffeeLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCommand' => 'Phobject',
'ArcanistCommentRemover' => 'Phobject',
'ArcanistCommentRemoverTestCase' => 'PhutilTestCase',
'ArcanistCommentSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCommitGraph' => 'Phobject',
'ArcanistCommitGraphPartition' => 'Phobject',
'ArcanistCommitGraphPartitionQuery' => 'Phobject',
'ArcanistCommitGraphQuery' => 'Phobject',
'ArcanistCommitGraphSet' => 'Phobject',
'ArcanistCommitGraphSetQuery' => 'Phobject',
'ArcanistCommitGraphSetTreeView' => 'Phobject',
'ArcanistCommitGraphSetView' => 'Phobject',
'ArcanistCommitGraphTestCase' => 'PhutilTestCase',
'ArcanistCommitNode' => 'Phobject',
'ArcanistCommitRef' => 'ArcanistRef',
'ArcanistCommitSymbolRef' => 'ArcanistSymbolRef',
'ArcanistCommitSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistCommitUpstreamHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
'ArcanistComposerLinter' => 'ArcanistLinter',
'ArcanistComprehensiveLintEngine' => 'ArcanistLintEngine',
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistConduitAuthenticationException' => 'Exception',
'ArcanistConduitCallFuture' => 'FutureProxy',
'ArcanistConduitEngine' => 'Phobject',
'ArcanistConduitException' => 'Exception',
'ArcanistConfigOption' => 'Phobject',
'ArcanistConfiguration' => 'Phobject',
'ArcanistConfigurationDrivenLintEngine' => 'ArcanistLintEngine',
'ArcanistConfigurationDrivenUnitTestEngine' => 'ArcanistUnitTestEngine',
'ArcanistConfigurationEngine' => 'Phobject',
'ArcanistConfigurationEngineExtension' => 'Phobject',
'ArcanistConfigurationManager' => 'Phobject',
'ArcanistConfigurationSource' => 'Phobject',
'ArcanistConfigurationSourceList' => 'Phobject',
'ArcanistConfigurationSourceValue' => 'Phobject',
'ArcanistConsoleLintRenderer' => 'ArcanistLintRenderer',
'ArcanistConsoleLintRendererTestCase' => 'PhutilTestCase',
'ArcanistConstructorParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistConstructorParenthesesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistContinueInsideSwitchXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistContinueInsideSwitchXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistControlStatementSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistControlStatementSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCoverWorkflow' => 'ArcanistWorkflow',
'ArcanistCppcheckLinter' => 'ArcanistExternalLinter',
'ArcanistCppcheckLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCpplintLinter' => 'ArcanistExternalLinter',
'ArcanistCpplintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCurlyBraceArrayIndexXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCurlyBraceArrayIndexXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDeclarationParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDeclarationParenthesesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDefaultParametersXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDefaultParametersXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDefaultsConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
'ArcanistDeprecationXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDeprecationXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDictionaryConfigurationSource' => 'ArcanistConfigurationSource',
'ArcanistDiffByteSizeException' => 'Exception',
'ArcanistDiffChange' => 'Phobject',
'ArcanistDiffChangeType' => 'Phobject',
'ArcanistDiffHunk' => 'Phobject',
'ArcanistDiffParser' => 'Phobject',
'ArcanistDiffParserTestCase' => 'PhutilTestCase',
'ArcanistDiffUtils' => 'Phobject',
'ArcanistDiffUtilsTestCase' => 'PhutilTestCase',
'ArcanistDiffVectorNode' => 'Phobject',
'ArcanistDiffVectorTree' => 'Phobject',
'ArcanistDiffWorkflow' => 'ArcanistWorkflow',
'ArcanistDifferentialCommitMessage' => 'Phobject',
'ArcanistDifferentialCommitMessageParserException' => 'Exception',
'ArcanistDifferentialDependencyGraph' => 'AbstractDirectedGraph',
'ArcanistDifferentialRevisionHash' => 'Phobject',
'ArcanistDifferentialRevisionStatus' => 'Phobject',
'ArcanistDoubleQuoteXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDoubleQuoteXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDownloadWorkflow' => 'ArcanistArcWorkflow',
'ArcanistDuplicateKeysInArrayXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDuplicateKeysInArrayXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDuplicateSwitchCaseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDuplicateSwitchCaseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDynamicDefineXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDynamicDefineXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistEachUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistEachUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistElseIfUsageXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistElseIfUsageXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistEmptyFileXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistEmptyStatementXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistEmptyStatementXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistEventType' => 'PhutilEventType',
'ArcanistExitExpressionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistExitExpressionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistExportWorkflow' => 'ArcanistWorkflow',
'ArcanistExternalLinter' => 'ArcanistFutureLinter',
'ArcanistExternalLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistExtractUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistExtractUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistFileConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
'ArcanistFileDataRef' => 'Phobject',
'ArcanistFileRef' => 'ArcanistRef',
'ArcanistFileSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistFileUploader' => 'Phobject',
'ArcanistFilenameLinter' => 'ArcanistLinter',
'ArcanistFilenameLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistFilesystemAPI' => 'ArcanistRepositoryAPI',
'ArcanistFilesystemConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
'ArcanistFilesystemWorkingCopy' => 'ArcanistWorkingCopy',
'ArcanistFlake8Linter' => 'ArcanistExternalLinter',
'ArcanistFlake8LinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistFormattedStringXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistFutureLinter' => 'ArcanistLinter',
'ArcanistGeneratedLinter' => 'ArcanistLinter',
'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow',
'ArcanistGitAPI' => 'ArcanistRepositoryAPI',
'ArcanistGitCommitGraphQuery' => 'ArcanistCommitGraphQuery',
'ArcanistGitCommitMessageHardpointQuery' => 'ArcanistWorkflowGitHardpointQuery',
'ArcanistGitCommitSymbolCommitHardpointQuery' => 'ArcanistWorkflowGitHardpointQuery',
'ArcanistGitLandEngine' => 'ArcanistLandEngine',
'ArcanistGitLocalState' => 'ArcanistRepositoryLocalState',
'ArcanistGitRawCommit' => 'Phobject',
'ArcanistGitRawCommitTestCase' => 'PhutilTestCase',
'ArcanistGitRepositoryMarkerQuery' => 'ArcanistRepositoryMarkerQuery',
'ArcanistGitRepositoryRemoteQuery' => 'ArcanistRepositoryRemoteQuery',
'ArcanistGitUpstreamPath' => 'Phobject',
'ArcanistGitWorkEngine' => 'ArcanistWorkEngine',
'ArcanistGitWorkingCopy' => 'ArcanistWorkingCopy',
'ArcanistGitWorkingCopyRevisionHardpointQuery' => 'ArcanistWorkflowGitHardpointQuery',
'ArcanistGlobalVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistGlobalVariableXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistGoLintLinter' => 'ArcanistExternalLinter',
'ArcanistGoLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistGoTestResultParser' => 'ArcanistTestResultParser',
'ArcanistGoTestResultParserTestCase' => 'PhutilTestCase',
'ArcanistGridCell' => 'Phobject',
'ArcanistGridColumn' => 'Phobject',
'ArcanistGridRow' => 'Phobject',
'ArcanistGridView' => 'Phobject',
'ArcanistHLintLinter' => 'ArcanistExternalLinter',
'ArcanistHLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistHardpoint' => 'Phobject',
'ArcanistHardpointEngine' => 'Phobject',
'ArcanistHardpointFutureList' => 'Phobject',
'ArcanistHardpointList' => 'Phobject',
'ArcanistHardpointObject' => 'Phobject',
'ArcanistHardpointQuery' => 'Phobject',
'ArcanistHardpointRequest' => 'Phobject',
'ArcanistHardpointRequestList' => 'Phobject',
'ArcanistHardpointTask' => 'Phobject',
'ArcanistHardpointTaskResult' => 'Phobject',
'ArcanistHelpWorkflow' => 'ArcanistWorkflow',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistHgClientChannel' => 'PhutilProtocolChannel',
'ArcanistHgProxyClient' => 'Phobject',
'ArcanistHgProxyServer' => 'Phobject',
'ArcanistHgServerChannel' => 'PhutilProtocolChannel',
'ArcanistHostMemorySnapshot' => 'Phobject',
'ArcanistHostMemorySnapshotTestCase' => 'PhutilTestCase',
'ArcanistImplicitConstructorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistImplicitFallthroughXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistImplicitFallthroughXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistImplicitVisibilityXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistImplicitVisibilityXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistImplodeArgumentOrderXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistImplodeArgumentOrderXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInlineHTMLXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInlineHTMLXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInnerFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInnerFunctionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInspectWorkflow' => 'ArcanistArcWorkflow',
'ArcanistInstallCertificateWorkflow' => 'ArcanistWorkflow',
'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInterfaceAbstractMethodXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInterfaceAbstractMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInterfaceMethodBodyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInvalidDefaultParameterXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInvalidDefaultParameterXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInvalidModifiersXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInvalidModifiersXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInvalidOctalNumericScalarXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistIsAShouldBeInstanceOfXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistIsAShouldBeInstanceOfXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistJSHintLinter' => 'ArcanistExternalLinter',
'ArcanistJSHintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistJSONLintLinter' => 'ArcanistExternalLinter',
'ArcanistJSONLintRenderer' => 'ArcanistLintRenderer',
'ArcanistJSONLinter' => 'ArcanistLinter',
'ArcanistJSONLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistJscsLinter' => 'ArcanistExternalLinter',
'ArcanistJscsLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistKeywordCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistKeywordCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistLambdaFuncFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistLambdaFuncFunctionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistLandCommit' => 'Phobject',
'ArcanistLandCommitSet' => 'Phobject',
'ArcanistLandEngine' => 'ArcanistWorkflowEngine',
'ArcanistLandPushFailureException' => 'Exception',
'ArcanistLandSymbol' => 'Phobject',
'ArcanistLandTarget' => 'Phobject',
'ArcanistLandWorkflow' => 'ArcanistArcWorkflow',
'ArcanistLanguageConstructParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistLanguageConstructParenthesesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistLesscLinter' => 'ArcanistExternalLinter',
'ArcanistLesscLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistLiberateWorkflow' => 'ArcanistArcWorkflow',
'ArcanistLintEngine' => 'Phobject',
'ArcanistLintMessage' => 'Phobject',
'ArcanistLintMessageTestCase' => 'PhutilTestCase',
'ArcanistLintPatcher' => 'Phobject',
'ArcanistLintRenderer' => 'Phobject',
'ArcanistLintResult' => 'Phobject',
'ArcanistLintSeverity' => 'Phobject',
'ArcanistLintWorkflow' => 'ArcanistWorkflow',
'ArcanistLinter' => 'Phobject',
'ArcanistLinterStandard' => 'Phobject',
'ArcanistLinterStandardTestCase' => 'PhutilTestCase',
'ArcanistLinterTestCase' => 'PhutilTestCase',
'ArcanistLintersWorkflow' => 'ArcanistWorkflow',
'ArcanistListAssignmentXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistListAssignmentXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistListConfigOption' => 'ArcanistSingleSourceConfigOption',
'ArcanistListWorkflow' => 'ArcanistWorkflow',
'ArcanistLocalConfigurationSource' => 'ArcanistWorkingCopyConfigurationSource',
'ArcanistLogEngine' => 'Phobject',
'ArcanistLogMessage' => 'Phobject',
'ArcanistLogicalOperatorsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistLogicalOperatorsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistLookWorkflow' => 'ArcanistArcWorkflow',
'ArcanistLowercaseFunctionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistMarkerRef' => 'ArcanistRef',
'ArcanistMarkersWorkflow' => 'ArcanistArcWorkflow',
'ArcanistMercurialAPI' => 'ArcanistRepositoryAPI',
'ArcanistMercurialCommitGraphQuery' => 'ArcanistCommitGraphQuery',
'ArcanistMercurialCommitMessageHardpointQuery' => 'ArcanistWorkflowMercurialHardpointQuery',
'ArcanistMercurialCommitSymbolCommitHardpointQuery' => 'ArcanistWorkflowMercurialHardpointQuery',
'ArcanistMercurialLandEngine' => 'ArcanistLandEngine',
'ArcanistMercurialLocalState' => 'ArcanistRepositoryLocalState',
'ArcanistMercurialParser' => 'Phobject',
'ArcanistMercurialParserTestCase' => 'PhutilTestCase',
'ArcanistMercurialRepositoryMarkerQuery' => 'ArcanistRepositoryMarkerQuery',
'ArcanistMercurialRepositoryRemoteQuery' => 'ArcanistRepositoryRemoteQuery',
'ArcanistMercurialWorkEngine' => 'ArcanistWorkEngine',
'ArcanistMercurialWorkingCopy' => 'ArcanistWorkingCopy',
'ArcanistMercurialWorkingCopyRevisionHardpointQuery' => 'ArcanistWorkflowMercurialHardpointQuery',
'ArcanistMergeConflictLinter' => 'ArcanistLinter',
'ArcanistMergeConflictLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistMessageRevisionHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistMissingArgumentTerminatorException' => 'Exception',
'ArcanistMissingLinterException' => 'Exception',
'ArcanistModifierOrderingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistMultiSourceConfigOption' => 'ArcanistConfigOption',
'ArcanistNamespaceFirstStatementXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistNamespaceFirstStatementXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistNamingConventionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistNamingConventionsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistNestedNamespacesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistNestedNamespacesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistNewlineAfterOpenTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistNewlineAfterOpenTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistNoEffectException' => 'ArcanistUsageException',
'ArcanistNoEngineException' => 'ArcanistUsageException',
'ArcanistNoLintLinter' => 'ArcanistLinter',
'ArcanistNoLintLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistNoParentScopeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistNoParentScopeXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistNoURIConduitException' => 'ArcanistConduitException',
'ArcanistNonblockingGuard' => 'Phobject',
'ArcanistNoneLintRenderer' => 'ArcanistLintRenderer',
'ArcanistObjectListHardpoint' => 'ArcanistHardpoint',
'ArcanistObjectOperatorSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistObjectOperatorSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPEP8Linter' => 'ArcanistExternalLinter',
'ArcanistPEP8LinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPHPCloseTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPHPCloseTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPHPCompatibilityXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPHPCompatibilityXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPHPEchoTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPHPEchoTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPHPOpenTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPHPOpenTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPHPShortTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPHPShortTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPaamayimNekudotayimSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPaamayimNekudotayimSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistParentMemberReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistParentMemberReferenceXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistParenthesesSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistParseStrUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPartialCatchXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPartialCatchXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPasteRef' => 'ArcanistRef',
'ArcanistPasteSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistPasteWorkflow' => 'ArcanistArcWorkflow',
'ArcanistPatchWorkflow' => 'ArcanistWorkflow',
'ArcanistPhpLinter' => 'ArcanistExternalLinter',
'ArcanistPhpLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPhpcsLinter' => 'ArcanistExternalLinter',
'ArcanistPhpcsLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPhpunitTestResultParser' => 'ArcanistTestResultParser',
'ArcanistPhutilLibraryLinter' => 'ArcanistLinter',
'ArcanistPhutilWorkflow' => 'PhutilArgumentWorkflow',
'ArcanistPhutilXHPASTLinterStandard' => 'ArcanistLinterStandard',
'ArcanistPlusOperatorOnStringsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistProjectConfigurationSource' => 'ArcanistWorkingCopyConfigurationSource',
'ArcanistPrompt' => 'Phobject',
'ArcanistPromptResponse' => 'Phobject',
'ArcanistPromptsConfigOption' => 'ArcanistMultiSourceConfigOption',
'ArcanistPromptsWorkflow' => 'ArcanistWorkflow',
'ArcanistPublicPropertyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPuppetLintLinter' => 'ArcanistExternalLinter',
'ArcanistPuppetLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPyFlakesLinter' => 'ArcanistExternalLinter',
'ArcanistPyFlakesLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPyLintLinter' => 'ArcanistExternalLinter',
'ArcanistPyLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistRef' => 'ArcanistHardpointObject',
'ArcanistRefInspector' => 'Phobject',
'ArcanistRefView' => array(
'Phobject',
'ArcanistTerminalStringInterface',
),
'ArcanistRemoteRef' => 'ArcanistRef',
'ArcanistRemoteRefInspector' => 'ArcanistRefInspector',
'ArcanistRemoteRepositoryRefsHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRepositoryAPI' => 'Phobject',
'ArcanistRepositoryAPIMiscTestCase' => 'PhutilTestCase',
'ArcanistRepositoryAPIStateTestCase' => 'PhutilTestCase',
'ArcanistRepositoryLocalState' => 'Phobject',
'ArcanistRepositoryMarkerQuery' => 'ArcanistRepositoryQuery',
'ArcanistRepositoryQuery' => 'Phobject',
'ArcanistRepositoryRef' => 'ArcanistRef',
'ArcanistRepositoryRemoteQuery' => 'ArcanistRepositoryQuery',
'ArcanistRepositoryURINormalizer' => 'Phobject',
'ArcanistRepositoryURINormalizerTestCase' => 'PhutilTestCase',
'ArcanistReusedAsIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistReusedAsIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistReusedIteratorReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistReusedIteratorReferenceXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistReusedIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistRevisionAuthorHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionBuildableHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionCommitMessageHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionParentRevisionsHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionRef' => 'ArcanistRef',
'ArcanistRevisionRefSource' => 'Phobject',
'ArcanistRevisionSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
'ArcanistRubyLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistRuntimeConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
'ArcanistRuntimeHardpointQuery' => 'ArcanistHardpointQuery',
'ArcanistScalarHardpoint' => 'ArcanistHardpoint',
'ArcanistScriptAndRegexLinter' => 'ArcanistLinter',
'ArcanistSelfClassReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSelfClassReferenceXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistSelfMemberReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSelfMemberReferenceXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistSemicolonSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSemicolonSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistSetConfigWorkflow' => 'ArcanistWorkflow',
'ArcanistSetting' => 'Phobject',
'ArcanistSettings' => 'Phobject',
'ArcanistShellCompleteWorkflow' => 'ArcanistWorkflow',
'ArcanistSimpleCommitGraphQuery' => 'ArcanistCommitGraphQuery',
'ArcanistSimpleSymbolHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistSimpleSymbolRef' => 'ArcanistSymbolRef',
'ArcanistSimpleSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistSingleLintEngine' => 'ArcanistLintEngine',
'ArcanistSingleSourceConfigOption' => 'ArcanistConfigOption',
'ArcanistSlownessXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSlownessXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistSpellingLinter' => 'ArcanistLinter',
'ArcanistSpellingLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistStaticThisXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistStaticThisXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistStringConfigOption' => 'ArcanistSingleSourceConfigOption',
'ArcanistStringListConfigOption' => 'ArcanistListConfigOption',
'ArcanistSubversionAPI' => 'ArcanistRepositoryAPI',
'ArcanistSubversionWorkingCopy' => 'ArcanistWorkingCopy',
'ArcanistSummaryLintRenderer' => 'ArcanistLintRenderer',
'ArcanistSymbolEngine' => 'Phobject',
'ArcanistSymbolRef' => 'ArcanistRef',
'ArcanistSyntaxErrorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSystemConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
'ArcanistTaskRef' => 'ArcanistRef',
'ArcanistTaskSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistTasksWorkflow' => 'ArcanistWorkflow',
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistTestResultParser' => 'Phobject',
'ArcanistTestXHPASTLintSwitchHook' => 'ArcanistXHPASTLintSwitchHook',
'ArcanistTextLinter' => 'ArcanistLinter',
'ArcanistTextLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistThisReassignmentXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistThisReassignmentXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistToStringExceptionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistToStringExceptionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistTodoCommentXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistTodoCommentXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistTodoWorkflow' => 'ArcanistWorkflow',
'ArcanistToolset' => 'Phobject',
'ArcanistUSEnglishTranslation' => 'PhutilTranslation',
'ArcanistUnableToParseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUndeclaredVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUndeclaredVariableXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUnexpectedReturnValueXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnexpectedReturnValueXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUnitConsoleRenderer' => 'ArcanistUnitRenderer',
'ArcanistUnitRenderer' => 'Phobject',
'ArcanistUnitTestEngine' => 'Phobject',
'ArcanistUnitTestResult' => 'Phobject',
'ArcanistUnitTestResultTestCase' => 'PhutilTestCase',
'ArcanistUnitTestableLintEngine' => 'ArcanistLintEngine',
'ArcanistUnitWorkflow' => 'ArcanistWorkflow',
'ArcanistUnnecessaryFinalModifierXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnnecessaryFinalModifierXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUnnecessarySemicolonXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnnecessarySymbolAliasXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnnecessarySymbolAliasXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUnsafeDynamicStringXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnsafeDynamicStringXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUpgradeWorkflow' => 'ArcanistArcWorkflow',
'ArcanistUploadWorkflow' => 'ArcanistArcWorkflow',
'ArcanistUsageException' => 'Exception',
'ArcanistUseStatementNamespacePrefixXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUseStatementNamespacePrefixXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUselessOverridingMethodXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUserAbortException' => 'ArcanistUsageException',
'ArcanistUserConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
'ArcanistUserRef' => 'ArcanistRef',
'ArcanistUserSymbolHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistUserSymbolRef' => 'ArcanistSymbolRef',
'ArcanistUserSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistVariableReferenceSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistVariableVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistVariableVariableXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistVectorHardpoint' => 'ArcanistHardpoint',
'ArcanistVersionWorkflow' => 'ArcanistWorkflow',
'ArcanistWeldWorkflow' => 'ArcanistArcWorkflow',
'ArcanistWhichWorkflow' => 'ArcanistWorkflow',
'ArcanistWildConfigOption' => 'ArcanistConfigOption',
'ArcanistWorkEngine' => 'ArcanistWorkflowEngine',
'ArcanistWorkWorkflow' => 'ArcanistArcWorkflow',
'ArcanistWorkflow' => 'Phobject',
'ArcanistWorkflowArgument' => 'Phobject',
'ArcanistWorkflowEngine' => 'Phobject',
'ArcanistWorkflowGitHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistWorkflowInformation' => 'Phobject',
'ArcanistWorkflowMercurialHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistWorkingCopy' => 'Phobject',
'ArcanistWorkingCopyConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
'ArcanistWorkingCopyIdentity' => 'Phobject',
'ArcanistWorkingCopyPath' => 'Phobject',
'ArcanistWorkingCopyStateRef' => 'ArcanistRef',
'ArcanistWorkingCopyStateRefInspector' => 'ArcanistRefInspector',
'ArcanistXHPASTLintNamingHook' => 'Phobject',
'ArcanistXHPASTLintNamingHookTestCase' => 'PhutilTestCase',
'ArcanistXHPASTLintSwitchHook' => 'Phobject',
'ArcanistXHPASTLinter' => 'ArcanistBaseXHPASTLinter',
'ArcanistXHPASTLinterRule' => 'Phobject',
'ArcanistXHPASTLinterRuleTestCase' => 'ArcanistLinterTestCase',
'ArcanistXHPASTLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistXMLLinter' => 'ArcanistLinter',
'ArcanistXMLLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistXUnitTestResultParser' => 'Phobject',
'BaseHTTPFuture' => 'Future',
'CSharpToolsTestEngine' => 'XUnitTestEngine',
'CaseInsensitiveArray' => 'PhutilArray',
'CaseInsensitiveArrayTestCase' => 'PhutilTestCase',
'CommandException' => 'Exception',
'ConduitClient' => 'Phobject',
'ConduitClientException' => 'Exception',
'ConduitClientTestCase' => 'PhutilTestCase',
'ConduitFuture' => 'FutureProxy',
'ConduitSearchFuture' => 'FutureAgent',
'ExecFuture' => 'PhutilExecutableFuture',
'ExecFutureTestCase' => 'PhutilTestCase',
'ExecPassthruTestCase' => 'PhutilTestCase',
'FileFinder' => 'Phobject',
'FileFinderTestCase' => 'PhutilTestCase',
'FileList' => 'Phobject',
'Filesystem' => 'Phobject',
'FilesystemException' => 'Exception',
'FilesystemTestCase' => 'PhutilTestCase',
'Future' => 'Phobject',
'FutureAgent' => 'Future',
'FutureIterator' => array(
'Phobject',
'Iterator',
),
'FutureIteratorTestCase' => 'PhutilTestCase',
'FuturePool' => 'Phobject',
'FutureProxy' => 'Future',
'HTTPFuture' => 'BaseHTTPFuture',
'HTTPFutureCURLResponseStatus' => 'HTTPFutureResponseStatus',
'HTTPFutureCertificateResponseStatus' => 'HTTPFutureResponseStatus',
'HTTPFutureHTTPResponseStatus' => 'HTTPFutureResponseStatus',
'HTTPFutureParseResponseStatus' => 'HTTPFutureResponseStatus',
'HTTPFutureResponseStatus' => 'Exception',
'HTTPFutureTransportResponseStatus' => 'HTTPFutureResponseStatus',
'HTTPSFuture' => 'BaseHTTPFuture',
'ImmediateFuture' => 'Future',
'LibphutilUSEnglishTranslation' => 'PhutilTranslation',
'LinesOfALarge' => array(
'Phobject',
'Iterator',
),
'LinesOfALargeExecFuture' => 'LinesOfALarge',
'LinesOfALargeExecFutureTestCase' => 'PhutilTestCase',
'LinesOfALargeFile' => 'LinesOfALarge',
'LinesOfALargeFileTestCase' => 'PhutilTestCase',
'MFilterTestHelper' => 'Phobject',
'MethodCallFuture' => 'Future',
'MethodCallFutureTestCase' => 'PhutilTestCase',
'NoseTestEngine' => 'ArcanistUnitTestEngine',
'PHPASTParserTestCase' => 'PhutilTestCase',
'PhageAction' => 'Phobject',
'PhageAgentAction' => 'PhageAction',
'PhageAgentBootloader' => 'Phobject',
'PhageAgentTestCase' => 'PhutilTestCase',
'PhageExecWorkflow' => 'PhageWorkflow',
'PhageExecuteAction' => 'PhageAction',
'PhageLocalAction' => 'PhageAgentAction',
'PhagePHPAgent' => 'Phobject',
'PhagePHPAgentBootloader' => 'PhageAgentBootloader',
'PhagePlanAction' => 'PhageAction',
'PhageToolset' => 'ArcanistToolset',
'PhageWorkflow' => 'ArcanistWorkflow',
'Phobject' => 'Iterator',
'PhobjectTestCase' => 'PhutilTestCase',
'PhpunitTestEngine' => 'ArcanistUnitTestEngine',
'PhpunitTestEngineTestCase' => 'PhutilTestCase',
'PhutilAWSCloudFormationFuture' => 'PhutilAWSFuture',
'PhutilAWSCloudWatchFuture' => 'PhutilAWSFuture',
'PhutilAWSEC2Future' => 'PhutilAWSFuture',
'PhutilAWSException' => 'Exception',
'PhutilAWSFuture' => 'FutureProxy',
'PhutilAWSManagementWorkflow' => 'PhutilArgumentWorkflow',
'PhutilAWSS3DeleteManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow',
'PhutilAWSS3Future' => 'PhutilAWSFuture',
'PhutilAWSS3GetManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow',
'PhutilAWSS3ManagementWorkflow' => 'PhutilAWSManagementWorkflow',
'PhutilAWSS3PutManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow',
'PhutilAWSv4Signature' => 'Phobject',
'PhutilAWSv4SignatureTestCase' => 'PhutilTestCase',
'PhutilAggregateException' => 'Exception',
'PhutilAllCapsEnglishLocale' => 'PhutilLocale',
'PhutilArgumentParser' => 'Phobject',
'PhutilArgumentParserException' => 'Exception',
'PhutilArgumentParserTestCase' => 'PhutilTestCase',
'PhutilArgumentSpecification' => 'Phobject',
'PhutilArgumentSpecificationException' => 'PhutilArgumentParserException',
'PhutilArgumentSpecificationTestCase' => 'PhutilTestCase',
'PhutilArgumentSpellingCorrector' => 'Phobject',
'PhutilArgumentSpellingCorrectorTestCase' => 'PhutilTestCase',
'PhutilArgumentUsageException' => 'PhutilArgumentParserException',
'PhutilArgumentWorkflow' => 'Phobject',
'PhutilArray' => array(
'Phobject',
'Countable',
'ArrayAccess',
'Iterator',
),
'PhutilArrayCheck' => 'Phobject',
'PhutilArrayTestCase' => 'PhutilTestCase',
'PhutilArrayWithDefaultValue' => 'PhutilArray',
'PhutilAsanaFuture' => 'FutureProxy',
'PhutilBacktraceSignalHandler' => 'PhutilSignalHandler',
'PhutilBallOfPHP' => 'Phobject',
'PhutilBinaryAnalyzer' => 'Phobject',
'PhutilBinaryAnalyzerTestCase' => 'PhutilTestCase',
'PhutilBootloaderException' => 'Exception',
'PhutilBritishEnglishLocale' => 'PhutilLocale',
'PhutilBufferedIterator' => array(
'Phobject',
'Iterator',
),
'PhutilBufferedIteratorTestCase' => 'PhutilTestCase',
'PhutilBugtraqParser' => 'Phobject',
'PhutilBugtraqParserTestCase' => 'PhutilTestCase',
'PhutilCIDRBlock' => 'Phobject',
'PhutilCIDRList' => 'Phobject',
'PhutilCallbackFilterIterator' => 'FilterIterator',
'PhutilCallbackSignalHandler' => 'PhutilSignalHandler',
'PhutilChannel' => 'Phobject',
'PhutilChannelChannel' => 'PhutilChannel',
'PhutilChannelTestCase' => 'PhutilTestCase',
'PhutilChunkedIterator' => array(
'Phobject',
'Iterator',
),
'PhutilChunkedIteratorTestCase' => 'PhutilTestCase',
'PhutilClassMapQuery' => 'Phobject',
'PhutilCloudWatchMetric' => 'Phobject',
'PhutilCommandString' => 'Phobject',
'PhutilConsole' => 'Phobject',
'PhutilConsoleBlock' => 'PhutilConsoleView',
'PhutilConsoleError' => 'PhutilConsoleLogLine',
'PhutilConsoleFormatter' => 'Phobject',
'PhutilConsoleInfo' => 'PhutilConsoleLogLine',
'PhutilConsoleList' => 'PhutilConsoleView',
'PhutilConsoleLogLine' => 'PhutilConsoleView',
'PhutilConsoleMessage' => 'Phobject',
'PhutilConsoleMetrics' => 'Phobject',
'PhutilConsoleMetricsSignalHandler' => 'PhutilSignalHandler',
'PhutilConsoleProgressBar' => 'Phobject',
'PhutilConsoleProgressSink' => 'PhutilProgressSink',
'PhutilConsoleServer' => 'Phobject',
'PhutilConsoleServerChannel' => 'PhutilChannelChannel',
'PhutilConsoleSkip' => 'PhutilConsoleLogLine',
'PhutilConsoleStdinNotInteractiveException' => 'Exception',
'PhutilConsoleTable' => 'PhutilConsoleView',
'PhutilConsoleView' => 'Phobject',
'PhutilConsoleWarning' => 'PhutilConsoleLogLine',
'PhutilConsoleWrapTestCase' => 'PhutilTestCase',
'PhutilCowsay' => 'Phobject',
'PhutilCowsayTestCase' => 'PhutilTestCase',
'PhutilCsprintfTestCase' => 'PhutilTestCase',
'PhutilCzechLocale' => 'PhutilLocale',
'PhutilDOMNode' => 'Phobject',
'PhutilDeferredLog' => 'Phobject',
'PhutilDeferredLogTestCase' => 'PhutilTestCase',
'PhutilDiffBinaryAnalyzer' => 'PhutilBinaryAnalyzer',
'PhutilDirectedScalarGraph' => 'AbstractDirectedGraph',
'PhutilDirectoryFixture' => 'Phobject',
'PhutilDocblockParser' => 'Phobject',
'PhutilDocblockParserTestCase' => 'PhutilTestCase',
'PhutilEditDistanceMatrix' => 'Phobject',
'PhutilEditDistanceMatrixTestCase' => 'PhutilTestCase',
'PhutilEditorConfig' => 'Phobject',
'PhutilEditorConfigTestCase' => 'PhutilTestCase',
'PhutilEmailAddress' => 'Phobject',
'PhutilEmailAddressTestCase' => 'PhutilTestCase',
'PhutilEmojiLocale' => 'PhutilLocale',
'PhutilEnglishCanadaLocale' => 'PhutilLocale',
'PhutilErrorHandler' => 'Phobject',
'PhutilErrorHandlerTestCase' => 'PhutilTestCase',
'PhutilErrorLog' => 'Phobject',
'PhutilErrorTrap' => 'Phobject',
'PhutilEvent' => 'Phobject',
'PhutilEventConstants' => 'Phobject',
'PhutilEventEngine' => 'Phobject',
'PhutilEventListener' => 'Phobject',
'PhutilEventType' => 'PhutilEventConstants',
'PhutilExampleBufferedIterator' => 'PhutilBufferedIterator',
'PhutilExecChannel' => 'PhutilChannel',
'PhutilExecPassthru' => 'PhutilExecutableFuture',
'PhutilExecutableFuture' => 'Future',
'PhutilExecutionEnvironment' => 'Phobject',
'PhutilFileLock' => 'PhutilLock',
'PhutilFileLockTestCase' => 'PhutilTestCase',
'PhutilFrenchLocale' => 'PhutilLocale',
'PhutilGermanLocale' => 'PhutilLocale',
'PhutilGitBinaryAnalyzer' => 'PhutilBinaryAnalyzer',
'PhutilGitHubFuture' => 'FutureProxy',
'PhutilGitHubResponse' => 'Phobject',
'PhutilGitURI' => 'Phobject',
'PhutilGitURITestCase' => 'PhutilTestCase',
'PhutilGitsprintfTestCase' => 'PhutilTestCase',
'PhutilHTMLParser' => 'Phobject',
'PhutilHTMLParserTestCase' => 'PhutilTestCase',
'PhutilHTTPEngineExtension' => 'Phobject',
'PhutilHTTPResponse' => 'Phobject',
'PhutilHTTPResponseParser' => 'Phobject',
'PhutilHTTPResponseParserTestCase' => 'PhutilTestCase',
'PhutilHashingIterator' => array(
'PhutilProxyIterator',
'Iterator',
),
'PhutilHashingIteratorTestCase' => 'PhutilTestCase',
'PhutilHelpArgumentWorkflow' => 'PhutilArgumentWorkflow',
'PhutilHgsprintfTestCase' => 'PhutilTestCase',
'PhutilINIParserException' => 'Exception',
'PhutilIPAddress' => 'Phobject',
'PhutilIPAddressTestCase' => 'PhutilTestCase',
'PhutilIPv4Address' => 'PhutilIPAddress',
'PhutilIPv6Address' => 'PhutilIPAddress',
'PhutilInteractiveEditor' => 'Phobject',
'PhutilInvalidRuleParserGeneratorException' => 'PhutilParserGeneratorException',
'PhutilInvalidStateException' => 'Exception',
'PhutilInvalidStateExceptionTestCase' => 'PhutilTestCase',
'PhutilIrreducibleRuleParserGeneratorException' => 'PhutilParserGeneratorException',
'PhutilJSON' => 'Phobject',
'PhutilJSONFragmentLexer' => 'PhutilLexer',
'PhutilJSONParser' => 'Phobject',
'PhutilJSONParserException' => 'Exception',
'PhutilJSONParserTestCase' => 'PhutilTestCase',
'PhutilJSONProtocolChannel' => 'PhutilProtocolChannel',
'PhutilJSONProtocolChannelTestCase' => 'PhutilTestCase',
'PhutilJSONTestCase' => 'PhutilTestCase',
'PhutilJavaFragmentLexer' => 'PhutilLexer',
'PhutilKoreanLocale' => 'PhutilLocale',
'PhutilLanguageGuesser' => 'Phobject',
'PhutilLanguageGuesserTestCase' => 'PhutilTestCase',
'PhutilLexer' => 'Phobject',
'PhutilLibraryConflictException' => 'Exception',
'PhutilLibraryMapBuilder' => 'Phobject',
'PhutilLibraryTestCase' => 'PhutilTestCase',
'PhutilLocale' => 'Phobject',
'PhutilLocaleTestCase' => 'PhutilTestCase',
'PhutilLock' => 'Phobject',
'PhutilLockException' => 'Exception',
'PhutilLogFileChannel' => 'PhutilChannelChannel',
'PhutilLunarPhase' => 'Phobject',
'PhutilLunarPhaseTestCase' => 'PhutilTestCase',
'PhutilMercurialBinaryAnalyzer' => 'PhutilBinaryAnalyzer',
'PhutilMethodNotImplementedException' => 'Exception',
'PhutilMetricsChannel' => 'PhutilChannelChannel',
'PhutilMissingSymbolException' => 'Exception',
'PhutilModuleUtilsTestCase' => 'PhutilTestCase',
'PhutilNumber' => 'Phobject',
'PhutilOAuth1Future' => 'FutureProxy',
'PhutilOAuth1FutureTestCase' => 'PhutilTestCase',
'PhutilOpaqueEnvelope' => 'Phobject',
'PhutilOpaqueEnvelopeKey' => 'Phobject',
'PhutilOpaqueEnvelopeTestCase' => 'PhutilTestCase',
'PhutilPHPFragmentLexer' => 'PhutilLexer',
'PhutilPHPFragmentLexerTestCase' => 'PhutilTestCase',
'PhutilPHPObjectProtocolChannel' => 'PhutilProtocolChannel',
'PhutilPHPObjectProtocolChannelTestCase' => 'PhutilTestCase',
'PhutilParserGenerator' => 'Phobject',
'PhutilParserGeneratorException' => 'Exception',
'PhutilParserGeneratorTestCase' => 'PhutilTestCase',
'PhutilPayPalAPIFuture' => 'FutureProxy',
'PhutilPersonTest' => array(
'Phobject',
'PhutilPerson',
),
'PhutilPhtTestCase' => 'PhutilTestCase',
'PhutilPirateEnglishLocale' => 'PhutilLocale',
'PhutilPortugueseBrazilLocale' => 'PhutilLocale',
'PhutilPortuguesePortugalLocale' => 'PhutilLocale',
'PhutilPostmarkFuture' => 'FutureProxy',
'PhutilPregsprintfTestCase' => 'PhutilTestCase',
'PhutilProcessQuery' => 'Phobject',
'PhutilProcessRef' => 'Phobject',
'PhutilProcessRefTestCase' => 'PhutilTestCase',
'PhutilProgressSink' => 'Phobject',
'PhutilProtocolChannel' => 'PhutilChannelChannel',
'PhutilProxyException' => 'Exception',
'PhutilProxyIterator' => array(
'Phobject',
'Iterator',
),
'PhutilPygmentizeBinaryAnalyzer' => 'PhutilBinaryAnalyzer',
'PhutilPythonFragmentLexer' => 'PhutilLexer',
'PhutilQueryStringParser' => 'Phobject',
'PhutilQueryStringParserTestCase' => 'PhutilTestCase',
'PhutilRawEnglishLocale' => 'PhutilLocale',
'PhutilReadableSerializer' => 'Phobject',
'PhutilReadableSerializerTestCase' => 'PhutilTestCase',
'PhutilRegexException' => 'Exception',
'PhutilRope' => 'Phobject',
'PhutilRopeTestCase' => 'PhutilTestCase',
'PhutilServiceProfiler' => 'Phobject',
'PhutilShellLexer' => 'PhutilLexer',
'PhutilShellLexerTestCase' => 'PhutilTestCase',
'PhutilSignalHandler' => 'Phobject',
'PhutilSignalRouter' => 'Phobject',
'PhutilSimpleOptions' => 'Phobject',
'PhutilSimpleOptionsLexer' => 'PhutilLexer',
'PhutilSimpleOptionsLexerTestCase' => 'PhutilTestCase',
'PhutilSimpleOptionsTestCase' => 'PhutilTestCase',
'PhutilSimplifiedChineseLocale' => 'PhutilLocale',
'PhutilSlackFuture' => 'FutureProxy',
'PhutilSocketChannel' => 'PhutilChannel',
'PhutilSortVector' => 'Phobject',
'PhutilSpanishSpainLocale' => 'PhutilLocale',
'PhutilStreamIterator' => array(
'Phobject',
'Iterator',
),
'PhutilSubversionBinaryAnalyzer' => 'PhutilBinaryAnalyzer',
'PhutilSystem' => 'Phobject',
'PhutilSystemTestCase' => 'PhutilTestCase',
'PhutilTerminalString' => 'Phobject',
'PhutilTestCase' => 'Phobject',
'PhutilTestCaseTestCase' => 'PhutilTestCase',
'PhutilTestPhobject' => 'Phobject',
'PhutilTestSkippedException' => 'Exception',
'PhutilTestTerminatedException' => 'Exception',
'PhutilTraditionalChineseLocale' => 'PhutilLocale',
'PhutilTranslation' => 'Phobject',
'PhutilTranslationTestCase' => 'PhutilTestCase',
'PhutilTranslator' => 'Phobject',
'PhutilTranslatorTestCase' => 'PhutilTestCase',
'PhutilTsprintfTestCase' => 'PhutilTestCase',
'PhutilTwitchFuture' => 'FutureProxy',
'PhutilTypeCheckException' => 'Exception',
'PhutilTypeExtraParametersException' => 'Exception',
'PhutilTypeLexer' => 'PhutilLexer',
'PhutilTypeMissingParametersException' => 'Exception',
'PhutilTypeSpec' => 'Phobject',
'PhutilTypeSpecTestCase' => 'PhutilTestCase',
'PhutilURI' => 'Phobject',
'PhutilURITestCase' => 'PhutilTestCase',
'PhutilUSEnglishLocale' => 'PhutilLocale',
'PhutilUTF8StringTruncator' => 'Phobject',
'PhutilUTF8TestCase' => 'PhutilTestCase',
'PhutilUnitTestEngine' => 'ArcanistUnitTestEngine',
'PhutilUnitTestEngineTestCase' => 'PhutilTestCase',
'PhutilUnknownSymbolParserGeneratorException' => 'PhutilParserGeneratorException',
'PhutilUnreachableRuleParserGeneratorException' => 'PhutilParserGeneratorException',
'PhutilUnreachableTerminalParserGeneratorException' => 'PhutilParserGeneratorException',
'PhutilUrisprintfTestCase' => 'PhutilTestCase',
'PhutilUtilsTestCase' => 'PhutilTestCase',
'PhutilVeryWowEnglishLocale' => 'PhutilLocale',
'PhutilWordPressFuture' => 'FutureProxy',
'PhutilXHPASTBinary' => 'Phobject',
'PytestTestEngine' => 'ArcanistUnitTestEngine',
'TempFile' => 'Phobject',
'TestAbstractDirectedGraph' => 'AbstractDirectedGraph',
'XHPASTNode' => 'AASTNode',
'XHPASTNodeTestCase' => 'PhutilTestCase',
'XHPASTSyntaxErrorException' => 'Exception',
'XHPASTToken' => 'AASTToken',
'XHPASTTree' => 'AASTTree',
'XHPASTTreeTestCase' => 'PhutilTestCase',
'XUnitTestEngine' => 'ArcanistUnitTestEngine',
'XUnitTestResultParserTestCase' => 'PhutilTestCase',
'XsprintfUnknownConversionException' => 'InvalidArgumentException',
),
));
diff --git a/src/unit/engine/phutil/PhutilTestCase.php b/src/unit/engine/phutil/PhutilTestCase.php
index efa946d9..e5f56164 100644
--- a/src/unit/engine/phutil/PhutilTestCase.php
+++ b/src/unit/engine/phutil/PhutilTestCase.php
@@ -1,785 +1,926 @@
<?php
/**
* Base test case for the very simple libphutil test framework.
*
* @task assert Making Test Assertions
* @task exceptions Exception Handling
* @task hook Hooks for Setup and Teardown
* @task internal Internals
*/
abstract class PhutilTestCase extends Phobject {
private $assertions = 0;
private $runningTest;
private $testStartTime;
private $results = array();
private $enableCoverage;
private $coverage = array();
private $workingCopy;
private $paths;
private $renderer;
private static $executables = array();
/* -( Making Test Assertions )--------------------------------------------- */
/**
* Assert that a value is `false`, strictly. The test fails if it is not.
*
* @param wild The empirically derived value, generated by executing the
* test.
* @param string A human-readable description of what these values represent,
* and particularly of what a discrepancy means.
*
* @return void
* @task assert
*/
final protected function assertFalse($result, $message = null) {
if ($result === false) {
$this->assertions++;
return;
}
$this->failAssertionWithExpectedValue('false', $result, $message);
}
/**
* Assert that a value is `true`, strictly. The test fails if it is not.
*
* @param wild The empirically derived value, generated by executing the
* test.
* @param string A human-readable description of what these values represent,
* and particularly of what a discrepancy means.
*
* @return void
* @task assert
*/
final protected function assertTrue($result, $message = null) {
if ($result === true) {
$this->assertions++;
return;
}
$this->failAssertionWithExpectedValue('true', $result, $message);
}
/**
* Assert that two values are equal, strictly. The test fails if they are not.
*
* NOTE: This method uses PHP's strict equality test operator (`===`) to
* compare values. This means values and types must be equal, key order must
* be identical in arrays, and objects must be referentially identical.
*
* @param wild The theoretically expected value, generated by careful
* reasoning about the properties of the system.
* @param wild The empirically derived value, generated by executing the
* test.
* @param string A human-readable description of what these values represent,
* and particularly of what a discrepancy means.
*
* @return void
* @task assert
*/
final protected function assertEqual($expect, $result, $message = null) {
if ($expect === $result) {
$this->assertions++;
return;
}
$expect = PhutilReadableSerializer::printableValue($expect);
$result = PhutilReadableSerializer::printableValue($result);
$caller = self::getCallerInfo();
$file = $caller['file'];
$line = $caller['line'];
if ($message !== null) {
$output = pht(
'Assertion failed, expected values to be equal (at %s:%d): %s',
$file,
$line,
$message);
} else {
$output = pht(
'Assertion failed, expected values to be equal (at %s:%d).',
$file,
$line);
}
$output .= "\n";
if (strpos($expect, "\n") === false && strpos($result, "\n") === false) {
$output .= pht("Expected: %s\n Actual: %s", $expect, $result);
} else {
$output .= pht(
"Expected vs Actual Output Diff\n%s",
ArcanistDiffUtils::renderDifferences(
$expect,
$result,
$lines = 0xFFFF));
}
$this->failTest($output);
throw new PhutilTestTerminatedException($output);
}
/**
* Assert an unconditional failure. This is just a convenience method that
* better indicates intent than using dummy values with assertEqual(). This
* causes test failure.
*
* @param string Human-readable description of the reason for test failure.
* @return void
* @task assert
*/
final protected function assertFailure($message) {
$this->failTest($message);
throw new PhutilTestTerminatedException($message);
}
/**
* End this test by asserting that the test should be skipped for some
* reason.
*
* @param string Reason for skipping this test.
* @return void
* @task assert
*/
final protected function assertSkipped($message) {
$this->skipTest($message);
throw new PhutilTestSkippedException($message);
}
+ final protected function assertCaught(
+ $expect,
+ $actual,
+ $message = null) {
+
+ if ($message !== null) {
+ $message = phutil_string_cast($message);
+ }
+
+ if ($actual === null) {
+ // This is okay: no exception.
+ } else if ($actual instanceof Exception) {
+ // This is also okay.
+ } else if ($actual instanceof Throwable) {
+ // And this is okay too.
+ } else {
+ // Anything else is no good.
+
+ if ($message !== null) {
+ $output = pht(
+ 'Call to "assertCaught(..., <junk>, ...)" for test case "%s" '.
+ 'passed bad value for test result. Expected null, Exception, '.
+ 'or Throwable; got: %s.',
+ $message,
+ phutil_describe_type($actual));
+ } else {
+ $output = pht(
+ 'Call to "assertCaught(..., <junk>, ...)" passed bad value for '.
+ 'test result. Expected null, Exception, or Throwable; got: %s.',
+ phutil_describe_type($actual));
+ }
+
+ $this->failTest($output);
+
+ throw new PhutilTestTerminatedException($output);
+ }
+
+ $expect_list = null;
+
+ if ($expect === false) {
+ $expect_list = array();
+ } else if ($expect === true) {
+ $expect_list = array(
+ 'Exception',
+ 'Throwable',
+ );
+ } else if (is_string($expect) || is_array($expect)) {
+ $list = (array)$expect;
+
+ $items_ok = true;
+ foreach ($list as $key => $item) {
+ if (!phutil_nonempty_stringlike($item)) {
+ $items_ok = false;
+ break;
+ }
+
+ $list[$key] = phutil_string_cast($item);
+ }
+
+ if ($items_ok) {
+ $expect_list = $list;
+ }
+ }
+
+ if ($expect_list === null) {
+ if ($message !== null) {
+ $output = pht(
+ 'Call to "assertCaught(<junk>, ...)" for test case "%s" '.
+ 'passed bad expected value. Expected bool, class name as a string, '.
+ 'or a list of class names. Got: %s.',
+ $message,
+ phutil_describe_type($expect));
+ } else {
+ $output = pht(
+ 'Call to "assertCaught(<junk>, ...)" passed bad expected value. '.
+ 'expected result. Expected null, Exception, or Throwable; got: %s.',
+ phutil_describe_type($expect));
+ }
+
+ $this->failTest($output);
+
+ throw new PhutilTestTerminatedException($output);
+ }
+
+ if ($actual === null) {
+ $is_match = !$expect_list;
+ } else {
+ $is_match = false;
+ foreach ($expect_list as $exception_class) {
+ if ($actual instanceof $exception_class) {
+ $is_match = true;
+ break;
+ }
+ }
+ }
+
+ if ($is_match) {
+ $this->assertions++;
+ return;
+ }
+
+ $caller = self::getCallerInfo();
+ $file = $caller['file'];
+ $line = $caller['line'];
+
+ $output = array();
+
+ if ($message !== null) {
+ $output[] = pht(
+ 'Assertion of caught exception failed (at %s:%d in test case "%s").',
+ $file,
+ $line,
+ $message);
+ } else {
+ $output[] = pht(
+ 'Assertion of caught exception failed (at %s:%d).',
+ $file,
+ $line);
+ }
+
+ if ($actual === null) {
+ $output[] = pht('Expected any exception, got no exception.');
+ } else if (!$expect_list) {
+ $output[] = pht(
+ 'Expected no exception, got exception of class "%s".',
+ get_class($actual));
+ } else {
+ $expected_classes = implode(', ', $expect_list);
+ $output[] = pht(
+ 'Expected exception (in class(es): %s), got exception of class "%s".',
+ $expected_classes,
+ get_class($actual));
+ }
+
+ $output = implode("\n\n", $output);
+
+ $this->failTest($output);
+
+ throw new PhutilTestTerminatedException($output);
+ }
+
/* -( Exception Handling )------------------------------------------------- */
/**
* This simplest way to assert exceptions are thrown.
*
* @param exception The expected exception.
* @param callable The thing which throws the exception.
*
* @return void
* @task exceptions
*/
final protected function assertException(
$expected_exception_class,
$callable) {
$this->tryTestCases(
array('assertException' => array()),
array(false),
$callable,
$expected_exception_class);
}
/**
* Straightforward method for writing unit tests which check if some block of
* code throws an exception. For example, this allows you to test the
* exception behavior of ##is_a_fruit()## on various inputs:
*
* public function testFruit() {
* $this->tryTestCases(
* array(
* 'apple is a fruit' => new Apple(),
* 'rock is not a fruit' => new Rock(),
* ),
* array(
* true,
* false,
* ),
* array($this, 'tryIsAFruit'),
* 'NotAFruitException');
* }
*
* protected function tryIsAFruit($input) {
* is_a_fruit($input);
* }
*
* @param map Map of test case labels to test case inputs.
* @param list List of expected results, true to indicate that the case
* is expected to succeed and false to indicate that the case
* is expected to throw.
* @param callable Callback to invoke for each test case.
* @param string Optional exception class to catch, defaults to
* 'Exception'.
* @return void
* @task exceptions
*/
final protected function tryTestCases(
array $inputs,
array $expect,
$callable,
$exception_class = 'Exception') {
if (count($inputs) !== count($expect)) {
$this->assertFailure(
pht('Input and expectations must have the same number of values.'));
}
$labels = array_keys($inputs);
$inputs = array_values($inputs);
$expecting = array_values($expect);
foreach ($inputs as $idx => $input) {
$expect = $expecting[$idx];
$label = $labels[$idx];
$caught = null;
try {
call_user_func($callable, $input);
} catch (Exception $ex) {
if ($ex instanceof PhutilTestTerminatedException) {
throw $ex;
}
if (!($ex instanceof $exception_class)) {
throw $ex;
}
$caught = $ex;
}
$actual = !($caught instanceof Exception);
if ($expect === $actual) {
if ($expect) {
$message = pht("Test case '%s' did not throw, as expected.", $label);
} else {
$message = pht("Test case '%s' threw, as expected.", $label);
}
} else {
if ($expect) {
$message = pht(
"Test case '%s' was expected to succeed, but it ".
"raised an exception of class %s with message: %s",
$label,
get_class($ex),
$ex->getMessage());
} else {
$message = pht(
"Test case '%s' was expected to raise an ".
"exception, but it did not throw anything.",
$label);
}
}
$this->assertEqual($expect, $actual, $message);
}
}
/**
* Convenience wrapper around @{method:tryTestCases} for cases where your
* inputs are scalar. For example:
*
* public function testFruit() {
* $this->tryTestCaseMap(
* array(
* 'apple' => true,
* 'rock' => false,
* ),
* array($this, 'tryIsAFruit'),
* 'NotAFruitException');
* }
*
* protected function tryIsAFruit($input) {
* is_a_fruit($input);
* }
*
* For cases where your inputs are not scalar, use @{method:tryTestCases}.
*
* @param map Map of scalar test inputs to expected success (true
* expects success, false expects an exception).
* @param callable Callback to invoke for each test case.
* @param string Optional exception class to catch, defaults to
* 'Exception'.
* @return void
* @task exceptions
*/
final protected function tryTestCaseMap(
array $map,
$callable,
$exception_class = 'Exception') {
return $this->tryTestCases(
array_fuse(array_keys($map)),
array_values($map),
$callable,
$exception_class);
}
/* -( Hooks for Setup and Teardown )--------------------------------------- */
/**
* This hook is invoked once, before any tests in this class are run. It
* gives you an opportunity to perform setup steps for the entire class.
*
* @return void
* @task hook
*/
protected function willRunTests() {
return;
}
/**
* This hook is invoked once, after any tests in this class are run. It gives
* you an opportunity to perform teardown steps for the entire class.
*
* @return void
* @task hook
*/
protected function didRunTests() {
return;
}
/**
* This hook is invoked once per test, before the test method is invoked.
*
* @param string Method name of the test which will be invoked.
* @return void
* @task hook
*/
protected function willRunOneTest($test_method_name) {
return;
}
/**
* This hook is invoked once per test, after the test method is invoked.
*
* @param string Method name of the test which was invoked.
* @return void
* @task hook
*/
protected function didRunOneTest($test_method_name) {
return;
}
/**
* This hook is invoked once, before any test cases execute. It gives you
* an opportunity to perform setup steps for the entire suite of test cases.
*
* @param list<PhutilTestCase> List of test cases to be run.
* @return void
* @task hook
*/
public function willRunTestCases(array $test_cases) {
return;
}
/**
* This hook is invoked once, after all test cases execute.
*
* @param list<PhutilTestCase> List of test cases that ran.
* @return void
* @task hook
*/
public function didRunTestCases(array $test_cases) {
return;
}
/* -( Internals )---------------------------------------------------------- */
/**
* Construct a new test case. This method is ##final##, use willRunTests() to
* provide test-wide setup logic.
*
* @task internal
*/
final public function __construct() {}
/**
* Mark the currently-running test as a failure.
*
* @param string Human-readable description of problems.
* @return void
*
* @task internal
*/
private function failTest($reason) {
$this->resultTest(ArcanistUnitTestResult::RESULT_FAIL, $reason);
}
/**
* This was a triumph. I'm making a note here: HUGE SUCCESS.
*
* @param string Human-readable overstatement of satisfaction.
* @return void
*
* @task internal
*/
private function passTest($reason) {
$this->resultTest(ArcanistUnitTestResult::RESULT_PASS, $reason);
}
/**
* Mark the current running test as skipped.
*
* @param string Description for why this test was skipped.
* @return void
* @task internal
*/
private function skipTest($reason) {
$this->resultTest(ArcanistUnitTestResult::RESULT_SKIP, $reason);
}
private function resultTest($test_result, $reason) {
$coverage = $this->endCoverage();
$result = new ArcanistUnitTestResult();
$result->setCoverage($coverage);
$result->setNamespace(get_class($this));
$result->setName($this->runningTest);
$result->setLink($this->getLink($this->runningTest));
$result->setResult($test_result);
$result->setDuration(microtime(true) - $this->testStartTime);
$result->setUserData($reason);
$this->results[] = $result;
if ($this->renderer) {
echo $this->renderer->renderUnitResult($result);
}
}
/**
* Execute the tests in this test case. You should not call this directly;
* use @{class:PhutilUnitTestEngine} to orchestrate test execution.
*
* @return void
* @task internal
*/
final public function run() {
$this->results = array();
$reflection = new ReflectionClass($this);
$methods = $reflection->getMethods();
// Try to ensure that poorly-written tests which depend on execution order
// (and are thus not properly isolated) will fail.
shuffle($methods);
$this->willRunTests();
foreach ($methods as $method) {
$name = $method->getName();
if (preg_match('/^test/', $name)) {
$this->runningTest = $name;
$this->assertions = 0;
$this->testStartTime = microtime(true);
try {
$this->willRunOneTest($name);
$this->beginCoverage();
$exceptions = array();
try {
call_user_func_array(
array($this, $name),
array());
$this->passTest(
pht(
'%s assertion(s) passed.',
new PhutilNumber($this->assertions)));
} catch (Exception $ex) {
$exceptions['Execution'] = $ex;
}
try {
$this->didRunOneTest($name);
} catch (Exception $ex) {
$exceptions['Shutdown'] = $ex;
}
if ($exceptions) {
if (count($exceptions) == 1) {
throw head($exceptions);
} else {
throw new PhutilAggregateException(
pht('Multiple exceptions were raised during test execution.'),
$exceptions);
}
}
if (!$this->assertions) {
$this->failTest(
pht(
'This test case made no assertions. Test cases must make at '.
'least one assertion.'));
}
} catch (PhutilTestTerminatedException $ex) {
// Continue with the next test.
} catch (PhutilTestSkippedException $ex) {
// Continue with the next test.
} catch (Exception $ex) {
$ex_class = get_class($ex);
$ex_message = $ex->getMessage();
$ex_trace = $ex->getTraceAsString();
$message = sprintf(
"%s (%s): %s\n%s",
pht('EXCEPTION'),
$ex_class,
$ex_message,
$ex_trace);
$this->failTest($message);
}
}
}
$this->didRunTests();
return $this->results;
}
final public function setEnableCoverage($enable_coverage) {
$this->enableCoverage = $enable_coverage;
return $this;
}
/**
* @phutil-external-symbol function xdebug_start_code_coverage
*/
private function beginCoverage() {
if (!$this->enableCoverage) {
return;
}
$this->assertCoverageAvailable();
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
}
/**
* @phutil-external-symbol function xdebug_get_code_coverage
* @phutil-external-symbol function xdebug_stop_code_coverage
*/
private function endCoverage() {
if (!$this->enableCoverage) {
return;
}
$result = xdebug_get_code_coverage();
xdebug_stop_code_coverage($cleanup = false);
$coverage = array();
foreach ($result as $file => $report) {
$project_root = $this->getProjectRoot();
if (strncmp($file, $project_root, strlen($project_root))) {
continue;
}
$max = max(array_keys($report));
$str = '';
for ($ii = 1; $ii <= $max; $ii++) {
$c = null;
if (isset($report[$ii])) {
$c = $report[$ii];
}
if ($c === -1) {
$str .= 'U'; // Un-covered.
} else if ($c === -2) {
// TODO: This indicates "unreachable", but it flags the closing braces
// of functions which end in "return", which is super ridiculous. Just
// ignore it for now.
//
// See http://bugs.xdebug.org/view.php?id=1041
$str .= 'N'; // Not executable.
} else if ($c === 1) {
$str .= 'C'; // Covered.
} else {
$str .= 'N'; // Not executable.
}
}
$coverage[substr($file, strlen($project_root) + 1)] = $str;
}
// Only keep coverage information for files modified by the change. In
// the case of --everything, we won't have paths, so just return all the
// coverage data.
if ($this->paths) {
$coverage = array_select_keys($coverage, $this->paths);
}
return $coverage;
}
private function assertCoverageAvailable() {
if (!function_exists('xdebug_start_code_coverage')) {
throw new Exception(
pht("You've enabled code coverage but XDebug is not installed."));
}
}
final public function getWorkingCopy() {
return $this->workingCopy;
}
final public function setWorkingCopy(
ArcanistWorkingCopyIdentity $working_copy) {
$this->workingCopy = $working_copy;
return $this;
}
final public function getProjectRoot() {
$working_copy = $this->getWorkingCopy();
if (!$working_copy) {
throw new PhutilInvalidStateException('setWorkingCopy');
}
return $working_copy->getProjectRoot();
}
final public function setPaths(array $paths) {
$this->paths = $paths;
return $this;
}
final protected function getLink($method) {
$base_uri = $this
->getWorkingCopy()
->getProjectConfig('phabricator.uri');
$uri = id(new PhutilURI($base_uri))
->setPath("/diffusion/symbol/{$method}/")
->setQueryParam('context', get_class($this))
->setQueryParam('jump', 'true')
->setQueryParam('lang', 'php');
return (string)$uri;
}
final public function setRenderer(ArcanistUnitRenderer $renderer) {
$this->renderer = $renderer;
return $this;
}
/**
* Returns info about the caller function.
*
* @return map
*/
private static function getCallerInfo() {
$callee = array();
$caller = array();
$seen = false;
foreach (array_slice(debug_backtrace(), 1) as $location) {
$function = idx($location, 'function');
if (!$seen && preg_match('/^assert[A-Z]/', $function)) {
$seen = true;
$caller = $location;
} else if ($seen && !preg_match('/^assert[A-Z]/', $function)) {
$callee = $location;
break;
}
}
return array(
'file' => basename(idx($caller, 'file')),
'line' => idx($caller, 'line'),
'function' => idx($callee, 'function'),
'class' => idx($callee, 'class'),
'object' => idx($caller, 'object'),
'type' => idx($callee, 'type'),
'args' => idx($caller, 'args'),
);
}
/**
* Fail an assertion which checks that some result is equal to a specific
* value, like 'true' or 'false'. This prints a readable error message and
* fails the current test.
*
* This method throws and does not return.
*
* @param string Human readable description of the expected value.
* @param string The actual value.
* @param string|null Optional assertion message.
* @return void
* @task internal
*/
private function failAssertionWithExpectedValue(
$expect_description,
$actual_result,
$message) {
$caller = self::getCallerInfo();
$file = $caller['file'];
$line = $caller['line'];
if ($message !== null) {
$description = pht(
"Assertion failed, expected '%s' (at %s:%d): %s",
$expect_description,
$file,
$line,
$message);
} else {
$description = pht(
"Assertion failed, expected '%s' (at %s:%d).",
$expect_description,
$file,
$line);
}
$actual_result = PhutilReadableSerializer::printableValue($actual_result);
$header = pht('ACTUAL VALUE');
$output = $description."\n\n".$header."\n".$actual_result;
$this->failTest($output);
throw new PhutilTestTerminatedException($output);
}
final protected function assertExecutable($binary) {
if (!isset(self::$executables[$binary])) {
switch ($binary) {
case 'xhpast':
$ok = true;
if (!PhutilXHPASTBinary::isAvailable()) {
try {
PhutilXHPASTBinary::build();
} catch (Exception $ex) {
$ok = false;
}
}
break;
default:
$ok = Filesystem::binaryExists($binary);
break;
}
self::$executables[$binary] = $ok;
}
if (!self::$executables[$binary]) {
$this->assertSkipped(
pht('Required executable "%s" is not available.', $binary));
}
}
final protected function getSupportExecutable($executable) {
$root = dirname(phutil_get_library_root('arcanist'));
return $root.'/support/unit/'.$executable.'.php';
}
}
diff --git a/src/utils/__tests__/PhutilUtilsTestCase.php b/src/utils/__tests__/PhutilUtilsTestCase.php
index 75fe4692..0d4c898f 100644
--- a/src/utils/__tests__/PhutilUtilsTestCase.php
+++ b/src/utils/__tests__/PhutilUtilsTestCase.php
@@ -1,1003 +1,1073 @@
<?php
/**
* Test cases for functions in utils.php.
*/
final class PhutilUtilsTestCase extends PhutilTestCase {
public function testMFilterNullMethodThrowException() {
$caught = null;
try {
mfilter(array(), null);
} catch (InvalidArgumentException $ex) {
$caught = $ex;
}
$this->assertTrue($caught instanceof InvalidArgumentException);
}
public function testMFilterWithEmptyValueFiltered() {
$a = new MFilterTestHelper('o', 'p', 'q');
$b = new MFilterTestHelper('o', '', 'q');
$c = new MFilterTestHelper('o', 'p', 'q');
$list = array(
'a' => $a,
'b' => $b,
'c' => $c,
);
$actual = mfilter($list, 'getI');
$expected = array(
'a' => $a,
'c' => $c,
);
$this->assertEqual($expected, $actual);
}
public function testMFilterWithEmptyValueNegateFiltered() {
$a = new MFilterTestHelper('o', 'p', 'q');
$b = new MFilterTestHelper('o', '', 'q');
$c = new MFilterTestHelper('o', 'p', 'q');
$list = array(
'a' => $a,
'b' => $b,
'c' => $c,
);
$actual = mfilter($list, 'getI', true);
$expected = array(
'b' => $b,
);
$this->assertEqual($expected, $actual);
}
public function testIFilterInvalidIndexThrowException() {
$caught = null;
try {
ifilter(array(), null);
} catch (InvalidArgumentException $ex) {
$caught = $ex;
}
$this->assertTrue($caught instanceof InvalidArgumentException);
}
public function testIFilterWithEmptyValueFiltered() {
$list = array(
'a' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
'b' => array('h' => 'o', 'i' => '', 'j' => 'q'),
'c' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
'd' => array('h' => 'o', 'i' => 0, 'j' => 'q'),
'e' => array('h' => 'o', 'i' => null, 'j' => 'q'),
'f' => array('h' => 'o', 'i' => false, 'j' => 'q'),
);
$actual = ifilter($list, 'i');
$expected = array(
'a' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
'c' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
);
$this->assertEqual($expected, $actual);
}
public function testIFilterIndexNotExistsAllFiltered() {
$list = array(
'a' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
'b' => array('h' => 'o', 'i' => '', 'j' => 'q'),
);
$actual = ifilter($list, 'NoneExisting');
$expected = array();
$this->assertEqual($expected, $actual);
}
public function testIFilterWithEmptyValueNegateFiltered() {
$list = array(
'a' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
'b' => array('h' => 'o', 'i' => '', 'j' => 'q'),
'c' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
'd' => array('h' => 'o', 'i' => 0, 'j' => 'q'),
'e' => array('h' => 'o', 'i' => null, 'j' => 'q'),
'f' => array('h' => 'o', 'i' => false, 'j' => 'q'),
);
$actual = ifilter($list, 'i', true);
$expected = array(
'b' => array('h' => 'o', 'i' => '', 'j' => 'q'),
'd' => array('h' => 'o', 'i' => 0, 'j' => 'q'),
'e' => array('h' => 'o', 'i' => null, 'j' => 'q'),
'f' => array('h' => 'o', 'i' => false, 'j' => 'q'),
);
$this->assertEqual($expected, $actual);
}
public function testIFilterIndexNotExistsNotFiltered() {
$list = array(
'a' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
'b' => array('h' => 'o', 'i' => '', 'j' => 'q'),
);
$actual = ifilter($list, 'NoneExisting', true);
$expected = array(
'a' => array('h' => 'o', 'i' => 'p', 'j' => 'q'),
'b' => array('h' => 'o', 'i' => '', 'j' => 'q'),
);
$this->assertEqual($expected, $actual);
}
public function testmergevMergingBasicallyWorksCorrectly() {
$this->assertEqual(
array(),
array_mergev(
array(
// <empty>
)));
$this->assertEqual(
array(),
array_mergev(
array(
array(),
array(),
array(),
)));
$this->assertEqual(
array(1, 2, 3, 4, 5),
array_mergev(
array(
array(1, 2),
array(3),
array(),
array(4, 5),
)));
$not_valid = array(
'scalar' => array(1),
'array plus scalar' => array(array(), 1),
'null' => array(null),
);
foreach ($not_valid as $key => $invalid_input) {
$caught = null;
try {
array_mergev($invalid_input);
} catch (InvalidArgumentException $ex) {
$caught = $ex;
}
$this->assertTrue(
($caught instanceof InvalidArgumentException),
pht('%s invalid on %s', 'array_mergev()', $key));
}
}
public function testNonempty() {
$this->assertEqual(
'zebra',
nonempty(false, null, 0, '', array(), 'zebra'));
$this->assertEqual(
null,
nonempty());
$this->assertEqual(
false,
nonempty(null, false));
$this->assertEqual(
null,
nonempty(false, null));
}
protected function tryAssertInstancesOfArray($input) {
assert_instances_of($input, 'array');
}
protected function tryAssertInstancesOfStdClass($input) {
assert_instances_of($input, 'stdClass');
}
public function testAssertInstancesOf() {
$object = new stdClass();
$inputs = array(
'empty' => array(),
'stdClass' => array($object, $object),
__CLASS__ => array($object, $this),
'array' => array(array(), array()),
'integer' => array($object, 1),
);
$this->tryTestCases(
$inputs,
array(true, true, false, false, false),
array($this, 'tryAssertInstancesOfStdClass'),
'InvalidArgumentException');
$this->tryTestCases(
$inputs,
array(true, false, false, true, false),
array($this, 'tryAssertInstancesOfArray'),
'InvalidArgumentException');
}
public function testAssertSameKeys() {
$cases = array(
array(true, array(), array()),
array(true, array(0), array(1)),
array(false, array(0), array()),
array(false, array(), array(0)),
array(false, array('a' => 1), array('b' => 1)),
// Make sure "null" values survive "isset()" tests.
array(true, array('a' => 1), array('a' => null)),
// Key order should not matter.
array(true, array('a' => 1, 'b' => 1), array('b' => 1, 'a' => 1)),
);
foreach ($cases as $case) {
list($same_keys, $expect, $input) = $case;
$caught = null;
try {
assert_same_keys($expect, $input);
} catch (InvalidArgumentException $ex) {
$caught = $ex;
}
$this->assertEqual($same_keys, ($caught === null));
}
}
public function testAssertStringLike() {
$this->assertEqual(
null,
assert_stringlike(null));
$this->assertEqual(
null,
assert_stringlike(''));
$this->assertEqual(
null,
assert_stringlike('Hello World'));
$this->assertEqual(
null,
assert_stringlike(1));
$this->assertEqual(
null,
assert_stringlike(9.9999));
$this->assertEqual(
null,
assert_stringlike(true));
$obj = new Exception('.');
$this->assertEqual(
null,
assert_stringlike($obj));
$obj = (object)array();
try {
assert_stringlike($obj);
} catch (InvalidArgumentException $ex) {
$caught = $ex;
}
$this->assertTrue($caught instanceof InvalidArgumentException);
$array = array(
'foo' => 'bar',
'bar' => 'foo',
);
try {
assert_stringlike($array);
} catch (InvalidArgumentException $ex) {
$caught = $ex;
}
$this->assertTrue($caught instanceof InvalidArgumentException);
$tmp = new TempFile();
$resource = fopen($tmp, 'r');
try {
assert_stringlike($resource);
} catch (InvalidArgumentException $ex) {
$caught = $ex;
}
fclose($resource);
$this->assertTrue($caught instanceof InvalidArgumentException);
}
public function testCoalesce() {
$this->assertEqual(
'zebra',
coalesce(null, 'zebra'));
$this->assertEqual(
null,
coalesce());
$this->assertEqual(
false,
coalesce(false, null));
$this->assertEqual(
false,
coalesce(null, false));
}
public function testHeadLast() {
$this->assertEqual(
'a',
head(explode('.', 'a.b')));
$this->assertEqual(
'b',
last(explode('.', 'a.b')));
}
public function testHeadKeyLastKey() {
$this->assertEqual(
'a',
head_key(array('a' => 0, 'b' => 1)));
$this->assertEqual(
'b',
last_key(array('a' => 0, 'b' => 1)));
$this->assertEqual(null, head_key(array()));
$this->assertEqual(null, last_key(array()));
}
public function testID() {
$this->assertEqual(true, id(true));
$this->assertEqual(false, id(false));
}
public function testIdx() {
$array = array(
'present' => true,
'null' => null,
);
$this->assertEqual(true, idx($array, 'present'));
$this->assertEqual(true, idx($array, 'present', false));
$this->assertEqual(null, idx($array, 'null'));
$this->assertEqual(null, idx($array, 'null', false));
$this->assertEqual(null, idx($array, 'missing'));
$this->assertEqual(false, idx($array, 'missing', false));
}
public function testSplitLines() {
$retain_cases = array(
'' => array(''),
'x' => array('x'),
"x\n" => array("x\n"),
"\n" => array("\n"),
"\n\n\n" => array("\n", "\n", "\n"),
"\r\n" => array("\r\n"),
"x\r\ny\n" => array("x\r\n", "y\n"),
"x\ry\nz\r\n" => array("x\ry\n", "z\r\n"),
"x\ry\nz\r\n\n" => array("x\ry\n", "z\r\n", "\n"),
);
foreach ($retain_cases as $input => $expect) {
$this->assertEqual(
$expect,
phutil_split_lines($input, $retain_endings = true),
pht('(Retained) %s', addcslashes($input, "\r\n\\")));
}
$discard_cases = array(
'' => array(''),
'x' => array('x'),
"x\n" => array('x'),
"\n" => array(''),
"\n\n\n" => array('', '', ''),
"\r\n" => array(''),
"x\r\ny\n" => array('x', 'y'),
"x\ry\nz\r\n" => array("x\ry", 'z'),
"x\ry\nz\r\n\n" => array("x\ry", 'z', ''),
);
foreach ($discard_cases as $input => $expect) {
$this->assertEqual(
$expect,
phutil_split_lines($input, $retain_endings = false),
pht('(Discarded) %s', addcslashes($input, "\r\n\\")));
}
}
public function testArrayFuse() {
$this->assertEqual(array(), array_fuse(array()));
$this->assertEqual(array('x' => 'x'), array_fuse(array('x')));
}
public function testArrayInterleave() {
$this->assertEqual(array(), array_interleave('x', array()));
$this->assertEqual(array('y'), array_interleave('x', array('y')));
$this->assertEqual(
array('y', 'x', 'z'),
array_interleave('x', array('y', 'z')));
$this->assertEqual(
array('y', 'x', 'z'),
array_interleave(
'x',
array(
'kangaroo' => 'y',
'marmoset' => 'z',
)));
$obj1 = (object)array();
$obj2 = (object)array();
$this->assertEqual(
array($obj1, $obj2, $obj1, $obj2, $obj1),
array_interleave(
$obj2,
array(
$obj1,
$obj1,
$obj1,
)));
$implode_tests = array(
'' => array(1, 2, 3),
'x' => array(1, 2, 3),
'y' => array(),
'z' => array(1),
);
foreach ($implode_tests as $x => $y) {
$this->assertEqual(
implode('', array_interleave($x, $y)),
implode($x, $y));
}
}
public function testLoggableString() {
$this->assertEqual(
'',
phutil_loggable_string(''));
$this->assertEqual(
"a\\nb",
phutil_loggable_string("a\nb"));
$this->assertEqual(
"a\\x01b",
phutil_loggable_string("a\x01b"));
$this->assertEqual(
"a\\x1Fb",
phutil_loggable_string("a\x1Fb"));
}
public function testPhutilUnits() {
$cases = array(
'0 seconds in seconds' => 0,
'1 second in seconds' => 1,
'2 seconds in seconds' => 2,
'100 seconds in seconds' => 100,
'2 minutes in seconds' => 120,
'1 hour in seconds' => 3600,
'1 day in seconds' => 86400,
'3 days in seconds' => 259200,
'128 bits in bytes' => 16,
'1 byte in bytes' => 1,
'8 bits in bytes' => 1,
'1 minute in milliseconds' => 60000,
'2 minutes in microseconds' => 120000000,
);
foreach ($cases as $input => $expect) {
$this->assertEqual(
$expect,
phutil_units($input),
'phutil_units("'.$input.'")');
}
$bad_cases = array(
'quack',
'3 years in seconds',
'1 day in days',
'-1 minutes in seconds',
'1.5 minutes in seconds',
'7 bits in bytes',
'2 hours in bytes',
'1 dram in bytes',
'24 bits in seconds',
);
foreach ($bad_cases as $input) {
$caught = null;
try {
phutil_units($input);
} catch (InvalidArgumentException $ex) {
$caught = $ex;
}
$this->assertTrue(
($caught instanceof InvalidArgumentException),
'phutil_units("'.$input.'")');
}
}
public function testPhutilJSONDecode() {
$valid_cases = array(
'{}' => array(),
'[]' => array(),
'[1, 2]' => array(1, 2),
'{"a":"b"}' => array('a' => 'b'),
);
foreach ($valid_cases as $input => $expect) {
$result = phutil_json_decode($input);
$this->assertEqual($expect, $result, 'phutil_json_decode('.$input.')');
}
$invalid_cases = array(
'',
'"a"',
'{,}',
'null',
'"null"',
);
foreach ($invalid_cases as $input) {
$caught = null;
try {
phutil_json_decode($input);
} catch (Exception $ex) {
$caught = $ex;
}
$this->assertTrue($caught instanceof PhutilJSONParserException);
}
}
public function testPhutilINIDecode() {
// Skip the test if we are using an older version of PHP that doesn't
// have the `parse_ini_string` function.
try {
phutil_ini_decode('');
} catch (PhutilMethodNotImplementedException $ex) {
$this->assertSkipped($ex->getMessage());
}
$valid_cases = array(
'' => array(),
'foo=' => array('foo' => ''),
'foo=bar' => array('foo' => 'bar'),
'foo = bar' => array('foo' => 'bar'),
"foo = bar\n" => array('foo' => 'bar'),
"foo\nbar = baz" => array('bar' => 'baz'),
"[foo]\nbar = baz" => array('foo' => array('bar' => 'baz')),
"[foo]\n[bar]\nbaz = foo" => array(
'foo' => array(),
'bar' => array('baz' => 'foo'),
),
"[foo]\nbar = baz\n\n[bar]\nbaz = foo" => array(
'foo' => array('bar' => 'baz'),
'bar' => array('baz' => 'foo'),
),
"; Comment\n[foo]\nbar = baz" => array('foo' => array('bar' => 'baz')),
"# Comment\n[foo]\nbar = baz" => array('foo' => array('bar' => 'baz')),
"foo = true\n[bar]\nbaz = false"
=> array('foo' => true, 'bar' => array('baz' => false)),
"foo = 1\nbar = 1.234" => array('foo' => 1, 'bar' => 1.234),
'x = {"foo": "bar"}' => array('x' => '{"foo": "bar"}'),
);
foreach ($valid_cases as $input => $expect) {
$result = phutil_ini_decode($input);
$this->assertEqual($expect, $result, 'phutil_ini_decode('.$input.')');
}
$invalid_cases = array(
'[' => new PhutilINIParserException(),
);
foreach ($invalid_cases as $input => $expect) {
$caught = null;
try {
phutil_ini_decode($input);
} catch (Exception $ex) {
$caught = $ex;
}
$this->assertTrue($caught instanceof $expect);
}
}
public function testCensorCredentials() {
$cases = array(
'' => '',
'abc' => 'abc',
// NOTE: We're liberal about censoring here, since we can't tell
// if this is a truncated password at the end of an input string
// or a domain name. The version with a "/" isn't censored.
'http://example.com' => 'http://********',
'http://example.com/' => 'http://example.com/',
'http://username@example.com' => 'http://********@example.com',
'http://user:pass@example.com' => 'http://********@example.com',
// We censor these because they might be truncated credentials at the end
// of the string.
'http://user' => 'http://********',
"http://user\n" => "http://********\n",
'svn+ssh://user:pass@example.com' => 'svn+ssh://********@example.com',
);
foreach ($cases as $input => $expect) {
$this->assertEqual(
$expect,
phutil_censor_credentials($input),
pht('Credential censoring for: %s', $input));
}
}
public function testVarExport() {
// Constants
$this->assertEqual('null', phutil_var_export(null));
$this->assertEqual('true', phutil_var_export(true));
$this->assertEqual('false', phutil_var_export(false));
$this->assertEqual("'quack'", phutil_var_export('quack'));
$this->assertEqual('1234567', phutil_var_export(1234567));
// Arrays
$this->assertEqual(
'array()',
phutil_var_export(array()));
$this->assertEqual(
implode("\n", array(
'array(',
' 1,',
' 2,',
' 3,',
')',
)),
phutil_var_export(array(1, 2, 3)));
$this->assertEqual(
implode("\n", array(
'array(',
" 'foo' => 'bar',",
" 'bar' => 'baz',",
')',
)),
phutil_var_export(array('foo' => 'bar', 'bar' => 'baz')));
$this->assertEqual(
implode("\n", array(
'array(',
" 'foo' => array(",
" 'bar' => array(",
" 'baz' => array(),",
' ),',
' ),',
')',
)),
phutil_var_export(
array('foo' => array('bar' => array('baz' => array())))));
// NOTE: Object behavior differs across PHP versions. Older versions of
// PHP export objects as "stdClass::__set_state(array())". Newer versions
// of PHP (7.3+) export objects as "(object) array()".
}
public function testFnmatch() {
$cases = array(
'' => array(
array(''),
array('.', '/'),
),
'*' => array(
array('file'),
array('dir/', '/dir'),
),
'**' => array(
array('file', 'dir/', '/dir', 'dir/subdir/file'),
array(),
),
'**/file' => array(
array('file', 'dir/file', 'dir/subdir/file', 'dir/subdir/subdir/file'),
array('file/', 'file/dir'),
),
'file.*' => array(
array('file.php', 'file.a', 'file.'),
array('files.php', 'file.php/blah'),
),
'fo?' => array(
array('foo', 'fot'),
array('fooo', 'ffoo', 'fo/', 'foo/'),
),
'fo{o,t}' => array(
array('foo', 'fot'),
array('fob', 'fo/', 'foo/'),
),
'fo{o,\\,}' => array(
array('foo', 'fo,'),
array('foo/', 'fo,/'),
),
'fo{o,\\\\}' => array(
array('foo', 'fo\\'),
array('foo/', 'fo\\/'),
),
'/foo' => array(
array('/foo'),
array('foo', '/foo/'),
),
// Tests for various `fnmatch` flags.
'*.txt' => array(
array(
'file.txt',
// FNM_PERIOD
'.secret-file.txt',
),
array(
// FNM_PATHNAME
'dir/file.txt',
// FNM_CASEFOLD
'file.TXT',
),
'\\*.txt' => array(
array(
// FNM_NOESCAPE
'*.txt',
),
array(
'file.txt',
),
),
),
);
$invalid = array(
'{',
'asdf\\',
);
foreach ($cases as $input => $expect) {
list($matches, $no_matches) = $expect;
foreach ($matches as $match) {
$this->assertTrue(
phutil_fnmatch($input, $match),
pht('Expecting "%s" to match "%s".', $input, $match));
}
foreach ($no_matches as $no_match) {
$this->assertFalse(
phutil_fnmatch($input, $no_match),
pht('Expecting "%s" not to match "%s".', $input, $no_match));
}
}
foreach ($invalid as $input) {
$caught = null;
try {
phutil_fnmatch($input, '');
} catch (Exception $ex) {
$caught = $ex;
}
$this->assertTrue($caught instanceof InvalidArgumentException);
}
}
public function testJSONEncode() {
$in = array(
'example' => "Not Valid UTF8: \x80",
);
$caught = null;
try {
$value = phutil_json_encode($in);
} catch (Exception $ex) {
$caught = $ex;
}
$this->assertTrue(($caught instanceof Exception));
}
public function testHashComparisons() {
$tests = array(
array('1', '12', false),
array('0', '0e123', false),
array('0e123', '0e124', false),
array('', '0', false),
array('000', '0e0', false),
array('001', '002', false),
array('0', '', false),
array('987654321', '123456789', false),
array('A', 'a', false),
array('123456789', '123456789', true),
array('hunter42', 'hunter42', true),
);
foreach ($tests as $key => $test) {
list($u, $v, $expect) = $test;
$actual = phutil_hashes_are_identical($u, $v);
$this->assertEqual(
$expect,
$actual,
pht('Test Case: "%s" vs "%s"', $u, $v));
}
}
public function testVectorSortInt() {
$original = array(
~PHP_INT_MAX,
-2147483648,
-5,
-3,
-1,
0,
1,
2,
3,
100,
PHP_INT_MAX,
);
$items = $this->shuffleMap($original);
foreach ($items as $key => $value) {
$items[$key] = (string)id(new PhutilSortVector())
->addInt($value);
}
asort($items, SORT_STRING);
$this->assertEqual(
array_keys($original),
array_keys($items));
}
public function testVectorSortString() {
$original = array(
'',
"\1",
'A',
'AB',
'Z',
"Z\1",
'ZZZ',
);
$items = $this->shuffleMap($original);
foreach ($items as $key => $value) {
$items[$key] = (string)id(new PhutilSortVector())
->addString($value);
}
asort($items, SORT_STRING);
$this->assertEqual(
array_keys($original),
array_keys($items));
}
private function shuffleMap(array $map) {
$keys = array_keys($map);
shuffle($keys);
return array_select_keys($map, $keys);
}
public function testQueryStringEncoding() {
$expect = array();
// As a starting point, we expect every character to encode as an "%XX"
// escaped version.
foreach (range(0, 255) as $byte) {
$c = chr($byte);
$expect[$c] = sprintf('%%%02X', $byte);
}
// We expect these characters to not be escaped.
$ranges = array(
range('a', 'z'),
range('A', 'Z'),
range('0', '9'),
array('-', '.', '_', '~'),
);
foreach ($ranges as $range) {
foreach ($range as $preserve_char) {
$expect[$preserve_char] = $preserve_char;
}
}
foreach (range(0, 255) as $byte) {
$c = chr($byte);
$expect_c = $expect[$c];
$expect_str = "{$expect_c}={$expect_c}";
$actual_str = phutil_build_http_querystring(array($c => $c));
$this->assertEqual(
$expect_str,
$actual_str,
pht('HTTP querystring for byte "%s".', sprintf('0x%02x', $byte)));
}
}
public function testNaturalList() {
$cases = array(
array(true, array()),
array(true, array(0 => true, 1 => true, 2 => true)),
array(true, array('a', 'b', 'c')),
array(false, array(0 => true, 2 => true, 1 => true)),
array(false, array(1 => true)),
array(false, array('sound' => 'quack')),
);
foreach ($cases as $case) {
list($expect, $value) = $case;
$this->assertEqual($expect, phutil_is_natural_list($value));
}
}
public function testArrayPartition() {
$map = array(
'empty' => array(
array(),
array(),
),
'unique' => array(
array('a' => 'a', 'b' => 'b', 'c' => 'c'),
array(array('a' => 'a'), array('b' => 'b'), array('c' => 'c')),
),
'xy' => array(
array('a' => 'x', 'b' => 'x', 'c' => 'y', 'd' => 'y'),
array(
array('a' => 'x', 'b' => 'x'),
array('c' => 'y', 'd' => 'y'),
),
),
'multi' => array(
array('a' => true, 'b' => true, 'c' => false, 'd' => true),
array(
array('a' => true, 'b' => true),
array('c' => false),
array('d' => true),
),
),
);
foreach ($map as $name => $item) {
list($input, $expect) = $item;
$actual = phutil_partition($input);
$this->assertEqual($expect, $actual, pht('Partition of "%s"', $name));
}
}
+ public function testEmptyStringMethods() {
+
+ $uri = new PhutilURI('http://example.org/');
+
+ $map = array(
+ array(null, false, false, false, 'literal null'),
+ array('', false, false, false, 'empty string'),
+ array('x', true, true, true, 'nonempty string'),
+ array(false, null, null, null, 'bool'),
+ array(1, null, null, true, 'integer'),
+ array($uri, null, true, true, 'uri object'),
+ array(2.5, null, null, true, 'float'),
+ array(array(), null, null, null, 'array'),
+ array((object)array(), null, null, null, 'object'),
+ );
+
+ foreach ($map as $test_case) {
+ $input = $test_case[0];
+
+ $expect_string = $test_case[1];
+ $expect_stringlike = $test_case[2];
+ $expect_scalar = $test_case[3];
+
+ $test_name = $test_case[4];
+
+ $this->executeEmptyStringTest(
+ $input,
+ $expect_string,
+ 'phutil_nonempty_string',
+ $test_name);
+
+ $this->executeEmptyStringTest(
+ $input,
+ $expect_stringlike,
+ 'phutil_nonempty_stringlike',
+ $test_name);
+
+ $this->executeEmptyStringTest(
+ $input,
+ $expect_scalar,
+ 'phutil_nonempty_scalar',
+ $test_name);
+ }
+
+ }
+
+ private function executeEmptyStringTest($input, $expect, $call, $name) {
+ $name = sprintf('%s(<%s>)', $call, $name);
+
+ $caught = null;
+ try {
+ $actual = call_user_func($call, $input);
+ } catch (Exception $ex) {
+ $caught = $ex;
+ } catch (Throwable $ex) {
+ $caught = $ex;
+ }
+
+ if ($expect === null) {
+ $expect_exceptions = array('InvalidArgumentException');
+ } else {
+ $expect_exceptions = false;
+ }
+
+ $this->assertCaught($expect_exceptions, $caught, $name);
+ if (!$caught) {
+ $this->assertEqual($expect, $actual, $name);
+ }
+ }
+
}
diff --git a/src/utils/utils.php b/src/utils/utils.php
index cbc4d5fb..3bcaab02 100644
--- a/src/utils/utils.php
+++ b/src/utils/utils.php
@@ -1,2096 +1,2221 @@
<?php
/**
* Identity function, returns its argument unmodified.
*
* This is useful almost exclusively as a workaround to an oddity in the PHP
* grammar -- this is a syntax error:
*
* COUNTEREXAMPLE
* new Thing()->doStuff();
*
* ...but this works fine:
*
* id(new Thing())->doStuff();
*
* @param wild Anything.
* @return wild Unmodified argument.
*/
function id($x) {
return $x;
}
/**
* Access an array index, retrieving the value stored there if it exists or
* a default if it does not. This function allows you to concisely access an
* index which may or may not exist without raising a warning.
*
* @param array Array to access.
* @param scalar Index to access in the array.
* @param wild Default value to return if the key is not present in the
* array.
* @return wild If `$array[$key]` exists, that value is returned. If not,
* $default is returned without raising a warning.
*/
function idx(array $array, $key, $default = null) {
// isset() is a micro-optimization - it is fast but fails for null values.
if (isset($array[$key])) {
return $array[$key];
}
// Comparing $default is also a micro-optimization.
if ($default === null || array_key_exists($key, $array)) {
return null;
}
return $default;
}
/**
* Access a sequence of array indexes, retrieving a deeply nested value if
* it exists or a default if it does not.
*
* For example, `idxv($dict, array('a', 'b', 'c'))` accesses the key at
* `$dict['a']['b']['c']`, if it exists. If it does not, or any intermediate
* value is not itself an array, it returns the defualt value.
*
* @param array Array to access.
* @param list<string> List of keys to access, in sequence.
* @param wild Default value to return.
* @return wild Accessed value, or default if the value is not accessible.
*/
function idxv(array $map, array $path, $default = null) {
if (!$path) {
return $default;
}
$last = last($path);
$path = array_slice($path, 0, -1);
$cursor = $map;
foreach ($path as $key) {
$cursor = idx($cursor, $key);
if (!is_array($cursor)) {
return $default;
}
}
return idx($cursor, $last, $default);
}
/**
* Call a method on a list of objects. Short for "method pull", this function
* works just like @{function:ipull}, except that it operates on a list of
* objects instead of a list of arrays. This function simplifies a common type
* of mapping operation:
*
* COUNTEREXAMPLE
* $names = array();
* foreach ($objects as $key => $object) {
* $names[$key] = $object->getName();
* }
*
* You can express this more concisely with mpull():
*
* $names = mpull($objects, 'getName');
*
* mpull() takes a third argument, which allows you to do the same but for
* the array's keys:
*
* COUNTEREXAMPLE
* $names = array();
* foreach ($objects as $object) {
* $names[$object->getID()] = $object->getName();
* }
*
* This is the mpull version():
*
* $names = mpull($objects, 'getName', 'getID');
*
* If you pass ##null## as the second argument, the objects will be preserved:
*
* COUNTEREXAMPLE
* $id_map = array();
* foreach ($objects as $object) {
* $id_map[$object->getID()] = $object;
* }
*
* With mpull():
*
* $id_map = mpull($objects, null, 'getID');
*
* See also @{function:ipull}, which works similarly but accesses array indexes
* instead of calling methods.
*
* @param list Some list of objects.
* @param string|null Determines which **values** will appear in the result
* array. Use a string like 'getName' to store the
* value of calling the named method in each value, or
* ##null## to preserve the original objects.
* @param string|null Determines how **keys** will be assigned in the result
* array. Use a string like 'getID' to use the result
* of calling the named method as each object's key, or
* `null` to preserve the original keys.
* @return dict A dictionary with keys and values derived according
* to whatever you passed as `$method` and `$key_method`.
*/
function mpull(array $list, $method, $key_method = null) {
$result = array();
foreach ($list as $key => $object) {
if ($key_method !== null) {
$key = $object->$key_method();
}
if ($method !== null) {
$value = $object->$method();
} else {
$value = $object;
}
$result[$key] = $value;
}
return $result;
}
/**
* Access a property on a list of objects. Short for "property pull", this
* function works just like @{function:mpull}, except that it accesses object
* properties instead of methods. This function simplifies a common type of
* mapping operation:
*
* COUNTEREXAMPLE
* $names = array();
* foreach ($objects as $key => $object) {
* $names[$key] = $object->name;
* }
*
* You can express this more concisely with ppull():
*
* $names = ppull($objects, 'name');
*
* ppull() takes a third argument, which allows you to do the same but for
* the array's keys:
*
* COUNTEREXAMPLE
* $names = array();
* foreach ($objects as $object) {
* $names[$object->id] = $object->name;
* }
*
* This is the ppull version():
*
* $names = ppull($objects, 'name', 'id');
*
* If you pass ##null## as the second argument, the objects will be preserved:
*
* COUNTEREXAMPLE
* $id_map = array();
* foreach ($objects as $object) {
* $id_map[$object->id] = $object;
* }
*
* With ppull():
*
* $id_map = ppull($objects, null, 'id');
*
* See also @{function:mpull}, which works similarly but calls object methods
* instead of accessing object properties.
*
* @param list Some list of objects.
* @param string|null Determines which **values** will appear in the result
* array. Use a string like 'name' to store the value of
* accessing the named property in each value, or
* `null` to preserve the original objects.
* @param string|null Determines how **keys** will be assigned in the result
* array. Use a string like 'id' to use the result of
* accessing the named property as each object's key, or
* `null` to preserve the original keys.
* @return dict A dictionary with keys and values derived according
* to whatever you passed as `$property` and
* `$key_property`.
*/
function ppull(array $list, $property, $key_property = null) {
$result = array();
foreach ($list as $key => $object) {
if ($key_property !== null) {
$key = $object->$key_property;
}
if ($property !== null) {
$value = $object->$property;
} else {
$value = $object;
}
$result[$key] = $value;
}
return $result;
}
/**
* Choose an index from a list of arrays. Short for "index pull", this function
* works just like @{function:mpull}, except that it operates on a list of
* arrays and selects an index from them instead of operating on a list of
* objects and calling a method on them.
*
* This function simplifies a common type of mapping operation:
*
* COUNTEREXAMPLE
* $names = array();
* foreach ($list as $key => $dict) {
* $names[$key] = $dict['name'];
* }
*
* With ipull():
*
* $names = ipull($list, 'name');
*
* See @{function:mpull} for more usage examples.
*
* @param list Some list of arrays.
* @param scalar|null Determines which **values** will appear in the result
* array. Use a scalar to select that index from each
* array, or null to preserve the arrays unmodified as
* values.
* @param scalar|null Determines which **keys** will appear in the result
* array. Use a scalar to select that index from each
* array, or null to preserve the array keys.
* @return dict A dictionary with keys and values derived according
* to whatever you passed for `$index` and `$key_index`.
*/
function ipull(array $list, $index, $key_index = null) {
$result = array();
foreach ($list as $key => $array) {
if ($key_index !== null) {
$key = $array[$key_index];
}
if ($index !== null) {
$value = $array[$index];
} else {
$value = $array;
}
$result[$key] = $value;
}
return $result;
}
/**
* Group a list of objects by the result of some method, similar to how
* GROUP BY works in an SQL query. This function simplifies grouping objects
* by some property:
*
* COUNTEREXAMPLE
* $animals_by_species = array();
* foreach ($animals as $animal) {
* $animals_by_species[$animal->getSpecies()][] = $animal;
* }
*
* This can be expressed more tersely with mgroup():
*
* $animals_by_species = mgroup($animals, 'getSpecies');
*
* In either case, the result is a dictionary which maps species (e.g., like
* "dog") to lists of animals with that property, so all the dogs are grouped
* together and all the cats are grouped together, or whatever super
* businessesey thing is actually happening in your problem domain.
*
* See also @{function:igroup}, which works the same way but operates on
* array indexes.
*
* @param list List of objects to group by some property.
* @param string Name of a method, like 'getType', to call on each object
* in order to determine which group it should be placed into.
* @param ... Zero or more additional method names, to subgroup the
* groups.
* @return dict Dictionary mapping distinct method returns to lists of
* all objects which returned that value.
*/
function mgroup(array $list, $by /* , ... */) {
$map = mpull($list, $by);
$groups = array();
foreach ($map as $group) {
// Can't array_fill_keys() here because 'false' gets encoded wrong.
$groups[$group] = array();
}
foreach ($map as $key => $group) {
$groups[$group][$key] = $list[$key];
}
$args = func_get_args();
$args = array_slice($args, 2);
if ($args) {
array_unshift($args, null);
foreach ($groups as $group_key => $grouped) {
$args[0] = $grouped;
$groups[$group_key] = call_user_func_array('mgroup', $args);
}
}
return $groups;
}
/**
* Group a list of arrays by the value of some index. This function is the same
* as @{function:mgroup}, except it operates on the values of array indexes
* rather than the return values of method calls.
*
* @param list List of arrays to group by some index value.
* @param string Name of an index to select from each array in order to
* determine which group it should be placed into.
* @param ... Zero or more additional indexes names, to subgroup the
* groups.
* @return dict Dictionary mapping distinct index values to lists of
* all objects which had that value at the index.
*/
function igroup(array $list, $by /* , ... */) {
$map = ipull($list, $by);
$groups = array();
foreach ($map as $group) {
$groups[$group] = array();
}
foreach ($map as $key => $group) {
$groups[$group][$key] = $list[$key];
}
$args = func_get_args();
$args = array_slice($args, 2);
if ($args) {
array_unshift($args, null);
foreach ($groups as $group_key => $grouped) {
$args[0] = $grouped;
$groups[$group_key] = call_user_func_array('igroup', $args);
}
}
return $groups;
}
/**
* Sort a list of objects by the return value of some method. In PHP, this is
* often vastly more efficient than `usort()` and similar.
*
* // Sort a list of Duck objects by name.
* $sorted = msort($ducks, 'getName');
*
* It is usually significantly more efficient to define an ordering method
* on objects and call `msort()` than to write a comparator. It is often more
* convenient, as well.
*
* NOTE: This method does not take the list by reference; it returns a new list.
*
* @param list List of objects to sort by some property.
* @param string Name of a method to call on each object; the return values
* will be used to sort the list.
* @return list Objects ordered by the return values of the method calls.
*/
function msort(array $list, $method) {
$surrogate = mpull($list, $method);
// See T13303. A "PhutilSortVector" is technically a sortable object, so
// a method which returns a "PhutilSortVector" is suitable for use with
// "msort()". However, it's almost certain that the caller intended to use
// "msortv()", not "msort()", and forgot to add a "v". Treat this as an error.
if ($surrogate) {
$item = head($surrogate);
if ($item instanceof PhutilSortVector) {
throw new Exception(
pht(
'msort() was passed a method ("%s") which returns '.
'"PhutilSortVector" objects. Use "msortv()", not "msort()", to '.
'sort a list which produces vectors.',
$method));
}
}
asort($surrogate);
$result = array();
foreach ($surrogate as $key => $value) {
$result[$key] = $list[$key];
}
return $result;
}
/**
* Sort a list of objects by a sort vector.
*
* This sort is stable, well-behaved, and more efficient than `usort()`.
*
* @param list List of objects to sort.
* @param string Name of a method to call on each object. The method must
* return a @{class:PhutilSortVector}.
* @return list Objects ordered by the vectors.
*/
function msortv(array $list, $method) {
return msortv_internal($list, $method, SORT_STRING);
}
function msortv_natural(array $list, $method) {
return msortv_internal($list, $method, SORT_NATURAL | SORT_FLAG_CASE);
}
function msortv_internal(array $list, $method, $flags) {
$surrogate = mpull($list, $method);
$index = 0;
foreach ($surrogate as $key => $value) {
if (!($value instanceof PhutilSortVector)) {
throw new Exception(
pht(
'Objects passed to "%s" must return sort vectors (objects of '.
'class "%s") from the specified method ("%s"). One object (with '.
'key "%s") did not.',
'msortv()',
'PhutilSortVector',
$method,
$key));
}
// Add the original index to keep the sort stable.
$value->addInt($index++);
$surrogate[$key] = (string)$value;
}
asort($surrogate, $flags);
$result = array();
foreach ($surrogate as $key => $value) {
$result[$key] = $list[$key];
}
return $result;
}
/**
* Sort a list of arrays by the value of some index. This method is identical to
* @{function:msort}, but operates on a list of arrays instead of a list of
* objects.
*
* @param list List of arrays to sort by some index value.
* @param string Index to access on each object; the return values
* will be used to sort the list.
* @return list Arrays ordered by the index values.
*/
function isort(array $list, $index) {
$surrogate = ipull($list, $index);
asort($surrogate);
$result = array();
foreach ($surrogate as $key => $value) {
$result[$key] = $list[$key];
}
return $result;
}
/**
* Filter a list of objects by executing a method across all the objects and
* filter out the ones with empty() results. this function works just like
* @{function:ifilter}, except that it operates on a list of objects instead
* of a list of arrays.
*
* For example, to remove all objects with no children from a list, where
* 'hasChildren' is a method name, do this:
*
* mfilter($list, 'hasChildren');
*
* The optional third parameter allows you to negate the operation and filter
* out nonempty objects. To remove all objects that DO have children, do this:
*
* mfilter($list, 'hasChildren', true);
*
* @param array List of objects to filter.
* @param string A method name.
* @param bool Optionally, pass true to drop objects which pass the
* filter instead of keeping them.
* @return array List of objects which pass the filter.
*/
function mfilter(array $list, $method, $negate = false) {
if (!is_string($method)) {
throw new InvalidArgumentException(pht('Argument method is not a string.'));
}
$result = array();
foreach ($list as $key => $object) {
$value = $object->$method();
if (!$negate) {
if (!empty($value)) {
$result[$key] = $object;
}
} else {
if (empty($value)) {
$result[$key] = $object;
}
}
}
return $result;
}
/**
* Filter a list of arrays by removing the ones with an empty() value for some
* index. This function works just like @{function:mfilter}, except that it
* operates on a list of arrays instead of a list of objects.
*
* For example, to remove all arrays without value for key 'username', do this:
*
* ifilter($list, 'username');
*
* The optional third parameter allows you to negate the operation and filter
* out nonempty arrays. To remove all arrays that DO have value for key
* 'username', do this:
*
* ifilter($list, 'username', true);
*
* @param array List of arrays to filter.
* @param scalar The index.
* @param bool Optionally, pass true to drop arrays which pass the
* filter instead of keeping them.
* @return array List of arrays which pass the filter.
*/
function ifilter(array $list, $index, $negate = false) {
if (!is_scalar($index)) {
throw new InvalidArgumentException(pht('Argument index is not a scalar.'));
}
$result = array();
if (!$negate) {
foreach ($list as $key => $array) {
if (!empty($array[$index])) {
$result[$key] = $array;
}
}
} else {
foreach ($list as $key => $array) {
if (empty($array[$index])) {
$result[$key] = $array;
}
}
}
return $result;
}
/**
* Selects a list of keys from an array, returning a new array with only the
* key-value pairs identified by the selected keys, in the specified order.
*
* Note that since this function orders keys in the result according to the
* order they appear in the list of keys, there are effectively two common
* uses: either reducing a large dictionary to a smaller one, or changing the
* key order on an existing dictionary.
*
* @param dict Dictionary of key-value pairs to select from.
* @param list List of keys to select.
* @return dict Dictionary of only those key-value pairs where the key was
* present in the list of keys to select. Ordering is
* determined by the list order.
*/
function array_select_keys(array $dict, array $keys) {
$result = array();
foreach ($keys as $key) {
if (array_key_exists($key, $dict)) {
$result[$key] = $dict[$key];
}
}
return $result;
}
/**
* Checks if all values of array are instances of the passed class. Throws
* `InvalidArgumentException` if it isn't true for any value.
*
* @param array
* @param string Name of the class or 'array' to check arrays.
* @return array Returns passed array.
*/
function assert_instances_of(array $arr, $class) {
$is_array = !strcasecmp($class, 'array');
foreach ($arr as $key => $object) {
if ($is_array) {
if (!is_array($object)) {
$given = gettype($object);
throw new InvalidArgumentException(
pht(
"Array item with key '%s' must be of type array, %s given.",
$key,
$given));
}
} else if (!($object instanceof $class)) {
$given = gettype($object);
if (is_object($object)) {
$given = pht('instance of %s', get_class($object));
}
throw new InvalidArgumentException(
pht(
"Array item with key '%s' must be an instance of %s, %s given.",
$key,
$class,
$given));
}
}
return $arr;
}
/**
* Assert that two arrays have the exact same keys, in any order.
*
* @param map Array with expected keys.
* @param map Array with actual keys.
* @return void
*/
function assert_same_keys(array $expect, array $actual) {
foreach ($expect as $key => $value) {
if (isset($actual[$key]) || array_key_exists($key, $actual)) {
continue;
}
throw new InvalidArgumentException(
pht(
'Expected to find key "%s", but it is not present.',
$key));
}
foreach ($actual as $key => $value) {
if (isset($expect[$key]) || array_key_exists($key, $expect)) {
continue;
}
throw new InvalidArgumentException(
pht(
'Found unexpected surplus key "%s" where no such key was expected.',
$key));
}
}
/**
* Assert that passed data can be converted to string.
*
* @param string Assert that this data is valid.
* @return void
*
* @task assert
*/
function assert_stringlike($parameter) {
switch (gettype($parameter)) {
case 'string':
case 'NULL':
case 'boolean':
case 'double':
case 'integer':
return;
case 'object':
if (method_exists($parameter, '__toString')) {
return;
}
break;
case 'array':
case 'resource':
case 'unknown type':
default:
break;
}
throw new InvalidArgumentException(
pht(
'Argument must be scalar or object which implements %s!',
'__toString()'));
}
/**
* Returns the first argument which is not strictly null, or `null` if there
* are no such arguments. Identical to the MySQL function of the same name.
*
* @param ... Zero or more arguments of any type.
* @return mixed First non-`null` arg, or null if no such arg exists.
*/
function coalesce(/* ... */) {
$args = func_get_args();
foreach ($args as $arg) {
if ($arg !== null) {
return $arg;
}
}
return null;
}
/**
* Similar to @{function:coalesce}, but less strict: returns the first
* non-`empty()` argument, instead of the first argument that is strictly
* non-`null`. If no argument is nonempty, it returns the last argument. This
* is useful idiomatically for setting defaults:
*
* $display_name = nonempty($user_name, $full_name, "Anonymous");
*
* @param ... Zero or more arguments of any type.
* @return mixed First non-`empty()` arg, or last arg if no such arg
* exists, or null if you passed in zero args.
*/
function nonempty(/* ... */) {
$args = func_get_args();
$result = null;
foreach ($args as $arg) {
$result = $arg;
if ($arg) {
break;
}
}
return $result;
}
/**
* Invokes the "new" operator with a vector of arguments. There is no way to
* `call_user_func_array()` on a class constructor, so you can instead use this
* function:
*
* $obj = newv($class_name, $argv);
*
* That is, these two statements are equivalent:
*
* $pancake = new Pancake('Blueberry', 'Maple Syrup', true);
* $pancake = newv('Pancake', array('Blueberry', 'Maple Syrup', true));
*
* DO NOT solve this problem in other, more creative ways! Three popular
* alternatives are:
*
* - Build a fake serialized object and unserialize it.
* - Invoke the constructor twice.
* - just use `eval()` lol
*
* These are really bad solutions to the problem because they can have side
* effects (e.g., __wakeup()) and give you an object in an otherwise impossible
* state. Please endeavor to keep your objects in possible states.
*
* If you own the classes you're doing this for, you should consider whether
* or not restructuring your code (for instance, by creating static
* construction methods) might make it cleaner before using `newv()`. Static
* constructors can be invoked with `call_user_func_array()`, and may give your
* class a cleaner and more descriptive API.
*
* @param string The name of a class.
* @param list Array of arguments to pass to its constructor.
* @return obj A new object of the specified class, constructed by passing
* the argument vector to its constructor.
*/
function newv($class_name, array $argv) {
$reflector = new ReflectionClass($class_name);
if ($argv) {
return $reflector->newInstanceArgs($argv);
} else {
return $reflector->newInstance();
}
}
/**
* Returns the first element of an array. Exactly like reset(), but doesn't
* choke if you pass it some non-referenceable value like the return value of
* a function.
*
* @param array Array to retrieve the first element from.
* @return wild The first value of the array.
*/
function head(array $arr) {
return reset($arr);
}
/**
* Returns the last element of an array. This is exactly like `end()` except
* that it won't warn you if you pass some non-referencable array to
* it -- e.g., the result of some other array operation.
*
* @param array Array to retrieve the last element from.
* @return wild The last value of the array.
*/
function last(array $arr) {
return end($arr);
}
/**
* Returns the first key of an array.
*
* @param array Array to retrieve the first key from.
* @return int|string The first key of the array.
*/
function head_key(array $arr) {
reset($arr);
return key($arr);
}
/**
* Returns the last key of an array.
*
* @param array Array to retrieve the last key from.
* @return int|string The last key of the array.
*/
function last_key(array $arr) {
end($arr);
return key($arr);
}
/**
* Merge a vector of arrays performantly. This has the same semantics as
* array_merge(), so these calls are equivalent:
*
* array_merge($a, $b, $c);
* array_mergev(array($a, $b, $c));
*
* However, when you have a vector of arrays, it is vastly more performant to
* merge them with this function than by calling array_merge() in a loop,
* because using a loop generates an intermediary array on each iteration.
*
* @param list Vector of arrays to merge.
* @return list Arrays, merged with array_merge() semantics.
*/
function array_mergev(array $arrayv) {
if (!$arrayv) {
return array();
}
foreach ($arrayv as $key => $item) {
if (!is_array($item)) {
throw new InvalidArgumentException(
pht(
'Expected all items passed to "array_mergev()" to be arrays, but '.
'argument with key "%s" has type "%s".',
$key,
gettype($item)));
}
}
// See T13588. In PHP8, "call_user_func_array()" will attempt to use
// "unnatural" array keys as named parameters, and then fail because
// "array_merge()" does not accept named parameters . Guarantee the list is
// a "natural" list to avoid this.
$arrayv = array_values($arrayv);
return call_user_func_array('array_merge', $arrayv);
}
/**
* Split a corpus of text into lines. This function splits on "\n", "\r\n", or
* a mixture of any of them.
*
* NOTE: This function does not treat "\r" on its own as a newline because none
* of SVN, Git or Mercurial do on any OS.
*
* @param string Block of text to be split into lines.
* @param bool If true, retain line endings in result strings.
* @return list List of lines.
*
* @phutil-external-symbol class PhutilSafeHTML
* @phutil-external-symbol function phutil_safe_html
*/
function phutil_split_lines($corpus, $retain_endings = true) {
if (!strlen($corpus)) {
return array('');
}
// Split on "\r\n" or "\n".
if ($retain_endings) {
$lines = preg_split('/(?<=\n)/', $corpus);
} else {
$lines = preg_split('/\r?\n/', $corpus);
}
// If the text ends with "\n" or similar, we'll end up with an empty string
// at the end; discard it.
if (end($lines) == '') {
array_pop($lines);
}
if ($corpus instanceof PhutilSafeHTML) {
foreach ($lines as $key => $line) {
$lines[$key] = phutil_safe_html($line);
}
return $lines;
}
return $lines;
}
/**
* Simplifies a common use of `array_combine()`. Specifically, this:
*
* COUNTEREXAMPLE:
* if ($list) {
* $result = array_combine($list, $list);
* } else {
* // Prior to PHP 5.4, array_combine() failed if given empty arrays.
* $result = array();
* }
*
* ...is equivalent to this:
*
* $result = array_fuse($list);
*
* @param list List of scalars.
* @return dict Dictionary with inputs mapped to themselves.
*/
function array_fuse(array $list) {
if ($list) {
return array_combine($list, $list);
}
return array();
}
/**
* Add an element between every two elements of some array. That is, given a
* list `A, B, C, D`, and some element to interleave, `x`, this function returns
* `A, x, B, x, C, x, D`. This works like `implode()`, but does not concatenate
* the list into a string. In particular:
*
* implode('', array_interleave($x, $list));
*
* ...is equivalent to:
*
* implode($x, $list);
*
* This function does not preserve keys.
*
* @param wild Element to interleave.
* @param list List of elements to be interleaved.
* @return list Original list with the new element interleaved.
*/
function array_interleave($interleave, array $array) {
$result = array();
foreach ($array as $item) {
$result[] = $item;
$result[] = $interleave;
}
array_pop($result);
return $result;
}
function phutil_is_windows() {
// We can also use PHP_OS, but that's kind of sketchy because it returns
// "WINNT" for Windows 7 and "Darwin" for Mac OS X. Practically, testing for
// DIRECTORY_SEPARATOR is more straightforward.
return (DIRECTORY_SEPARATOR != '/');
}
function phutil_is_hiphop_runtime() {
return (array_key_exists('HPHP', $_ENV) && $_ENV['HPHP'] === 1);
}
/**
* Converts a string to a loggable one, with unprintables and newlines escaped.
*
* @param string Any string.
* @return string String with control and newline characters escaped, suitable
* for printing on a single log line.
*/
function phutil_loggable_string($string) {
if (preg_match('/^[\x20-\x7E]+$/', $string)) {
return $string;
}
$result = '';
static $c_map = array(
'\\' => '\\\\',
"\n" => '\\n',
"\r" => '\\r',
"\t" => '\\t',
);
$len = strlen($string);
for ($ii = 0; $ii < $len; $ii++) {
$c = $string[$ii];
if (isset($c_map[$c])) {
$result .= $c_map[$c];
} else {
$o = ord($c);
if ($o < 0x20 || $o >= 0x7F) {
$result .= '\\x'.sprintf('%02X', $o);
} else {
$result .= $c;
}
}
}
return $result;
}
/**
* Perform an `fwrite()` which distinguishes between EAGAIN and EPIPE.
*
* PHP's `fwrite()` is broken, and never returns `false` for writes to broken
* nonblocking pipes: it always returns 0, and provides no straightforward
* mechanism for distinguishing between EAGAIN (buffer is full, can't write any
* more right now) and EPIPE or similar (no write will ever succeed).
*
* See: https://bugs.php.net/bug.php?id=39598
*
* If you call this method instead of `fwrite()`, it will attempt to detect
* when a zero-length write is caused by EAGAIN and return `0` only if the
* write really should be retried.
*
* @param resource Socket or pipe stream.
* @param string Bytes to write.
* @return bool|int Number of bytes written, or `false` on any error (including
* errors which `fwrite()` can not detect, like a broken pipe).
*/
function phutil_fwrite_nonblocking_stream($stream, $bytes) {
if (!strlen($bytes)) {
return 0;
}
$result = @fwrite($stream, $bytes);
if ($result !== 0) {
// In cases where some bytes are witten (`$result > 0`) or
// an error occurs (`$result === false`), the behavior of fwrite() is
// correct. We can return the value as-is.
return $result;
}
// If we make it here, we performed a 0-length write. Try to distinguish
// between EAGAIN and EPIPE. To do this, we're going to `stream_select()`
// the stream, write to it again if PHP claims that it's writable, and
// consider the pipe broken if the write fails.
// (Signals received during the "fwrite()" do not appear to affect anything,
// see D20083.)
$read = array();
$write = array($stream);
$except = array();
$result = @stream_select($read, $write, $except, 0);
if ($result === false) {
// See T13243. If the select is interrupted by a signal, it may return
// "false" indicating an underlying EINTR condition. In this case, the
// results (notably, "$write") are not usable because "stream_select()"
// didn't update them.
// In this case, treat this stream as blocked and tell the caller to
// retry, since EINTR is the only condition we're currently aware of that
// can cause "fwrite()" to return "0" and "stream_select()" to return
// "false" on the same stream.
return 0;
}
if (!$write) {
// The stream isn't writable, so we conclude that it probably really is
// blocked and the underlying error was EAGAIN. Return 0 to indicate that
// no data could be written yet.
return 0;
}
// If we make it here, PHP **just** claimed that this stream is writable, so
// perform a write. If the write also fails, conclude that these failures are
// EPIPE or some other permanent failure.
$result = @fwrite($stream, $bytes);
if ($result !== 0) {
// The write worked or failed explicitly. This value is fine to return.
return $result;
}
// We performed a 0-length write, were told that the stream was writable, and
// then immediately performed another 0-length write. Conclude that the pipe
// is broken and return `false`.
return false;
}
/**
* Convert a human-readable unit description into a numeric one. This function
* allows you to replace this:
*
* COUNTEREXAMPLE
* $ttl = (60 * 60 * 24 * 30); // 30 days
*
* ...with this:
*
* $ttl = phutil_units('30 days in seconds');
*
* ...which is self-documenting and difficult to make a mistake with.
*
* @param string Human readable description of a unit quantity.
* @return int Quantity of specified unit.
*/
function phutil_units($description) {
$matches = null;
if (!preg_match('/^(\d+) (\w+) in (\w+)$/', $description, $matches)) {
throw new InvalidArgumentException(
pht(
'Unable to parse unit specification (expected a specification in the '.
'form "%s"): %s',
'5 days in seconds',
$description));
}
$quantity = (int)$matches[1];
$src_unit = $matches[2];
$dst_unit = $matches[3];
$is_divisor = false;
switch ($dst_unit) {
case 'seconds':
switch ($src_unit) {
case 'second':
case 'seconds':
$factor = 1;
break;
case 'minute':
case 'minutes':
$factor = 60;
break;
case 'hour':
case 'hours':
$factor = 60 * 60;
break;
case 'day':
case 'days':
$factor = 60 * 60 * 24;
break;
default:
throw new InvalidArgumentException(
pht(
'This function can not convert from the unit "%s".',
$src_unit));
}
break;
case 'bytes':
switch ($src_unit) {
case 'byte':
case 'bytes':
$factor = 1;
break;
case 'bit':
case 'bits':
$factor = 8;
$is_divisor = true;
break;
default:
throw new InvalidArgumentException(
pht(
'This function can not convert from the unit "%s".',
$src_unit));
}
break;
case 'milliseconds':
switch ($src_unit) {
case 'second':
case 'seconds':
$factor = 1000;
break;
case 'minute':
case 'minutes':
$factor = 1000 * 60;
break;
case 'hour':
case 'hours':
$factor = 1000 * 60 * 60;
break;
case 'day':
case 'days':
$factor = 1000 * 60 * 60 * 24;
break;
default:
throw new InvalidArgumentException(
pht(
'This function can not convert from the unit "%s".',
$src_unit));
}
break;
case 'microseconds':
switch ($src_unit) {
case 'second':
case 'seconds':
$factor = 1000000;
break;
case 'minute':
case 'minutes':
$factor = 1000000 * 60;
break;
case 'hour':
case 'hours':
$factor = 1000000 * 60 * 60;
break;
case 'day':
case 'days':
$factor = 1000000 * 60 * 60 * 24;
break;
default:
throw new InvalidArgumentException(
pht(
'This function can not convert from the unit "%s".',
$src_unit));
}
break;
default:
throw new InvalidArgumentException(
pht(
'This function can not convert into the unit "%s".',
$dst_unit));
}
if ($is_divisor) {
if ($quantity % $factor) {
throw new InvalidArgumentException(
pht(
'"%s" is not an exact quantity.',
$description));
}
return (int)($quantity / $factor);
} else {
return $quantity * $factor;
}
}
/**
* Compute the number of microseconds that have elapsed since an earlier
* timestamp (from `microtime(true)`).
*
* @param double Microsecond-precision timestamp, from `microtime(true)`.
* @return int Elapsed microseconds.
*/
function phutil_microseconds_since($timestamp) {
if (!is_float($timestamp)) {
throw new Exception(
pht(
'Argument to "phutil_microseconds_since(...)" should be a value '.
'returned from "microtime(true)".'));
}
$delta = (microtime(true) - $timestamp);
$delta = 1000000 * $delta;
$delta = (int)$delta;
return $delta;
}
/**
* Decode a JSON dictionary.
*
* @param string A string which ostensibly contains a JSON-encoded list or
* dictionary.
* @return mixed Decoded list/dictionary.
*/
function phutil_json_decode($string) {
$result = @json_decode($string, true);
if (!is_array($result)) {
// Failed to decode the JSON. Try to use @{class:PhutilJSONParser} instead.
// This will probably fail, but will throw a useful exception.
$parser = new PhutilJSONParser();
$result = $parser->parse($string);
}
return $result;
}
/**
* Encode a value in JSON, raising an exception if it can not be encoded.
*
* @param wild A value to encode.
* @return string JSON representation of the value.
*/
function phutil_json_encode($value) {
$result = @json_encode($value);
if ($result === false) {
$reason = phutil_validate_json($value);
if (function_exists('json_last_error')) {
$err = json_last_error();
if (function_exists('json_last_error_msg')) {
$msg = json_last_error_msg();
$extra = pht('#%d: %s', $err, $msg);
} else {
$extra = pht('#%d', $err);
}
} else {
$extra = null;
}
if ($extra) {
$message = pht(
'Failed to JSON encode value (%s): %s.',
$extra,
$reason);
} else {
$message = pht(
'Failed to JSON encode value: %s.',
$reason);
}
throw new Exception($message);
}
return $result;
}
/**
* Produce a human-readable explanation why a value can not be JSON-encoded.
*
* @param wild Value to validate.
* @param string Path within the object to provide context.
* @return string|null Explanation of why it can't be encoded, or null.
*/
function phutil_validate_json($value, $path = '') {
if ($value === null) {
return;
}
if ($value === true) {
return;
}
if ($value === false) {
return;
}
if (is_int($value)) {
return;
}
if (is_float($value)) {
return;
}
if (is_array($value)) {
foreach ($value as $key => $subvalue) {
if (strlen($path)) {
$full_key = $path.' > ';
} else {
$full_key = '';
}
if (!phutil_is_utf8($key)) {
$full_key = $full_key.phutil_utf8ize($key);
return pht(
'Dictionary key "%s" is not valid UTF8, and cannot be JSON encoded.',
$full_key);
}
$full_key .= $key;
$result = phutil_validate_json($subvalue, $full_key);
if ($result !== null) {
return $result;
}
}
}
if (is_string($value)) {
if (!phutil_is_utf8($value)) {
$display = substr($value, 0, 256);
$display = phutil_utf8ize($display);
if (!strlen($path)) {
return pht(
'String value is not valid UTF8, and can not be JSON encoded: %s',
$display);
} else {
return pht(
'Dictionary value at key "%s" is not valid UTF8, and cannot be '.
'JSON encoded: %s',
$path,
$display);
}
}
}
return;
}
/**
* Decode an INI string.
*
* @param string
* @return mixed
*/
function phutil_ini_decode($string) {
$results = null;
$trap = new PhutilErrorTrap();
try {
$have_call = false;
if (function_exists('parse_ini_string')) {
if (defined('INI_SCANNER_RAW')) {
$results = @parse_ini_string($string, true, INI_SCANNER_RAW);
$have_call = true;
}
}
if (!$have_call) {
throw new PhutilMethodNotImplementedException(
pht(
'%s is not compatible with your version of PHP (%s). This function '.
'is only supported on PHP versions newer than 5.3.0.',
__FUNCTION__,
phpversion()));
}
if ($results === false) {
throw new PhutilINIParserException(trim($trap->getErrorsAsString()));
}
foreach ($results as $section => $result) {
if (!is_array($result)) {
// We JSON decode the value in ordering to perform the following
// conversions:
//
// - `'true'` => `true`
// - `'false'` => `false`
// - `'123'` => `123`
// - `'1.234'` => `1.234`
//
$result = json_decode($result, true);
if ($result !== null && !is_array($result)) {
$results[$section] = $result;
}
continue;
}
foreach ($result as $key => $value) {
$value = json_decode($value, true);
if ($value !== null && !is_array($value)) {
$results[$section][$key] = $value;
}
}
}
} catch (Exception $ex) {
$trap->destroy();
throw $ex;
}
$trap->destroy();
return $results;
}
/**
* Attempt to censor any plaintext credentials from a string.
*
* The major use case here is to censor usernames and passwords from command
* output. For example, when `git fetch` fails, the output includes credentials
* for authenticated HTTP remotes.
*
* @param string Some block of text.
* @return string A similar block of text, but with credentials that could
* be identified censored.
*/
function phutil_censor_credentials($string) {
return preg_replace(',(?<=://)([^/@\s]+)(?=@|$),', '********', $string);
}
/**
* Returns a parsable string representation of a variable.
*
* This function is intended to behave similarly to PHP's `var_export` function,
* but the output is intended to follow our style conventions.
*
* @param wild The variable you want to export.
* @return string
*/
function phutil_var_export($var) {
// `var_export(null, true)` returns `"NULL"` (in uppercase).
if ($var === null) {
return 'null';
}
// PHP's `var_export` doesn't format arrays very nicely. In particular:
//
// - An empty array is split over two lines (`"array (\n)"`).
// - A space separates "array" and the first opening brace.
// - Non-associative arrays are returned as associative arrays with an
// integer key.
//
if (is_array($var)) {
if (count($var) === 0) {
return 'array()';
}
// Don't show keys for non-associative arrays.
$show_keys = !phutil_is_natural_list($var);
$output = array();
$output[] = 'array(';
foreach ($var as $key => $value) {
// Adjust the indentation of the value.
$value = str_replace("\n", "\n ", phutil_var_export($value));
$output[] = ' '.
($show_keys ? var_export($key, true).' => ' : '').
$value.',';
}
$output[] = ')';
return implode("\n", $output);
}
// Let PHP handle everything else.
return var_export($var, true);
}
/**
* An improved version of `fnmatch`.
*
* @param string A glob pattern.
* @param string A path.
* @return bool
*/
function phutil_fnmatch($glob, $path) {
// Modify the glob to allow `**/` to match files in the root directory.
$glob = preg_replace('@(?:(?<!\\\\)\\*){2}/@', '{,*/,**/}', $glob);
$escaping = false;
$in_curlies = 0;
$regex = '';
for ($i = 0; $i < strlen($glob); $i++) {
$char = $glob[$i];
$next_char = ($i < strlen($glob) - 1) ? $glob[$i + 1] : null;
$escape = array('$', '(', ')', '+', '.', '^', '|');
$mapping = array();
if ($escaping) {
$escape[] = '*';
$escape[] = '?';
$escape[] = '{';
} else {
$mapping['*'] = $next_char === '*' ? '.*' : '[^/]*';
$mapping['?'] = '[^/]';
$mapping['{'] = '(';
if ($in_curlies) {
$mapping[','] = '|';
$mapping['}'] = ')';
}
}
if (in_array($char, $escape)) {
$regex .= "\\{$char}";
} else if ($replacement = idx($mapping, $char)) {
$regex .= $replacement;
} else if ($char === '\\') {
if ($escaping) {
$regex .= '\\\\';
}
$escaping = !$escaping;
continue;
} else {
$regex .= $char;
}
if ($char === '{' && !$escaping) {
$in_curlies++;
} else if ($char === '}' && $in_curlies && !$escaping) {
$in_curlies--;
}
$escaping = false;
}
if ($in_curlies || $escaping) {
throw new InvalidArgumentException(pht('Invalid glob pattern.'));
}
$regex = '(\A'.$regex.'\z)';
return (bool)preg_match($regex, $path);
}
/**
* Compare two hashes for equality.
*
* This function defuses two attacks: timing attacks and type juggling attacks.
*
* In a timing attack, the attacker observes that strings which match the
* secret take slightly longer to fail to match because more characters are
* compared. By testing a large number of strings, they can learn the secret
* character by character. This defuses timing attacks by always doing the
* same amount of work.
*
* In a type juggling attack, an attacker takes advantage of PHP's type rules
* where `"0" == "0e12345"` for any exponent. A portion of of hexadecimal
* hashes match this pattern and are vulnerable. This defuses this attack by
* performing bytewise character-by-character comparison.
*
* It is questionable how practical these attacks are, but they are possible
* in theory and defusing them is straightforward.
*
* @param string First hash.
* @param string Second hash.
* @return bool True if hashes are identical.
*/
function phutil_hashes_are_identical($u, $v) {
if (!is_string($u)) {
throw new Exception(pht('First hash argument must be a string.'));
}
if (!is_string($v)) {
throw new Exception(pht('Second hash argument must be a string.'));
}
if (strlen($u) !== strlen($v)) {
return false;
}
$len = strlen($v);
$bits = 0;
for ($ii = 0; $ii < $len; $ii++) {
$bits |= (ord($u[$ii]) ^ ord($v[$ii]));
}
return ($bits === 0);
}
/**
* Build a query string from a dictionary.
*
* @param map<string, string> Dictionary of parameters.
* @return string HTTP query string.
*/
function phutil_build_http_querystring(array $parameters) {
$pairs = array();
foreach ($parameters as $key => $value) {
$pairs[] = array($key, $value);
}
return phutil_build_http_querystring_from_pairs($pairs);
}
/**
* Build a query string from a list of parameter pairs.
*
* @param list<pair<string, string>> List of pairs.
* @return string HTTP query string.
*/
function phutil_build_http_querystring_from_pairs(array $pairs) {
// We want to encode in RFC3986 mode, but "http_build_query()" did not get
// a flag for that mode until PHP 5.4.0. This is equivalent to calling
// "http_build_query()" with the "PHP_QUERY_RFC3986" flag.
$query = array();
foreach ($pairs as $pair_key => $pair) {
if (!is_array($pair) || (count($pair) !== 2)) {
throw new Exception(
pht(
'HTTP parameter pair (with key "%s") is not valid: each pair must '.
'be an array with exactly two elements.',
$pair_key));
}
list($key, $value) = $pair;
list($key, $value) = phutil_http_parameter_pair($key, $value);
$query[] = rawurlencode($key).'='.rawurlencode($value);
}
$query = implode('&', $query);
return $query;
}
/**
* Typecheck and cast an HTTP key-value parameter pair.
*
* Scalar values are converted to strings. Nonscalar values raise exceptions.
*
* @param scalar HTTP parameter key.
* @param scalar HTTP parameter value.
* @return pair<string, string> Key and value as strings.
*/
function phutil_http_parameter_pair($key, $value) {
try {
assert_stringlike($key);
} catch (InvalidArgumentException $ex) {
throw new PhutilProxyException(
pht('HTTP query parameter key must be a scalar.'),
$ex);
}
$key = phutil_string_cast($key);
try {
assert_stringlike($value);
} catch (InvalidArgumentException $ex) {
throw new PhutilProxyException(
pht(
'HTTP query parameter value (for key "%s") must be a scalar.',
$key),
$ex);
}
$value = phutil_string_cast($value);
return array($key, $value);
}
function phutil_decode_mime_header($header) {
if (function_exists('iconv_mime_decode')) {
return iconv_mime_decode($header, 0, 'UTF-8');
}
if (function_exists('mb_decode_mimeheader')) {
return mb_decode_mimeheader($header);
}
throw new Exception(
pht(
'Unable to decode MIME header: install "iconv" or "mbstring" '.
'extension.'));
}
/**
* Perform a "(string)" cast without disabling standard exception behavior.
*
* When PHP invokes "__toString()" automatically, it fatals if the method
* raises an exception. In older versions of PHP (until PHP 7.1), this fatal is
* fairly opaque and does not give you any information about the exception
* itself, although newer versions of PHP at least include the exception
* message.
*
* This is documented on the "__toString()" manual page:
*
* Warning
* You cannot throw an exception from within a __toString() method. Doing
* so will result in a fatal error.
*
* However, this only applies to implicit invocation by the language runtime.
* Application code can safely call `__toString()` directly without any effect
* on exception handling behavior. Very cool.
*
* We also reject arrays. PHP casts them to the string "Array". This behavior
* is, charitably, evil.
*
* @param wild Any value which aspires to be represented as a string.
* @return string String representation of the provided value.
*/
function phutil_string_cast($value) {
if (is_array($value)) {
throw new Exception(
pht(
'Value passed to "phutil_string_cast()" is an array; arrays can '.
'not be sensibly cast to strings.'));
}
if (is_object($value)) {
$string = $value->__toString();
if (!is_string($string)) {
throw new Exception(
pht(
'Object (of class "%s") did not return a string from "__toString()".',
get_class($value)));
}
return $string;
}
return (string)$value;
}
/**
* Return a short, human-readable description of an object's type.
*
* This is mostly useful for raising errors like "expected x() to return a Y,
* but it returned a Z".
*
* This is similar to "get_type()", but describes objects and arrays in more
* detail.
*
* @param wild Anything.
* @return string Human-readable description of the value's type.
*/
function phutil_describe_type($value) {
return PhutilTypeSpec::getTypeOf($value);
}
/**
* Test if a list has the natural numbers (1, 2, 3, and so on) as keys, in
* order.
*
* @return bool True if the list is a natural list.
*/
function phutil_is_natural_list(array $list) {
$expect = 0;
foreach ($list as $key => $item) {
if ($key !== $expect) {
return false;
}
$expect++;
}
return true;
}
/**
* Escape text for inclusion in a URI or a query parameter. Note that this
* method does NOT escape '/', because "%2F" is invalid in paths and Apache
* will automatically 404 the page if it's present. This will produce correct
* (the URIs will work) and desirable (the URIs will be readable) behavior in
* these cases:
*
* '/path/?param='.phutil_escape_uri($string); # OK: Query Parameter
* '/path/to/'.phutil_escape_uri($string); # OK: URI Suffix
*
* It will potentially produce the WRONG behavior in this special case:
*
* COUNTEREXAMPLE
* '/path/to/'.phutil_escape_uri($string).'/thing/'; # BAD: URI Infix
*
* In this case, any '/' characters in the string will not be escaped, so you
* will not be able to distinguish between the string and the suffix (unless
* you have more information, like you know the format of the suffix). For infix
* URI components, use @{function:phutil_escape_uri_path_component} instead.
*
* @param string Some string.
* @return string URI encoded string, except for '/'.
*/
function phutil_escape_uri($string) {
return str_replace('%2F', '/', rawurlencode($string));
}
/**
* Escape text for inclusion as an infix URI substring. See discussion at
* @{function:phutil_escape_uri}. This function covers an unusual special case;
* @{function:phutil_escape_uri} is usually the correct function to use.
*
* This function will escape a string into a format which is safe to put into
* a URI path and which does not contain '/' so it can be correctly parsed when
* embedded as a URI infix component.
*
* However, you MUST decode the string with
* @{function:phutil_unescape_uri_path_component} before it can be used in the
* application.
*
* @param string Some string.
* @return string URI encoded string that is safe for infix composition.
*/
function phutil_escape_uri_path_component($string) {
return rawurlencode(rawurlencode($string));
}
/**
* Unescape text that was escaped by
* @{function:phutil_escape_uri_path_component}. See
* @{function:phutil_escape_uri} for discussion.
*
* Note that this function is NOT the inverse of
* @{function:phutil_escape_uri_path_component}! It undoes additional escaping
* which is added to survive the implied unescaping performed by the webserver
* when interpreting the request.
*
* @param string Some string emitted
* from @{function:phutil_escape_uri_path_component} and
* then accessed via a web server.
* @return string Original string.
*/
function phutil_unescape_uri_path_component($string) {
return rawurldecode($string);
}
function phutil_is_noninteractive() {
if (function_exists('posix_isatty') && !posix_isatty(STDIN)) {
return true;
}
return false;
}
function phutil_is_interactive() {
if (function_exists('posix_isatty') && posix_isatty(STDIN)) {
return true;
}
return false;
}
function phutil_encode_log($message) {
return addcslashes($message, "\0..\37\\\177..\377");
}
/**
* Insert a value in between each pair of elements in a list.
*
* Keys in the input list are preserved.
*/
function phutil_glue(array $list, $glue) {
if (!$list) {
return $list;
}
$last_key = last_key($list);
$keys = array();
$values = array();
$tmp = $list;
foreach ($list as $key => $ignored) {
$keys[] = $key;
if ($key !== $last_key) {
$tmp[] = $glue;
$keys[] = last_key($tmp);
}
}
return array_select_keys($tmp, $keys);
}
function phutil_partition(array $map) {
$partitions = array();
$partition = array();
$is_first = true;
$partition_value = null;
foreach ($map as $key => $value) {
if (!$is_first) {
if ($partition_value === $value) {
$partition[$key] = $value;
continue;
}
$partitions[] = $partition;
}
$is_first = false;
$partition = array($key => $value);
$partition_value = $value;
}
if ($partition) {
$partitions[] = $partition;
}
return $partitions;
}
function phutil_preg_match(
$pattern,
$subject,
$flags = 0,
$offset = 0) {
$matches = null;
$result = @preg_match($pattern, $subject, $matches, $flags, $offset);
if ($result === false || $result === null) {
phutil_raise_preg_exception(
'preg_match',
array(
$pattern,
$subject,
$matches,
$flags,
$offset,
));
}
return $matches;
}
function phutil_preg_match_all(
$pattern,
$subject,
$flags = 0,
$offset = 0) {
$matches = null;
$result = @preg_match_all($pattern, $subject, $matches, $flags, $offset);
if ($result === false || $result === null) {
phutil_raise_preg_exception(
'preg_match_all',
array(
$pattern,
$subject,
$matches,
$flags,
$offset,
));
}
return $matches;
}
function phutil_raise_preg_exception($function, array $argv) {
$trap = new PhutilErrorTrap();
// NOTE: This ugly construction to avoid issues with reference behavior when
// passing values through "call_user_func_array()".
switch ($function) {
case 'preg_match':
@preg_match($argv[0], $argv[1], $argv[2], $argv[3], $argv[4]);
break;
case 'preg_match_all':
@preg_match_all($argv[0], $argv[1], $argv[2], $argv[3], $argv[4]);
break;
}
$error_message = $trap->getErrorsAsString();
$trap->destroy();
$pattern = $argv[0];
$pattern_display = sprintf(
'"%s"',
addcslashes($pattern, '\\\"'));
$message = array();
$message[] = pht(
'Call to %s(%s, ...) failed.',
$function,
$pattern_display);
if (strlen($error_message)) {
$message[] = pht(
'Regular expression engine emitted message: %s',
$error_message);
}
$message = implode("\n\n", $message);
throw new PhutilRegexException($message);
}
+
+
+/**
+ * Test if a value is a nonempty string.
+ *
+ * The value "null" and the empty string are considered empty; all other
+ * strings are considered nonempty.
+ *
+ * This method raises an exception if passed a value which is neither null
+ * nor a string.
+ *
+ * @param Value to test.
+ * @return bool True if the parameter is a nonempty string.
+ */
+function phutil_nonempty_string($value) {
+ if ($value === null) {
+ return false;
+ }
+
+ if ($value === '') {
+ return false;
+ }
+
+ if (is_string($value)) {
+ return true;
+ }
+
+ throw new InvalidArgumentException(
+ pht(
+ 'Call to phutil_nonempty_string() expected null or a string, got: %s.',
+ phutil_describe_type($value)));
+}
+
+
+/**
+ * Test if a value is a nonempty, stringlike value.
+ *
+ * The value "null", the empty string, and objects which have a "__toString()"
+ * method which returns the empty string are empty.
+ *
+ * Other strings, and objects with a "__toString()" method that returns a
+ * string other than the empty string are considered nonempty.
+ *
+ * This method raises an exception if passed any other value.
+ *
+ * @param Value to test.
+ * @return bool True if the parameter is a nonempty, stringlike value.
+ */
+function phutil_nonempty_stringlike($value) {
+ if ($value === null) {
+ return false;
+ }
+
+ if ($value === '') {
+ return false;
+ }
+
+ if (is_string($value)) {
+ return true;
+ }
+
+ if (is_object($value)) {
+ try {
+ $string = phutil_string_cast($value);
+ return phutil_nonempty_string($string);
+ } catch (Exception $ex) {
+ // Continue below.
+ } catch (Throwable $ex) {
+ // Continue below.
+ }
+ }
+
+ throw new InvalidArgumentException(
+ pht(
+ 'Call to phutil_nonempty_stringlike() expected a string or stringlike '.
+ 'object, got: %s.',
+ phutil_describe_type($value)));
+}
+
+
+/**
+ * Test if a value is a nonempty, scalar value.
+ *
+ * The value "null", the empty string, and objects which have a "__toString()"
+ * method which returns the empty string are empty.
+ *
+ * Other strings, objects with a "__toString()" method which returns a
+ * string other than the empty string, integers, and floats are considered
+ * scalar.
+ *
+ * This method raises an exception if passed any other value.
+ *
+ * @param Value to test.
+ * @return bool True if the parameter is a nonempty, scalar value.
+ */
+function phutil_nonempty_scalar($value) {
+ if ($value === null) {
+ return false;
+ }
+
+ if ($value === '') {
+ return false;
+ }
+
+ if (is_string($value) || is_int($value) || is_float($value)) {
+ return true;
+ }
+
+ if (is_object($value)) {
+ try {
+ $string = phutil_string_cast($value);
+ return phutil_nonempty_string($string);
+ } catch (Exception $ex) {
+ // Continue below.
+ } catch (Throwable $ex) {
+ // Continue below.
+ }
+ }
+
+ throw new InvalidArgumentException(
+ pht(
+ 'Call to phutil_nonempty_scalar() expected: a string; or stringlike '.
+ 'object; or int; or float. Got: %s.',
+ phutil_describe_type($value)));
+}

File Metadata

Mime Type
text/x-diff
Expires
Sun, May 11, 07:49 (1 d, 10 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1222187
Default Alt Text
(262 KB)

Event Timeline