From 861e94cf9dc2638eb628c6bf5fb449fc5d4fc9b4 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Mon, 21 May 2018 00:23:56 +0200 Subject: [PATCH] Add latest changes from icehrm pro --- bower.json | 4 +- build.xml | 5 +- .../employees/customTemplates/myDetails.html | 32 +- core/admin/fieldnames/meta.json | 8 +- core/admin/travel/index.php | 30 +- core/config.base.php | 8 +- core/configureUIManager.php | 6 + core/header.php | 10 +- core/includes.inc.php | 2 +- core/lang/de.po | 306 + core/lang/en.po | 306 + core/lang/es.po | 306 + core/lang/fr.po | 306 + core/lang/it.po | 1142 +- core/lang/ja.po | 306 + core/lang/pl.po | 306 + core/lang/zh.po | 668 +- core/lib/Mail/RFC822.php | 951 + core/lib/Mail/mail.php | 168 + core/lib/Mail/mock.php | 143 + core/lib/Mail/null.php | 84 + core/lib/Mail/sendmail.php | 171 + core/lib/Mail/smtp.php | 444 + core/lib/Mail/smtpmx.php | 502 + core/lib/composer/composer.json | 5 +- core/lib/composer/composer.lock | 273 +- core/lib/composer/vendor/autoload.php | 2 +- .../composer/vendor/bin/export-plural-rules | 5 +- .../vendor/bin/export-plural-rules.php | 235 +- core/lib/composer/vendor/bin/markdown | 170 + core/lib/composer/vendor/bin/phpunit | 54 +- core/lib/composer/vendor/bin/robo | 23 +- .../vendor/cebe/markdown/.gitattributes | 6 + .../composer/vendor/cebe/markdown/.gitignore | 4 + .../vendor/cebe/markdown/.scrutinizer.yml | 6 + .../composer/vendor/cebe/markdown/.travis.yml | 42 + .../vendor/cebe/markdown/CHANGELOG.md | 104 + .../vendor/cebe/markdown/CONTRIBUTING.md | 36 + .../vendor/cebe/markdown/GithubMarkdown.php | 114 + .../lib/composer/vendor/cebe/markdown/LICENSE | 21 + .../vendor/cebe/markdown/Markdown.php | 128 + .../vendor/cebe/markdown/MarkdownExtra.php | 256 + .../composer/vendor/cebe/markdown/Parser.php | 389 + .../composer/vendor/cebe/markdown/README.md | 521 + .../vendor/cebe/markdown/bin/markdown | 170 + .../vendor/cebe/markdown/block/CodeTrait.php | 66 + .../cebe/markdown/block/FencedCodeTrait.php | 58 + .../cebe/markdown/block/HeadlineTrait.php | 70 + .../vendor/cebe/markdown/block/HtmlTrait.php | 168 + .../vendor/cebe/markdown/block/ListTrait.php | 202 + .../vendor/cebe/markdown/block/QuoteTrait.php | 63 + .../vendor/cebe/markdown/block/RuleTrait.php | 40 + .../vendor/cebe/markdown/block/TableTrait.php | 156 + .../vendor/cebe/markdown/composer.json | 42 + .../vendor/cebe/markdown/inline/CodeTrait.php | 45 + .../cebe/markdown/inline/EmphStrongTrait.php | 87 + .../vendor/cebe/markdown/inline/LinkTrait.php | 287 + .../cebe/markdown/inline/StrikeoutTrait.php | 40 + .../cebe/markdown/inline/UrlLinkTrait.php | 50 + .../vendor/cebe/markdown/phpunit.xml.dist | 27 + .../cebe/markdown/tests/BaseMarkdownTest.php | 115 + .../markdown/tests/GithubMarkdownTest.php | 80 + .../cebe/markdown/tests/MarkdownExtraTest.php | 24 + .../markdown/tests/MarkdownOLStartNumTest.php | 32 + .../cebe/markdown/tests/MarkdownTest.php | 60 + .../vendor/cebe/markdown/tests/ParserTest.php | 94 + .../vendor/cebe/markdown/tests/bootstrap.php | 5 + .../tests/extra-data/code_in_lists.html | 82 + .../tests/extra-data/code_in_lists.md | 94 + .../tests/extra-data/fenced-code.html | 17 + .../markdown/tests/extra-data/fenced-code.md | 24 + .../markdown/tests/extra-data/non-tables.html | 8 + .../markdown/tests/extra-data/non-tables.md | 13 + .../tests/extra-data/special-attributes.html | 12 + .../tests/extra-data/special-attributes.md | 25 + .../markdown/tests/extra-data/tables.html | 219 + .../cebe/markdown/tests/extra-data/tables.md | 130 + .../tests/extra-data/test_precedence.html | 8 + .../tests/extra-data/test_precedence.md | 14 + .../tests/github-data/code_in_lists.html | 82 + .../tests/github-data/code_in_lists.md | 94 + .../cebe/markdown/tests/github-data/del.html | 5 + .../cebe/markdown/tests/github-data/del.md | 9 + .../github-data/dense-block-markers.html | 52 + .../tests/github-data/dense-block-markers.md | 56 + .../github-data/dense-block-markers2.html | 23 + .../tests/github-data/dense-block-markers2.md | 27 + .../tests/github-data/github-basics.html | 19 + .../tests/github-data/github-basics.md | 40 + .../github-code-in-numbered-list.html | 12 + .../github-code-in-numbered-list.md | 14 + .../tests/github-data/github-sample.html | 117 + .../tests/github-data/github-sample.md | 159 + .../markdown/tests/github-data/issue-33.html | 5 + .../markdown/tests/github-data/issue-33.md | 6 + .../markdown/tests/github-data/issue-38.html | 21 + .../markdown/tests/github-data/issue-38.md | 26 + .../markdown/tests/github-data/issue-50.html | 9 + .../markdown/tests/github-data/issue-50.md | 5 + .../markdown/tests/github-data/lists.html | 16 + .../cebe/markdown/tests/github-data/lists.md | 12 + .../tests/github-data/non-tables.html | 8 + .../markdown/tests/github-data/non-tables.md | 13 + .../markdown/tests/github-data/tables.html | 203 + .../cebe/markdown/tests/github-data/tables.md | 122 + .../tests/github-data/test_precedence.html | 8 + .../tests/github-data/test_precedence.md | 14 + .../cebe/markdown/tests/github-data/url.html | 17 + .../cebe/markdown/tests/github-data/url.md | 33 + .../cebe/markdown/tests/markdown-data/README | 1 + .../markdown-data/blockquote-nested.html | 11 + .../tests/markdown-data/blockquote-nested.md | 10 + .../tests/markdown-data/blockquote.html | 9 + .../tests/markdown-data/blockquote.md | 10 + .../markdown/tests/markdown-data/code.html | 17 + .../cebe/markdown/tests/markdown-data/code.md | 27 + .../markdown-data/dense-block-markers.html | 50 + .../markdown-data/dense-block-markers.md | 56 + .../markdown/tests/markdown-data/dos.html | 2549 ++ .../cebe/markdown/tests/markdown-data/dos.md | 2549 ++ .../markdown/tests/markdown-data/dos2.html | 2549 ++ .../cebe/markdown/tests/markdown-data/dos2.md | 2549 ++ .../tests/markdown-data/emphasis.html | 34 + .../markdown/tests/markdown-data/emphasis.md | 65 + .../tests/markdown-data/empty-line.html | 8 + .../tests/markdown-data/empty-line.md | 11 + .../tests/markdown-data/endless_loop_bug.html | 9 + .../tests/markdown-data/endless_loop_bug.md | 12 + .../tests/markdown-data/escape-in-link.html | 3 + .../tests/markdown-data/escape-in-link.md | 7 + .../tests/markdown-data/headline.html | 21 + .../markdown/tests/markdown-data/headline.md | 41 + .../cebe/markdown/tests/markdown-data/hr.html | 15 + .../cebe/markdown/tests/markdown-data/hr.md | 29 + .../tests/markdown-data/html-block.html | 42 + .../tests/markdown-data/html-block.md | 59 + .../markdown/tests/markdown-data/images.html | 14 + .../markdown/tests/markdown-data/images.md | 22 + .../tests/markdown-data/inline-html.html | 11 + .../tests/markdown-data/inline-html.md | 19 + .../tests/markdown-data/lazy-list.html | 43 + .../markdown/tests/markdown-data/lazy-list.md | 40 + .../markdown/tests/markdown-data/links.html | 14 + .../markdown/tests/markdown-data/links.md | 25 + .../list-marker-in-paragraph.html | 7 + .../markdown-data/list-marker-in-paragraph.md | 8 + .../markdown-data/list-separated-by-hr.html | 7 + .../markdown-data/list-separated-by-hr.md | 3 + .../markdown/tests/markdown-data/list.html | 59 + .../cebe/markdown/tests/markdown-data/list.md | 60 + .../markdown-data/list_and_reference.html | 9 + .../tests/markdown-data/list_and_reference.md | 13 + .../list_items_with_undefined_ref.html | 14 + .../list_items_with_undefined_ref.md | 11 + .../md1_amps_and_angle_encoding.html | 8 + .../md1_amps_and_angle_encoding.md | 19 + .../tests/markdown-data/md1_auto_links.html | 12 + .../tests/markdown-data/md1_auto_links.md | 13 + .../markdown-data/md1_backslash_escapes.html | 67 + .../markdown-data/md1_backslash_escapes.md | 104 + .../md1_blockquotes_with_code_blocks.html | 11 + .../md1_blockquotes_with_code_blocks.md | 11 + .../markdown-data/md1_horizontal_rules.html | 39 + .../markdown-data/md1_horizontal_rules.md | 67 + .../md1_inline_html_avanced.html | 11 + .../markdown-data/md1_inline_html_avanced.md | 14 + .../md1_inline_html_comments.html | 8 + .../markdown-data/md1_inline_html_comments.md | 13 + .../markdown-data/md1_inline_html_simple.html | 46 + .../markdown-data/md1_inline_html_simple.md | 69 + .../markdown-data/md1_links_inline_style.html | 5 + .../markdown-data/md1_links_inline_style.md | 9 + .../md1_links_reference_style.html | 10 + .../md1_links_reference_style.md | 31 + .../md1_literal_quotes_in_titles.html | 2 + .../md1_literal_quotes_in_titles.md | 7 + .../md1_markdown_documentation_basics.html | 243 + .../md1_markdown_documentation_basics.md | 306 + .../markdown-data/md1_nested_blockquotes.html | 5 + .../markdown-data/md1_nested_blockquotes.md | 5 + .../md1_ordered_and_unordered_lists.html | 125 + .../md1_ordered_and_unordered_lists.md | 123 + .../md1_strong_and_em_together.html | 4 + .../md1_strong_and_em_together.md | 7 + .../tests/markdown-data/md1_tabs.html | 21 + .../markdown/tests/markdown-data/md1_tabs.md | 21 + .../tests/markdown-data/md1_tidyness.html | 7 + .../tests/markdown-data/md1_tidyness.md | 5 + .../tests/markdown-data/nested-lists.html | 150 + .../tests/markdown-data/nested-lists.md | 123 + .../markdown/tests/markdown-data/newline.html | 3 + .../markdown/tests/markdown-data/newline.md | 4 + .../tests/markdown-data/paragraph.html | 3 + .../markdown/tests/markdown-data/paragraph.md | 4 + .../tests/markdown-data/references.html | 11 + .../tests/markdown-data/references.md | 27 + .../markdown/tests/markdown-data/specs.html | 717 + .../markdown/tests/markdown-data/specs.md | 899 + .../tests/markdown-data/test_precedence.html | 5 + .../tests/markdown-data/test_precedence.md | 8 + .../markdown/tests/markdown-data/unicode.html | 13 + .../markdown/tests/markdown-data/unicode.md | 21 + .../utf8-do-not-kill-characters.html | 3 + .../utf8-do-not-kill-characters.md | 5 + .../markdown-ol-start-num-data/list.html | 23 + .../tests/markdown-ol-start-num-data/list.md | 21 + .../md1_ordered_and_unordered_lists.html | 66 + .../md1_ordered_and_unordered_lists.md | 62 + .../vendor/cebe/markdown/tests/profile.php | 31 + .../composer/vendor/composer/ClassLoader.php | 60 +- core/lib/composer/vendor/composer/LICENSE | 2 +- .../vendor/composer/autoload_classmap.php | 2 +- .../vendor/composer/autoload_namespaces.php | 1 + .../vendor/composer/autoload_psr4.php | 2 + .../vendor/composer/autoload_real.php | 6 +- .../vendor/composer/autoload_static.php | 25 +- .../vendor/composer/include_paths.php | 2 +- .../composer/vendor/composer/installed.json | 394 +- .../config/scenarios/symfony2/src | 1 - .../config/scenarios/symfony2/src/Config.php | 157 + .../symfony2/src/ConfigInterface.php | 105 + .../GlobalOptionDefaultValuesInterface.php | 10 + .../symfony2/src/Inject/ConfigForCommand.php | 127 + .../symfony2/src/Inject/ConfigForSetters.php | 47 + .../symfony2/src/Loader/ConfigLoader.php | 35 + .../src/Loader/ConfigLoaderInterface.php | 29 + .../symfony2/src/Loader/ConfigProcessor.php | 167 + .../symfony2/src/Loader/YamlConfigLoader.php | 26 + .../scenarios/symfony2/src/Util/ArrayUtil.php | 75 + .../symfony2/src/Util/ConfigFallback.php | 51 + .../symfony2/src/Util/ConfigGroup.php | 61 + .../symfony2/src/Util/ConfigMerge.php | 34 + .../symfony2/src/Util/ConfigOverlay.php | 203 + .../scenarios/symfony2/src/Util/EnvConfig.php | 96 + .../config/scenarios/symfony2/tests | 1 - .../symfony2/tests/ConfigForCommandTest.php | 130 + .../symfony2/tests/ConfigForSettersTest.php | 87 + .../symfony2/tests/ConfigGroupTest.php | 91 + .../symfony2/tests/ConfigLoaderTest.php | 29 + .../symfony2/tests/ConfigOverlayTest.php | 168 + .../symfony2/tests/ConfigProcessorTest.php | 152 + .../scenarios/symfony2/tests/ConfigTest.php | 140 + .../symfony2/tests/data/config-1.yml | 3 + .../symfony2/tests/data/config-2.yml | 3 + .../symfony2/tests/data/config-3.yml | 3 + .../symfony2/tests/scripts/install-scenario | 23 + .../symfony2/tests/scripts/prep-dependencies | 66 + .../symfony2/tests/scripts/scenarios | 12 + .../tests/src/ApplyConfigTestTarget.php | 43 + .../symfony2/tests/src/MyFooCommand.php | 47 + .../symfony2/tests/src/TestLoader.php | 36 + .../config/scenarios/symfony4/src | 1 - .../config/scenarios/symfony4/src/Config.php | 157 + .../symfony4/src/ConfigInterface.php | 105 + .../GlobalOptionDefaultValuesInterface.php | 10 + .../symfony4/src/Inject/ConfigForCommand.php | 127 + .../symfony4/src/Inject/ConfigForSetters.php | 47 + .../symfony4/src/Loader/ConfigLoader.php | 35 + .../src/Loader/ConfigLoaderInterface.php | 29 + .../symfony4/src/Loader/ConfigProcessor.php | 167 + .../symfony4/src/Loader/YamlConfigLoader.php | 26 + .../scenarios/symfony4/src/Util/ArrayUtil.php | 75 + .../symfony4/src/Util/ConfigFallback.php | 51 + .../symfony4/src/Util/ConfigGroup.php | 61 + .../symfony4/src/Util/ConfigMerge.php | 34 + .../symfony4/src/Util/ConfigOverlay.php | 203 + .../scenarios/symfony4/src/Util/EnvConfig.php | 96 + .../config/scenarios/symfony4/tests | 1 - .../symfony4/tests/ConfigForCommandTest.php | 130 + .../symfony4/tests/ConfigForSettersTest.php | 87 + .../symfony4/tests/ConfigGroupTest.php | 91 + .../symfony4/tests/ConfigLoaderTest.php | 29 + .../symfony4/tests/ConfigOverlayTest.php | 168 + .../symfony4/tests/ConfigProcessorTest.php | 152 + .../scenarios/symfony4/tests/ConfigTest.php | 140 + .../symfony4/tests/data/config-1.yml | 3 + .../symfony4/tests/data/config-2.yml | 3 + .../symfony4/tests/data/config-3.yml | 3 + .../symfony4/tests/scripts/install-scenario | 23 + .../symfony4/tests/scripts/prep-dependencies | 66 + .../symfony4/tests/scripts/scenarios | 12 + .../tests/src/ApplyConfigTestTarget.php | 43 + .../symfony4/tests/src/MyFooCommand.php | 47 + .../symfony4/tests/src/TestLoader.php | 36 + .../consolidation/robo/scenarios/symfony2/src | 1 - .../scenarios/symfony2/src/Application.php | 73 + .../symfony2/src/Collection/CallableTask.php | 62 + .../symfony2/src/Collection/Collection.php | 769 + .../src/Collection/CollectionBuilder.php | 571 + .../src/Collection/CollectionInterface.php | 151 + .../src/Collection/CollectionProcessHook.php | 35 + .../src/Collection/CompletionWrapper.php | 106 + .../symfony2/src/Collection/Element.php | 116 + .../Collection/NestedCollectionInterface.php | 12 + .../symfony2/src/Collection/TaskForEach.php | 196 + .../symfony2/src/Collection/Temporary.php | 57 + .../symfony2/src/Collection/loadTasks.php | 17 + .../symfony2/src/Common/BuilderAwareTrait.php | 45 + .../symfony2/src/Common/CommandArguments.php | 130 + .../symfony2/src/Common/CommandReceiver.php | 30 + .../symfony2/src/Common/ConfigAwareTrait.php | 109 + .../symfony2/src/Common/DynamicParams.php | 45 + .../symfony2/src/Common/ExecCommand.php | 148 + .../symfony2/src/Common/ExecOneCommand.php | 12 + .../symfony2/src/Common/ExecTrait.php | 408 + .../robo/scenarios/symfony2/src/Common/IO.php | 171 + .../symfony2/src/Common/InflectionTrait.php | 21 + .../symfony2/src/Common/InputAwareTrait.php | 51 + .../symfony2/src/Common/OutputAdapter.php | 38 + .../symfony2/src/Common/OutputAwareTrait.php | 51 + .../symfony2/src/Common/ProcessExecutor.php | 51 + .../symfony2/src/Common/ProcessUtils.php | 79 + .../symfony2/src/Common/ProgressIndicator.php | 201 + .../Common/ProgressIndicatorAwareTrait.php | 135 + .../src/Common/ResourceExistenceChecker.php | 116 + .../scenarios/symfony2/src/Common/TaskIO.php | 237 + .../symfony2/src/Common/TimeKeeper.php | 69 + .../scenarios/symfony2/src/Common/Timer.php | 37 + .../src/Common/VerbosityThresholdTrait.php | 79 + .../robo/scenarios/symfony2/src/Config.php | 9 + .../scenarios/symfony2/src/Config/Config.php | 130 + .../GlobalOptionDefaultValuesInterface.php | 17 + .../src/Contract/BuilderAwareInterface.php | 22 + .../src/Contract/CommandInterface.php | 20 + .../src/Contract/CompletionInterface.php | 18 + .../src/Contract/ConfigAwareInterface.php | 24 + .../src/Contract/IOAwareInterface.php | 13 + .../src/Contract/InflectionInterface.php | 52 + .../src/Contract/OutputAdapterInterface.php | 11 + .../src/Contract/OutputAwareInterface.php | 19 + .../src/Contract/PrintedInterface.php | 16 + .../ProgressIndicatorAwareInterface.php | 24 + .../src/Contract/ProgressInterface.php | 19 + .../src/Contract/RollbackInterface.php | 18 + .../src/Contract/SimulatedInterface.php | 18 + .../symfony2/src/Contract/TaskInterface.php | 17 + .../Contract/VerbosityThresholdInterface.php | 24 + .../src/Contract/WrappedTaskInterface.php | 10 + .../symfony2/src/Exception/TaskException.php | 13 + .../src/Exception/TaskExitException.php | 13 + .../src/GlobalOptionsEventListener.php | 146 + .../scenarios/symfony2/src/LoadAllTasks.php | 39 + .../symfony2/src/Log/ResultPrinter.php | 112 + .../symfony2/src/Log/RoboLogLevel.php | 11 + .../symfony2/src/Log/RoboLogStyle.php | 74 + .../scenarios/symfony2/src/Log/RoboLogger.php | 29 + .../robo/scenarios/symfony2/src/Result.php | 258 + .../scenarios/symfony2/src/ResultData.php | 110 + .../robo/scenarios/symfony2/src/Robo.php | 394 + .../robo/scenarios/symfony2/src/Runner.php | 465 + .../symfony2/src/SelfUpdateCommand.php | 152 + .../scenarios/symfony2/src/State/Consumer.php | 12 + .../scenarios/symfony2/src/State/Data.php | 148 + .../src/State/StateAwareInterface.php | 30 + .../symfony2/src/State/StateAwareTrait.php | 49 + .../symfony2/src/Task/ApiGen/ApiGen.php | 518 + .../symfony2/src/Task/ApiGen/loadTasks.php | 15 + .../symfony2/src/Task/Archive/Extract.php | 279 + .../symfony2/src/Task/Archive/Pack.php | 257 + .../symfony2/src/Task/Archive/loadTasks.php | 25 + .../src/Task/Assets/CssPreprocessor.php | 214 + .../symfony2/src/Task/Assets/ImageMinify.php | 716 + .../symfony2/src/Task/Assets/Less.php | 108 + .../symfony2/src/Task/Assets/Minify.php | 297 + .../symfony2/src/Task/Assets/Scss.php | 93 + .../symfony2/src/Task/Assets/loadTasks.php | 45 + .../scenarios/symfony2/src/Task/Base/Exec.php | 125 + .../symfony2/src/Task/Base/ExecStack.php | 23 + .../symfony2/src/Task/Base/ParallelExec.php | 199 + .../symfony2/src/Task/Base/SymfonyCommand.php | 75 + .../symfony2/src/Task/Base/Watch.php | 89 + .../symfony2/src/Task/Base/loadShortcuts.php | 17 + .../symfony2/src/Task/Base/loadTasks.php | 48 + .../scenarios/symfony2/src/Task/BaseTask.php | 60 + .../symfony2/src/Task/Bower/Base.php | 88 + .../symfony2/src/Task/Bower/Install.php | 36 + .../symfony2/src/Task/Bower/Update.php | 34 + .../symfony2/src/Task/Bower/loadTasks.php | 25 + .../symfony2/src/Task/CommandStack.php | 134 + .../symfony2/src/Task/Composer/Base.php | 248 + .../symfony2/src/Task/Composer/Config.php | 93 + .../src/Task/Composer/CreateProject.php | 112 + .../src/Task/Composer/DumpAutoload.php | 62 + .../symfony2/src/Task/Composer/Init.php | 115 + .../symfony2/src/Task/Composer/Install.php | 40 + .../symfony2/src/Task/Composer/Remove.php | 85 + .../src/Task/Composer/RequireDependency.php | 50 + .../symfony2/src/Task/Composer/Update.php | 40 + .../symfony2/src/Task/Composer/Validate.php | 85 + .../symfony2/src/Task/Composer/loadTasks.php | 95 + .../src/Task/Development/Changelog.php | 246 + .../Task/Development/GenerateMarkdownDoc.php | 782 + .../src/Task/Development/GenerateTask.php | 107 + .../symfony2/src/Task/Development/GitHub.php | 157 + .../src/Task/Development/GitHubRelease.php | 208 + .../src/Task/Development/OpenBrowser.php | 80 + .../src/Task/Development/PackPhar.php | 252 + .../src/Task/Development/PhpServer.php | 86 + .../symfony2/src/Task/Development/SemVer.php | 255 + .../src/Task/Development/loadTasks.php | 86 + .../symfony2/src/Task/Docker/Base.php | 28 + .../symfony2/src/Task/Docker/Build.php | 55 + .../symfony2/src/Task/Docker/Commit.php | 66 + .../symfony2/src/Task/Docker/Exec.php | 95 + .../symfony2/src/Task/Docker/Pull.php | 33 + .../symfony2/src/Task/Docker/Remove.php | 32 + .../symfony2/src/Task/Docker/Result.php | 35 + .../symfony2/src/Task/Docker/Run.php | 301 + .../symfony2/src/Task/Docker/Start.php | 41 + .../symfony2/src/Task/Docker/Stop.php | 41 + .../symfony2/src/Task/Docker/loadTasks.php | 85 + .../symfony2/src/Task/File/Concat.php | 101 + .../symfony2/src/Task/File/Replace.php | 141 + .../symfony2/src/Task/File/TmpFile.php | 72 + .../symfony2/src/Task/File/Write.php | 335 + .../symfony2/src/Task/File/loadTasks.php | 48 + .../symfony2/src/Task/Filesystem/BaseDir.php | 30 + .../symfony2/src/Task/Filesystem/CleanDir.php | 63 + .../symfony2/src/Task/Filesystem/CopyDir.php | 162 + .../src/Task/Filesystem/DeleteDir.php | 36 + .../src/Task/Filesystem/FilesystemStack.php | 154 + .../src/Task/Filesystem/FlattenDir.php | 294 + .../src/Task/Filesystem/MirrorDir.php | 40 + .../symfony2/src/Task/Filesystem/TmpDir.php | 173 + .../symfony2/src/Task/Filesystem/WorkDir.php | 126 + .../src/Task/Filesystem/loadShortcuts.php | 159 + .../src/Task/Filesystem/loadTasks.php | 85 + .../scenarios/symfony2/src/Task/Gulp/Base.php | 97 + .../scenarios/symfony2/src/Task/Gulp/Run.php | 35 + .../symfony2/src/Task/Gulp/loadTasks.php | 16 + .../scenarios/symfony2/src/Task/Npm/Base.php | 60 + .../symfony2/src/Task/Npm/Install.php | 36 + .../symfony2/src/Task/Npm/Update.php | 34 + .../symfony2/src/Task/Npm/loadTasks.php | 25 + .../symfony2/src/Task/Remote/Rsync.php | 484 + .../symfony2/src/Task/Remote/Ssh.php | 273 + .../symfony2/src/Task/Remote/loadTasks.php | 24 + .../scenarios/symfony2/src/Task/Simulator.php | 168 + .../symfony2/src/Task/StackBasedTask.php | 236 + .../symfony2/src/Task/Testing/Atoum.php | 184 + .../symfony2/src/Task/Testing/Behat.php | 163 + .../symfony2/src/Task/Testing/Codecept.php | 271 + .../symfony2/src/Task/Testing/PHPUnit.php | 199 + .../symfony2/src/Task/Testing/Phpspec.php | 116 + .../symfony2/src/Task/Testing/loadTasks.php | 55 + .../symfony2/src/Task/Vcs/GitStack.php | 177 + .../symfony2/src/Task/Vcs/HgStack.php | 153 + .../symfony2/src/Task/Vcs/SvnStack.php | 106 + .../symfony2/src/Task/Vcs/loadShortcuts.php | 35 + .../symfony2/src/Task/Vcs/loadTasks.php | 37 + .../scenarios/symfony2/src/TaskAccessor.php | 47 + .../robo/scenarios/symfony2/src/TaskInfo.php | 35 + .../robo/scenarios/symfony2/src/Tasks.php | 23 + .../robo/scenarios/symfony2/tests/.gitkeep | 1 - .../robo/scenarios/symfony4/.gitkeep | 1 - .../consolidation/robo/scenarios/symfony4/src | 1 - .../scenarios/symfony4/src/Application.php | 73 + .../symfony4/src/Collection/CallableTask.php | 62 + .../symfony4/src/Collection/Collection.php | 769 + .../src/Collection/CollectionBuilder.php | 571 + .../src/Collection/CollectionInterface.php | 151 + .../src/Collection/CollectionProcessHook.php | 35 + .../src/Collection/CompletionWrapper.php | 106 + .../symfony4/src/Collection/Element.php | 116 + .../Collection/NestedCollectionInterface.php | 12 + .../symfony4/src/Collection/TaskForEach.php | 196 + .../symfony4/src/Collection/Temporary.php | 57 + .../symfony4/src/Collection/loadTasks.php | 17 + .../symfony4/src/Common/BuilderAwareTrait.php | 45 + .../symfony4/src/Common/CommandArguments.php | 130 + .../symfony4/src/Common/CommandReceiver.php | 30 + .../symfony4/src/Common/ConfigAwareTrait.php | 109 + .../symfony4/src/Common/DynamicParams.php | 45 + .../symfony4/src/Common/ExecCommand.php | 148 + .../symfony4/src/Common/ExecOneCommand.php | 12 + .../symfony4/src/Common/ExecTrait.php | 408 + .../robo/scenarios/symfony4/src/Common/IO.php | 171 + .../symfony4/src/Common/InflectionTrait.php | 21 + .../symfony4/src/Common/InputAwareTrait.php | 51 + .../symfony4/src/Common/OutputAdapter.php | 38 + .../symfony4/src/Common/OutputAwareTrait.php | 51 + .../symfony4/src/Common/ProcessExecutor.php | 51 + .../symfony4/src/Common/ProcessUtils.php | 79 + .../symfony4/src/Common/ProgressIndicator.php | 201 + .../Common/ProgressIndicatorAwareTrait.php | 135 + .../src/Common/ResourceExistenceChecker.php | 116 + .../scenarios/symfony4/src/Common/TaskIO.php | 237 + .../symfony4/src/Common/TimeKeeper.php | 69 + .../scenarios/symfony4/src/Common/Timer.php | 37 + .../src/Common/VerbosityThresholdTrait.php | 79 + .../robo/scenarios/symfony4/src/Config.php | 9 + .../scenarios/symfony4/src/Config/Config.php | 130 + .../GlobalOptionDefaultValuesInterface.php | 17 + .../src/Contract/BuilderAwareInterface.php | 22 + .../src/Contract/CommandInterface.php | 20 + .../src/Contract/CompletionInterface.php | 18 + .../src/Contract/ConfigAwareInterface.php | 24 + .../src/Contract/IOAwareInterface.php | 13 + .../src/Contract/InflectionInterface.php | 52 + .../src/Contract/OutputAdapterInterface.php | 11 + .../src/Contract/OutputAwareInterface.php | 19 + .../src/Contract/PrintedInterface.php | 16 + .../ProgressIndicatorAwareInterface.php | 24 + .../src/Contract/ProgressInterface.php | 19 + .../src/Contract/RollbackInterface.php | 18 + .../src/Contract/SimulatedInterface.php | 18 + .../symfony4/src/Contract/TaskInterface.php | 17 + .../Contract/VerbosityThresholdInterface.php | 24 + .../src/Contract/WrappedTaskInterface.php | 10 + .../symfony4/src/Exception/TaskException.php | 13 + .../src/Exception/TaskExitException.php | 13 + .../src/GlobalOptionsEventListener.php | 146 + .../scenarios/symfony4/src/LoadAllTasks.php | 39 + .../symfony4/src/Log/ResultPrinter.php | 112 + .../symfony4/src/Log/RoboLogLevel.php | 11 + .../symfony4/src/Log/RoboLogStyle.php | 74 + .../scenarios/symfony4/src/Log/RoboLogger.php | 29 + .../robo/scenarios/symfony4/src/Result.php | 258 + .../scenarios/symfony4/src/ResultData.php | 110 + .../robo/scenarios/symfony4/src/Robo.php | 394 + .../robo/scenarios/symfony4/src/Runner.php | 465 + .../symfony4/src/SelfUpdateCommand.php | 152 + .../scenarios/symfony4/src/State/Consumer.php | 12 + .../scenarios/symfony4/src/State/Data.php | 148 + .../src/State/StateAwareInterface.php | 30 + .../symfony4/src/State/StateAwareTrait.php | 49 + .../symfony4/src/Task/ApiGen/ApiGen.php | 518 + .../symfony4/src/Task/ApiGen/loadTasks.php | 15 + .../symfony4/src/Task/Archive/Extract.php | 279 + .../symfony4/src/Task/Archive/Pack.php | 257 + .../symfony4/src/Task/Archive/loadTasks.php | 25 + .../src/Task/Assets/CssPreprocessor.php | 214 + .../symfony4/src/Task/Assets/ImageMinify.php | 716 + .../symfony4/src/Task/Assets/Less.php | 108 + .../symfony4/src/Task/Assets/Minify.php | 297 + .../symfony4/src/Task/Assets/Scss.php | 93 + .../symfony4/src/Task/Assets/loadTasks.php | 45 + .../scenarios/symfony4/src/Task/Base/Exec.php | 125 + .../symfony4/src/Task/Base/ExecStack.php | 23 + .../symfony4/src/Task/Base/ParallelExec.php | 199 + .../symfony4/src/Task/Base/SymfonyCommand.php | 75 + .../symfony4/src/Task/Base/Watch.php | 89 + .../symfony4/src/Task/Base/loadShortcuts.php | 17 + .../symfony4/src/Task/Base/loadTasks.php | 48 + .../scenarios/symfony4/src/Task/BaseTask.php | 60 + .../symfony4/src/Task/Bower/Base.php | 88 + .../symfony4/src/Task/Bower/Install.php | 36 + .../symfony4/src/Task/Bower/Update.php | 34 + .../symfony4/src/Task/Bower/loadTasks.php | 25 + .../symfony4/src/Task/CommandStack.php | 134 + .../symfony4/src/Task/Composer/Base.php | 248 + .../symfony4/src/Task/Composer/Config.php | 93 + .../src/Task/Composer/CreateProject.php | 112 + .../src/Task/Composer/DumpAutoload.php | 62 + .../symfony4/src/Task/Composer/Init.php | 115 + .../symfony4/src/Task/Composer/Install.php | 40 + .../symfony4/src/Task/Composer/Remove.php | 85 + .../src/Task/Composer/RequireDependency.php | 50 + .../symfony4/src/Task/Composer/Update.php | 40 + .../symfony4/src/Task/Composer/Validate.php | 85 + .../symfony4/src/Task/Composer/loadTasks.php | 95 + .../src/Task/Development/Changelog.php | 246 + .../Task/Development/GenerateMarkdownDoc.php | 782 + .../src/Task/Development/GenerateTask.php | 107 + .../symfony4/src/Task/Development/GitHub.php | 157 + .../src/Task/Development/GitHubRelease.php | 208 + .../src/Task/Development/OpenBrowser.php | 80 + .../src/Task/Development/PackPhar.php | 252 + .../src/Task/Development/PhpServer.php | 86 + .../symfony4/src/Task/Development/SemVer.php | 255 + .../src/Task/Development/loadTasks.php | 86 + .../symfony4/src/Task/Docker/Base.php | 28 + .../symfony4/src/Task/Docker/Build.php | 55 + .../symfony4/src/Task/Docker/Commit.php | 66 + .../symfony4/src/Task/Docker/Exec.php | 95 + .../symfony4/src/Task/Docker/Pull.php | 33 + .../symfony4/src/Task/Docker/Remove.php | 32 + .../symfony4/src/Task/Docker/Result.php | 35 + .../symfony4/src/Task/Docker/Run.php | 301 + .../symfony4/src/Task/Docker/Start.php | 41 + .../symfony4/src/Task/Docker/Stop.php | 41 + .../symfony4/src/Task/Docker/loadTasks.php | 85 + .../symfony4/src/Task/File/Concat.php | 101 + .../symfony4/src/Task/File/Replace.php | 141 + .../symfony4/src/Task/File/TmpFile.php | 72 + .../symfony4/src/Task/File/Write.php | 335 + .../symfony4/src/Task/File/loadTasks.php | 48 + .../symfony4/src/Task/Filesystem/BaseDir.php | 30 + .../symfony4/src/Task/Filesystem/CleanDir.php | 63 + .../symfony4/src/Task/Filesystem/CopyDir.php | 162 + .../src/Task/Filesystem/DeleteDir.php | 36 + .../src/Task/Filesystem/FilesystemStack.php | 154 + .../src/Task/Filesystem/FlattenDir.php | 294 + .../src/Task/Filesystem/MirrorDir.php | 40 + .../symfony4/src/Task/Filesystem/TmpDir.php | 173 + .../symfony4/src/Task/Filesystem/WorkDir.php | 126 + .../src/Task/Filesystem/loadShortcuts.php | 159 + .../src/Task/Filesystem/loadTasks.php | 85 + .../scenarios/symfony4/src/Task/Gulp/Base.php | 97 + .../scenarios/symfony4/src/Task/Gulp/Run.php | 35 + .../symfony4/src/Task/Gulp/loadTasks.php | 16 + .../scenarios/symfony4/src/Task/Npm/Base.php | 60 + .../symfony4/src/Task/Npm/Install.php | 36 + .../symfony4/src/Task/Npm/Update.php | 34 + .../symfony4/src/Task/Npm/loadTasks.php | 25 + .../symfony4/src/Task/Remote/Rsync.php | 484 + .../symfony4/src/Task/Remote/Ssh.php | 273 + .../symfony4/src/Task/Remote/loadTasks.php | 24 + .../scenarios/symfony4/src/Task/Simulator.php | 168 + .../symfony4/src/Task/StackBasedTask.php | 236 + .../symfony4/src/Task/Testing/Atoum.php | 184 + .../symfony4/src/Task/Testing/Behat.php | 163 + .../symfony4/src/Task/Testing/Codecept.php | 271 + .../symfony4/src/Task/Testing/PHPUnit.php | 199 + .../symfony4/src/Task/Testing/Phpspec.php | 116 + .../symfony4/src/Task/Testing/loadTasks.php | 55 + .../symfony4/src/Task/Vcs/GitStack.php | 177 + .../symfony4/src/Task/Vcs/HgStack.php | 153 + .../symfony4/src/Task/Vcs/SvnStack.php | 106 + .../symfony4/src/Task/Vcs/loadShortcuts.php | 35 + .../symfony4/src/Task/Vcs/loadTasks.php | 37 + .../scenarios/symfony4/src/TaskAccessor.php | 47 + .../robo/scenarios/symfony4/src/TaskInfo.php | 35 + .../robo/scenarios/symfony4/src/Tasks.php | 23 + .../yaml-expander/scenarios/symfony2/src | 1 - .../scenarios/symfony2/src/Expander.php | 273 + .../yaml-expander/scenarios/symfony2/tests | 1 - .../symfony2/tests/phpunit/ExpanderTest.php | 99 + .../symfony2/tests/resources/valid.yml | 35 + .../yaml-expander/scenarios/symfony4/src | 1 - .../scenarios/symfony4/src/Expander.php | 273 + .../yaml-expander/scenarios/symfony4/tests | 1 - .../symfony4/tests/phpunit/ExpanderTest.php | 99 + .../symfony4/tests/resources/valid.yml | 35 + .../tests/Monolog/Handler/Fixtures/.gitkeep | 0 .../vendor/neitanod/forceutf8/README.md | 61 + .../vendor/neitanod/forceutf8/composer.json | 20 + .../forceutf8/src/ForceUTF8/Encoding.php | 347 + .../neitanod/forceutf8/test/ForceUTF8Test.php | 101 + .../neitanod/forceutf8/test/Test.class.php | 62 + .../neitanod/forceutf8/test/data/russian.txt | 1 + .../neitanod/forceutf8/test/data/test1.txt | 1 + .../forceutf8/test/data/test1Latin.txt | 1 + .../composer/vendor/pear/net_smtp/README.rst | 268 +- .../phpunit/src/Util/{XML.php => Xml.php} | 0 .../tests/Util/{XMLTest.php => XmlTest.php} | 0 .../vendor/spomky-labs/base64url/LICENSE | 22 + .../spomky-labs/base64url/composer.json | 31 + .../spomky-labs/base64url/src/Base64Url.php | 41 + core/login.php | 28 +- core/logout.php | 5 +- core/migrations/list.php | 2 + ...80507_230001_update_travel_record_type.php | 24 + ...0180514_230002_add_conversation_tables.php | 66 + core/modules.php | 2 - .../employees/customTemplates/myDetails.html | 28 +- core/modules/meta.json | 1 + core/modules/travel/index.php | 6 +- core/robo/RoboFile.php | 4 +- core/service.php | 16 + core/src/Classes/BaseService.php | 12 + core/src/Classes/CustomFieldManager.php | 4 +- core/src/Classes/IceConstants.php | 1 + core/src/Classes/LanguageManager.php | 4 + core/src/Classes/NotificationManager.php | 20 + core/src/Classes/SubActionManager.php | 5 + core/src/Classes/UIManager.php | 84 +- .../Admin/Api/OvertimeAdminManager.php | 10 + core/src/Utils/SessionUtils.php | 2 +- core/templates/app/company_announcement.html | 24 + core/templates/fields/date.html | 2 +- core/templates/fields/datetime.html | 2 +- core/templates/fields/fileupload.html | 9 +- core/templates/fields/text.html | 2 +- core/templates/menu/menuButtonHelp.html | 8 +- core/templates/menu/menuButtonLanguage.html | 10 + deployment/clients/dev/config.php | 8 +- deployment/clients/local/config.php | 10 +- deployment/clients/test/config.php | 4 +- test/unit/LanguageManagerUnit.php | 26 +- web/admin/employees/lib.js | 56 +- web/admin/fieldnames/lib.js | 96 - web/admin/travel/lib.js | 31 +- web/api/AdapterBase.js | 97 + web/api/Base.js | 2725 +-- web/api/ConversationsAdapter.js | 348 + .../flag-icon-css/.bower.json | 27 + web/bower_components/flag-icon-css/README.md | 76 + web/bower_components/flag-icon-css/bower.json | 16 + .../flag-icon-css/composer.json | 22 + .../flag-icon-css/css/flag-icon.css | 1556 ++ .../flag-icon-css/css/flag-icon.min.css | 1 + .../flag-icon-css/flags/1x1/ad.svg | 148 + .../flag-icon-css/flags/1x1/ae.svg | 6 + .../flag-icon-css/flags/1x1/af.svg | 81 + .../flag-icon-css/flags/1x1/ag.svg | 14 + .../flag-icon-css/flags/1x1/ai.svg | 767 + .../flag-icon-css/flags/1x1/al.svg | 5 + .../flag-icon-css/flags/1x1/am.svg | 5 + .../flag-icon-css/flags/1x1/ao.svg | 13 + .../flag-icon-css/flags/1x1/aq.svg | 13 + .../flag-icon-css/flags/1x1/ar.svg | 31 + .../flag-icon-css/flags/1x1/as.svg | 33 + .../flag-icon-css/flags/1x1/at.svg | 6 + .../flag-icon-css/flags/1x1/au.svg | 9 + .../flag-icon-css/flags/1x1/aw.svg | 186 + .../flag-icon-css/flags/1x1/ax.svg | 18 + .../flag-icon-css/flags/1x1/az.svg | 8 + .../flag-icon-css/flags/1x1/ba.svg | 12 + .../flag-icon-css/flags/1x1/bb.svg | 6 + .../flag-icon-css/flags/1x1/bd.svg | 4 + .../flag-icon-css/flags/1x1/be.svg | 7 + .../flag-icon-css/flags/1x1/bf.svg | 7 + .../flag-icon-css/flags/1x1/bg.svg | 7 + .../flag-icon-css/flags/1x1/bh.svg | 11 + .../flag-icon-css/flags/1x1/bi.svg | 15 + .../flag-icon-css/flags/1x1/bj.svg | 14 + .../flag-icon-css/flags/1x1/bl.svg | 7 + .../flag-icon-css/flags/1x1/bm.svg | 98 + .../flag-icon-css/flags/1x1/bn.svg | 36 + .../flag-icon-css/flags/1x1/bo.svg | 678 + .../flag-icon-css/flags/1x1/bq.svg | 5 + .../flag-icon-css/flags/1x1/br.svg | 45 + .../flag-icon-css/flags/1x1/bs.svg | 13 + .../flag-icon-css/flags/1x1/bt.svg | 89 + .../flag-icon-css/flags/1x1/bv.svg | 13 + .../flag-icon-css/flags/1x1/bw.svg | 7 + .../flag-icon-css/flags/1x1/by.svg | 22 + .../flag-icon-css/flags/1x1/bz.svg | 145 + .../flag-icon-css/flags/1x1/ca.svg | 4 + .../flag-icon-css/flags/1x1/cc.svg | 19 + .../flag-icon-css/flags/1x1/cd.svg | 12 + .../flag-icon-css/flags/1x1/cf.svg | 15 + .../flag-icon-css/flags/1x1/cg.svg | 12 + .../flag-icon-css/flags/1x1/ch.svg | 9 + .../flag-icon-css/flags/1x1/ci.svg | 7 + .../flag-icon-css/flags/1x1/ck.svg | 9 + .../flag-icon-css/flags/1x1/cl.svg | 13 + .../flag-icon-css/flags/1x1/cm.svg | 15 + .../flag-icon-css/flags/1x1/cn.svg | 11 + .../flag-icon-css/flags/1x1/co.svg | 7 + .../flag-icon-css/flags/1x1/cr.svg | 7 + .../flag-icon-css/flags/1x1/cu.svg | 13 + .../flag-icon-css/flags/1x1/cv.svg | 13 + .../flag-icon-css/flags/1x1/cw.svg | 14 + .../flag-icon-css/flags/1x1/cx.svg | 15 + .../flag-icon-css/flags/1x1/cy.svg | 6 + .../flag-icon-css/flags/1x1/cz.svg | 12 + .../flag-icon-css/flags/1x1/de.svg | 5 + .../flag-icon-css/flags/1x1/dj.svg | 13 + .../flag-icon-css/flags/1x1/dk.svg | 5 + .../flag-icon-css/flags/1x1/dm.svg | 152 + .../flag-icon-css/flags/1x1/do.svg | 6745 ++++++ .../flag-icon-css/flags/1x1/dz.svg | 5 + .../flag-icon-css/flags/1x1/ec.svg | 138 + .../flag-icon-css/flags/1x1/ee.svg | 7 + .../flag-icon-css/flags/1x1/eg.svg | 38 + .../flag-icon-css/flags/1x1/eh.svg | 15 + .../flag-icon-css/flags/1x1/er.svg | 13 + .../flag-icon-css/flags/1x1/es-ct.svg | 4 + .../flag-icon-css/flags/1x1/es.svg | 547 + .../flag-icon-css/flags/1x1/et.svg | 14 + .../flag-icon-css/flags/1x1/eu.svg | 28 + .../flag-icon-css/flags/1x1/fi.svg | 5 + .../flag-icon-css/flags/1x1/fj.svg | 123 + .../flag-icon-css/flags/1x1/fk.svg | 89 + .../flag-icon-css/flags/1x1/fm.svg | 11 + .../flag-icon-css/flags/1x1/fo.svg | 12 + .../flag-icon-css/flags/1x1/fr.svg | 7 + .../flag-icon-css/flags/1x1/ga.svg | 7 + .../flag-icon-css/flags/1x1/gb-eng.svg | 5 + .../flag-icon-css/flags/1x1/gb-nir.svg | 130 + .../flag-icon-css/flags/1x1/gb-sct.svg | 4 + .../flag-icon-css/flags/1x1/gb-wls.svg | 9 + .../flag-icon-css/flags/1x1/gb.svg | 15 + .../flag-icon-css/flags/1x1/gd.svg | 27 + .../flag-icon-css/flags/1x1/ge.svg | 6 + .../flag-icon-css/flags/1x1/gf.svg | 5 + .../flag-icon-css/flags/1x1/gg.svg | 9 + .../flag-icon-css/flags/1x1/gh.svg | 6 + .../flag-icon-css/flags/1x1/gi.svg | 32 + .../flag-icon-css/flags/1x1/gl.svg | 4 + .../flag-icon-css/flags/1x1/gm.svg | 9 + .../flag-icon-css/flags/1x1/gn.svg | 7 + .../flag-icon-css/flags/1x1/gp.svg | 7 + .../flag-icon-css/flags/1x1/gq.svg | 23 + .../flag-icon-css/flags/1x1/gr.svg | 24 + .../flag-icon-css/flags/1x1/gs.svg | 206 + .../flag-icon-css/flags/1x1/gt.svg | 204 + .../flag-icon-css/flags/1x1/gu.svg | 39 + .../flag-icon-css/flags/1x1/gw.svg | 15 + .../flag-icon-css/flags/1x1/gy.svg | 9 + .../flag-icon-css/flags/1x1/hk.svg | 30 + .../flag-icon-css/flags/1x1/hm.svg | 9 + .../flag-icon-css/flags/1x1/hn.svg | 18 + .../flag-icon-css/flags/1x1/hr.svg | 56 + .../flag-icon-css/flags/1x1/ht.svg | 116 + .../flag-icon-css/flags/1x1/hu.svg | 7 + .../flag-icon-css/flags/1x1/id.svg | 6 + .../flag-icon-css/flags/1x1/ie.svg | 7 + .../flag-icon-css/flags/1x1/il.svg | 14 + .../flag-icon-css/flags/1x1/im.svg | 36 + .../flag-icon-css/flags/1x1/in.svg | 25 + .../flag-icon-css/flags/1x1/io.svg | 142 + .../flag-icon-css/flags/1x1/iq.svg | 10 + .../flag-icon-css/flags/1x1/ir.svg | 219 + .../flag-icon-css/flags/1x1/is.svg | 12 + .../flag-icon-css/flags/1x1/it.svg | 7 + .../flag-icon-css/flags/1x1/je.svg | 31 + .../flag-icon-css/flags/1x1/jm.svg | 8 + .../flag-icon-css/flags/1x1/jo.svg | 16 + .../flag-icon-css/flags/1x1/jp.svg | 11 + .../flag-icon-css/flags/1x1/ke.svg | 23 + .../flag-icon-css/flags/1x1/kg.svg | 15 + .../flag-icon-css/flags/1x1/kh.svg | 61 + .../flag-icon-css/flags/1x1/ki.svg | 36 + .../flag-icon-css/flags/1x1/km.svg | 16 + .../flag-icon-css/flags/1x1/kn.svg | 14 + .../flag-icon-css/flags/1x1/kp.svg | 15 + .../flag-icon-css/flags/1x1/kr.svg | 24 + .../flag-icon-css/flags/1x1/kw.svg | 13 + .../flag-icon-css/flags/1x1/ky.svg | 70 + .../flag-icon-css/flags/1x1/kz.svg | 23 + .../flag-icon-css/flags/1x1/la.svg | 12 + .../flag-icon-css/flags/1x1/lb.svg | 15 + .../flag-icon-css/flags/1x1/lc.svg | 8 + .../flag-icon-css/flags/1x1/li.svg | 43 + .../flag-icon-css/flags/1x1/lk.svg | 22 + .../flag-icon-css/flags/1x1/lr.svg | 14 + .../flag-icon-css/flags/1x1/ls.svg | 8 + .../flag-icon-css/flags/1x1/lt.svg | 7 + .../flag-icon-css/flags/1x1/lu.svg | 5 + .../flag-icon-css/flags/1x1/lv.svg | 6 + .../flag-icon-css/flags/1x1/ly.svg | 13 + .../flag-icon-css/flags/1x1/ma.svg | 4 + .../flag-icon-css/flags/1x1/mc.svg | 6 + .../flag-icon-css/flags/1x1/md.svg | 71 + .../flag-icon-css/flags/1x1/me.svg | 118 + .../flag-icon-css/flags/1x1/mf.svg | 7 + .../flag-icon-css/flags/1x1/mg.svg | 7 + .../flag-icon-css/flags/1x1/mh.svg | 8 + .../flag-icon-css/flags/1x1/mk.svg | 5 + .../flag-icon-css/flags/1x1/ml.svg | 7 + .../flag-icon-css/flags/1x1/mm.svg | 16 + .../flag-icon-css/flags/1x1/mn.svg | 13 + .../flag-icon-css/flags/1x1/mo.svg | 9 + .../flag-icon-css/flags/1x1/mp.svg | 86 + .../flag-icon-css/flags/1x1/mq.svg | 7 + .../flag-icon-css/flags/1x1/mr.svg | 6 + .../flag-icon-css/flags/1x1/ms.svg | 39 + .../flag-icon-css/flags/1x1/mt.svg | 50 + .../flag-icon-css/flags/1x1/mu.svg | 8 + .../flag-icon-css/flags/1x1/mv.svg | 6 + .../flag-icon-css/flags/1x1/mw.svg | 15 + .../flag-icon-css/flags/1x1/mx.svg | 378 + .../flag-icon-css/flags/1x1/my.svg | 15 + .../flag-icon-css/flags/1x1/mz.svg | 21 + .../flag-icon-css/flags/1x1/na.svg | 16 + .../flag-icon-css/flags/1x1/nc.svg | 7 + .../flag-icon-css/flags/1x1/ne.svg | 6 + .../flag-icon-css/flags/1x1/nf.svg | 11 + .../flag-icon-css/flags/1x1/ng.svg | 6 + .../flag-icon-css/flags/1x1/ni.svg | 129 + .../flag-icon-css/flags/1x1/nl.svg | 7 + .../flag-icon-css/flags/1x1/no.svg | 7 + .../flag-icon-css/flags/1x1/np.svg | 19 + .../flag-icon-css/flags/1x1/nr.svg | 12 + .../flag-icon-css/flags/1x1/nu.svg | 26 + .../flag-icon-css/flags/1x1/nz.svg | 41 + .../flag-icon-css/flags/1x1/om.svg | 115 + .../flag-icon-css/flags/1x1/pa.svg | 13 + .../flag-icon-css/flags/1x1/pe.svg | 244 + .../flag-icon-css/flags/1x1/pf.svg | 18 + .../flag-icon-css/flags/1x1/pg.svg | 16 + .../flag-icon-css/flags/1x1/ph.svg | 28 + .../flag-icon-css/flags/1x1/pk.svg | 15 + .../flag-icon-css/flags/1x1/pl.svg | 6 + .../flag-icon-css/flags/1x1/pm.svg | 7 + .../flag-icon-css/flags/1x1/pn.svg | 67 + .../flag-icon-css/flags/1x1/pr.svg | 13 + .../flag-icon-css/flags/1x1/ps.svg | 15 + .../flag-icon-css/flags/1x1/pt.svg | 57 + .../flag-icon-css/flags/1x1/pw.svg | 11 + .../flag-icon-css/flags/1x1/py.svg | 156 + .../flag-icon-css/flags/1x1/qa.svg | 4 + .../flag-icon-css/flags/1x1/re.svg | 7 + .../flag-icon-css/flags/1x1/ro.svg | 7 + .../flag-icon-css/flags/1x1/rs.svg | 296 + .../flag-icon-css/flags/1x1/ru.svg | 7 + .../flag-icon-css/flags/1x1/rw.svg | 13 + .../flag-icon-css/flags/1x1/sa.svg | 26 + .../flag-icon-css/flags/1x1/sb.svg | 13 + .../flag-icon-css/flags/1x1/sc.svg | 14 + .../flag-icon-css/flags/1x1/sd.svg | 13 + .../flag-icon-css/flags/1x1/se.svg | 16 + .../flag-icon-css/flags/1x1/sg.svg | 13 + .../flag-icon-css/flags/1x1/sh.svg | 81 + .../flag-icon-css/flags/1x1/si.svg | 18 + .../flag-icon-css/flags/1x1/sj.svg | 7 + .../flag-icon-css/flags/1x1/sk.svg | 9 + .../flag-icon-css/flags/1x1/sl.svg | 12 + .../flag-icon-css/flags/1x1/sm.svg | 89 + .../flag-icon-css/flags/1x1/sn.svg | 8 + .../flag-icon-css/flags/1x1/so.svg | 11 + .../flag-icon-css/flags/1x1/sr.svg | 6 + .../flag-icon-css/flags/1x1/ss.svg | 8 + .../flag-icon-css/flags/1x1/st.svg | 16 + .../flag-icon-css/flags/1x1/sv.svg | 608 + .../flag-icon-css/flags/1x1/sx.svg | 56 + .../flag-icon-css/flags/1x1/sy.svg | 6 + .../flag-icon-css/flags/1x1/sz.svg | 45 + .../flag-icon-css/flags/1x1/tc.svg | 74 + .../flag-icon-css/flags/1x1/td.svg | 7 + .../flag-icon-css/flags/1x1/tf.svg | 15 + .../flag-icon-css/flags/1x1/tg.svg | 14 + .../flag-icon-css/flags/1x1/th.svg | 7 + .../flag-icon-css/flags/1x1/tj.svg | 26 + .../flag-icon-css/flags/1x1/tk.svg | 5 + .../flag-icon-css/flags/1x1/tl.svg | 13 + .../flag-icon-css/flags/1x1/tm.svg | 203 + .../flag-icon-css/flags/1x1/tn.svg | 13 + .../flag-icon-css/flags/1x1/to.svg | 10 + .../flag-icon-css/flags/1x1/tr.svg | 8 + .../flag-icon-css/flags/1x1/tt.svg | 7 + .../flag-icon-css/flags/1x1/tv.svg | 27 + .../flag-icon-css/flags/1x1/tw.svg | 14 + .../flag-icon-css/flags/1x1/tz.svg | 15 + .../flag-icon-css/flags/1x1/ua.svg | 6 + .../flag-icon-css/flags/1x1/ug.svg | 30 + .../flag-icon-css/flags/1x1/um.svg | 15 + .../flag-icon-css/flags/1x1/un.svg | 16 + .../flag-icon-css/flags/1x1/us.svg | 10 + .../flag-icon-css/flags/1x1/uy.svg | 28 + .../flag-icon-css/flags/1x1/uz.svg | 30 + .../flag-icon-css/flags/1x1/va.svg | 479 + .../flag-icon-css/flags/1x1/vc.svg | 8 + .../flag-icon-css/flags/1x1/ve.svg | 26 + .../flag-icon-css/flags/1x1/vg.svg | 128 + .../flag-icon-css/flags/1x1/vi.svg | 28 + .../flag-icon-css/flags/1x1/vn.svg | 11 + .../flag-icon-css/flags/1x1/vu.svg | 18 + .../flag-icon-css/flags/1x1/wf.svg | 7 + .../flag-icon-css/flags/1x1/ws.svg | 7 + .../flag-icon-css/flags/1x1/ye.svg | 7 + .../flag-icon-css/flags/1x1/yt.svg | 7 + .../flag-icon-css/flags/1x1/za.svg | 17 + .../flag-icon-css/flags/1x1/zm.svg | 27 + .../flag-icon-css/flags/1x1/zw.svg | 21 + .../flag-icon-css/flags/4x3/ad.svg | 150 + .../flag-icon-css/flags/4x3/ae.svg | 6 + .../flag-icon-css/flags/4x3/af.svg | 81 + .../flag-icon-css/flags/4x3/ag.svg | 14 + .../flag-icon-css/flags/4x3/ai.svg | 767 + .../flag-icon-css/flags/4x3/al.svg | 5 + .../flag-icon-css/flags/4x3/am.svg | 5 + .../flag-icon-css/flags/4x3/ao.svg | 13 + .../flag-icon-css/flags/4x3/aq.svg | 6 + .../flag-icon-css/flags/4x3/ar.svg | 31 + .../flag-icon-css/flags/4x3/as.svg | 33 + .../flag-icon-css/flags/4x3/at.svg | 6 + .../flag-icon-css/flags/4x3/au.svg | 9 + .../flag-icon-css/flags/4x3/aw.svg | 186 + .../flag-icon-css/flags/4x3/ax.svg | 18 + .../flag-icon-css/flags/4x3/az.svg | 8 + .../flag-icon-css/flags/4x3/ba.svg | 12 + .../flag-icon-css/flags/4x3/bb.svg | 6 + .../flag-icon-css/flags/4x3/bd.svg | 4 + .../flag-icon-css/flags/4x3/be.svg | 7 + .../flag-icon-css/flags/4x3/bf.svg | 7 + .../flag-icon-css/flags/4x3/bg.svg | 7 + .../flag-icon-css/flags/4x3/bh.svg | 11 + .../flag-icon-css/flags/4x3/bi.svg | 15 + .../flag-icon-css/flags/4x3/bj.svg | 14 + .../flag-icon-css/flags/4x3/bl.svg | 7 + .../flag-icon-css/flags/4x3/bm.svg | 98 + .../flag-icon-css/flags/4x3/bn.svg | 36 + .../flag-icon-css/flags/4x3/bo.svg | 676 + .../flag-icon-css/flags/4x3/bq.svg | 5 + .../flag-icon-css/flags/4x3/br.svg | 45 + .../flag-icon-css/flags/4x3/bs.svg | 13 + .../flag-icon-css/flags/4x3/bt.svg | 89 + .../flag-icon-css/flags/4x3/bv.svg | 13 + .../flag-icon-css/flags/4x3/bw.svg | 7 + .../flag-icon-css/flags/4x3/by.svg | 20 + .../flag-icon-css/flags/4x3/bz.svg | 145 + .../flag-icon-css/flags/4x3/ca.svg | 4 + .../flag-icon-css/flags/4x3/cc.svg | 19 + .../flag-icon-css/flags/4x3/cd.svg | 5 + .../flag-icon-css/flags/4x3/cf.svg | 15 + .../flag-icon-css/flags/4x3/cg.svg | 12 + .../flag-icon-css/flags/4x3/ch.svg | 9 + .../flag-icon-css/flags/4x3/ci.svg | 7 + .../flag-icon-css/flags/4x3/ck.svg | 9 + .../flag-icon-css/flags/4x3/cl.svg | 13 + .../flag-icon-css/flags/4x3/cm.svg | 15 + .../flag-icon-css/flags/4x3/cn.svg | 11 + .../flag-icon-css/flags/4x3/co.svg | 7 + .../flag-icon-css/flags/4x3/cr.svg | 7 + .../flag-icon-css/flags/4x3/cu.svg | 13 + .../flag-icon-css/flags/4x3/cv.svg | 13 + .../flag-icon-css/flags/4x3/cw.svg | 14 + .../flag-icon-css/flags/4x3/cx.svg | 15 + .../flag-icon-css/flags/4x3/cy.svg | 6 + .../flag-icon-css/flags/4x3/cz.svg | 12 + .../flag-icon-css/flags/4x3/de.svg | 5 + .../flag-icon-css/flags/4x3/dj.svg | 13 + .../flag-icon-css/flags/4x3/dk.svg | 5 + .../flag-icon-css/flags/4x3/dm.svg | 152 + .../flag-icon-css/flags/4x3/do.svg | 6745 ++++++ .../flag-icon-css/flags/4x3/dz.svg | 5 + .../flag-icon-css/flags/4x3/ec.svg | 138 + .../flag-icon-css/flags/4x3/ee.svg | 7 + .../flag-icon-css/flags/4x3/eg.svg | 38 + .../flag-icon-css/flags/4x3/eh.svg | 15 + .../flag-icon-css/flags/4x3/er.svg | 8 + .../flag-icon-css/flags/4x3/es-ct.svg | 4 + .../flag-icon-css/flags/4x3/es.svg | 544 + .../flag-icon-css/flags/4x3/et.svg | 14 + .../flag-icon-css/flags/4x3/eu.svg | 28 + .../flag-icon-css/flags/4x3/fi.svg | 5 + .../flag-icon-css/flags/4x3/fj.svg | 120 + .../flag-icon-css/flags/4x3/fk.svg | 89 + .../flag-icon-css/flags/4x3/fm.svg | 11 + .../flag-icon-css/flags/4x3/fo.svg | 12 + .../flag-icon-css/flags/4x3/fr.svg | 7 + .../flag-icon-css/flags/4x3/ga.svg | 7 + .../flag-icon-css/flags/4x3/gb-eng.svg | 5 + .../flag-icon-css/flags/4x3/gb-nir.svg | 131 + .../flag-icon-css/flags/4x3/gb-sct.svg | 4 + .../flag-icon-css/flags/4x3/gb-wls.svg | 9 + .../flag-icon-css/flags/4x3/gb.svg | 15 + .../flag-icon-css/flags/4x3/gd.svg | 27 + .../flag-icon-css/flags/4x3/ge.svg | 6 + .../flag-icon-css/flags/4x3/gf.svg | 5 + .../flag-icon-css/flags/4x3/gg.svg | 9 + .../flag-icon-css/flags/4x3/gh.svg | 6 + .../flag-icon-css/flags/4x3/gi.svg | 32 + .../flag-icon-css/flags/4x3/gl.svg | 4 + .../flag-icon-css/flags/4x3/gm.svg | 14 + .../flag-icon-css/flags/4x3/gn.svg | 7 + .../flag-icon-css/flags/4x3/gp.svg | 7 + .../flag-icon-css/flags/4x3/gq.svg | 23 + .../flag-icon-css/flags/4x3/gr.svg | 22 + .../flag-icon-css/flags/4x3/gs.svg | 201 + .../flag-icon-css/flags/4x3/gt.svg | 204 + .../flag-icon-css/flags/4x3/gu.svg | 39 + .../flag-icon-css/flags/4x3/gw.svg | 13 + .../flag-icon-css/flags/4x3/gy.svg | 9 + .../flag-icon-css/flags/4x3/hk.svg | 30 + .../flag-icon-css/flags/4x3/hm.svg | 9 + .../flag-icon-css/flags/4x3/hn.svg | 18 + .../flag-icon-css/flags/4x3/hr.svg | 58 + .../flag-icon-css/flags/4x3/ht.svg | 116 + .../flag-icon-css/flags/4x3/hu.svg | 7 + .../flag-icon-css/flags/4x3/id.svg | 6 + .../flag-icon-css/flags/4x3/ie.svg | 7 + .../flag-icon-css/flags/4x3/il.svg | 14 + .../flag-icon-css/flags/4x3/im.svg | 36 + .../flag-icon-css/flags/4x3/in.svg | 25 + .../flag-icon-css/flags/4x3/io.svg | 138 + .../flag-icon-css/flags/4x3/iq.svg | 10 + .../flag-icon-css/flags/4x3/ir.svg | 219 + .../flag-icon-css/flags/4x3/is.svg | 12 + .../flag-icon-css/flags/4x3/it.svg | 7 + .../flag-icon-css/flags/4x3/je.svg | 31 + .../flag-icon-css/flags/4x3/jm.svg | 8 + .../flag-icon-css/flags/4x3/jo.svg | 16 + .../flag-icon-css/flags/4x3/jp.svg | 11 + .../flag-icon-css/flags/4x3/ke.svg | 23 + .../flag-icon-css/flags/4x3/kg.svg | 15 + .../flag-icon-css/flags/4x3/kh.svg | 61 + .../flag-icon-css/flags/4x3/ki.svg | 36 + .../flag-icon-css/flags/4x3/km.svg | 16 + .../flag-icon-css/flags/4x3/kn.svg | 14 + .../flag-icon-css/flags/4x3/kp.svg | 15 + .../flag-icon-css/flags/4x3/kr.svg | 24 + .../flag-icon-css/flags/4x3/kw.svg | 13 + .../flag-icon-css/flags/4x3/ky.svg | 63 + .../flag-icon-css/flags/4x3/kz.svg | 23 + .../flag-icon-css/flags/4x3/la.svg | 12 + .../flag-icon-css/flags/4x3/lb.svg | 15 + .../flag-icon-css/flags/4x3/lc.svg | 8 + .../flag-icon-css/flags/4x3/li.svg | 43 + .../flag-icon-css/flags/4x3/lk.svg | 22 + .../flag-icon-css/flags/4x3/lr.svg | 14 + .../flag-icon-css/flags/4x3/ls.svg | 8 + .../flag-icon-css/flags/4x3/lt.svg | 7 + .../flag-icon-css/flags/4x3/lu.svg | 5 + .../flag-icon-css/flags/4x3/lv.svg | 6 + .../flag-icon-css/flags/4x3/ly.svg | 13 + .../flag-icon-css/flags/4x3/ma.svg | 4 + .../flag-icon-css/flags/4x3/mc.svg | 6 + .../flag-icon-css/flags/4x3/md.svg | 70 + .../flag-icon-css/flags/4x3/me.svg | 116 + .../flag-icon-css/flags/4x3/mf.svg | 7 + .../flag-icon-css/flags/4x3/mg.svg | 7 + .../flag-icon-css/flags/4x3/mh.svg | 7 + .../flag-icon-css/flags/4x3/mk.svg | 5 + .../flag-icon-css/flags/4x3/ml.svg | 7 + .../flag-icon-css/flags/4x3/mm.svg | 16 + .../flag-icon-css/flags/4x3/mn.svg | 13 + .../flag-icon-css/flags/4x3/mo.svg | 9 + .../flag-icon-css/flags/4x3/mp.svg | 86 + .../flag-icon-css/flags/4x3/mq.svg | 7 + .../flag-icon-css/flags/4x3/mr.svg | 6 + .../flag-icon-css/flags/4x3/ms.svg | 39 + .../flag-icon-css/flags/4x3/mt.svg | 49 + .../flag-icon-css/flags/4x3/mu.svg | 8 + .../flag-icon-css/flags/4x3/mv.svg | 6 + .../flag-icon-css/flags/4x3/mw.svg | 10 + .../flag-icon-css/flags/4x3/mx.svg | 382 + .../flag-icon-css/flags/4x3/my.svg | 15 + .../flag-icon-css/flags/4x3/mz.svg | 21 + .../flag-icon-css/flags/4x3/na.svg | 16 + .../flag-icon-css/flags/4x3/nc.svg | 7 + .../flag-icon-css/flags/4x3/ne.svg | 6 + .../flag-icon-css/flags/4x3/nf.svg | 9 + .../flag-icon-css/flags/4x3/ng.svg | 6 + .../flag-icon-css/flags/4x3/ni.svg | 129 + .../flag-icon-css/flags/4x3/nl.svg | 7 + .../flag-icon-css/flags/4x3/no.svg | 7 + .../flag-icon-css/flags/4x3/np.svg | 14 + .../flag-icon-css/flags/4x3/nr.svg | 12 + .../flag-icon-css/flags/4x3/nu.svg | 26 + .../flag-icon-css/flags/4x3/nz.svg | 41 + .../flag-icon-css/flags/4x3/om.svg | 115 + .../flag-icon-css/flags/4x3/pa.svg | 14 + .../flag-icon-css/flags/4x3/pe.svg | 244 + .../flag-icon-css/flags/4x3/pf.svg | 19 + .../flag-icon-css/flags/4x3/pg.svg | 9 + .../flag-icon-css/flags/4x3/ph.svg | 28 + .../flag-icon-css/flags/4x3/pk.svg | 15 + .../flag-icon-css/flags/4x3/pl.svg | 6 + .../flag-icon-css/flags/4x3/pm.svg | 7 + .../flag-icon-css/flags/4x3/pn.svg | 62 + .../flag-icon-css/flags/4x3/pr.svg | 13 + .../flag-icon-css/flags/4x3/ps.svg | 15 + .../flag-icon-css/flags/4x3/pt.svg | 57 + .../flag-icon-css/flags/4x3/pw.svg | 11 + .../flag-icon-css/flags/4x3/py.svg | 157 + .../flag-icon-css/flags/4x3/qa.svg | 4 + .../flag-icon-css/flags/4x3/re.svg | 7 + .../flag-icon-css/flags/4x3/ro.svg | 7 + .../flag-icon-css/flags/4x3/rs.svg | 292 + .../flag-icon-css/flags/4x3/ru.svg | 7 + .../flag-icon-css/flags/4x3/rw.svg | 13 + .../flag-icon-css/flags/4x3/sa.svg | 26 + .../flag-icon-css/flags/4x3/sb.svg | 13 + .../flag-icon-css/flags/4x3/sc.svg | 14 + .../flag-icon-css/flags/4x3/sd.svg | 13 + .../flag-icon-css/flags/4x3/se.svg | 16 + .../flag-icon-css/flags/4x3/sg.svg | 13 + .../flag-icon-css/flags/4x3/sh.svg | 74 + .../flag-icon-css/flags/4x3/si.svg | 18 + .../flag-icon-css/flags/4x3/sj.svg | 7 + .../flag-icon-css/flags/4x3/sk.svg | 9 + .../flag-icon-css/flags/4x3/sl.svg | 7 + .../flag-icon-css/flags/4x3/sm.svg | 91 + .../flag-icon-css/flags/4x3/sn.svg | 8 + .../flag-icon-css/flags/4x3/so.svg | 11 + .../flag-icon-css/flags/4x3/sr.svg | 6 + .../flag-icon-css/flags/4x3/ss.svg | 8 + .../flag-icon-css/flags/4x3/st.svg | 16 + .../flag-icon-css/flags/4x3/sv.svg | 606 + .../flag-icon-css/flags/4x3/sx.svg | 56 + .../flag-icon-css/flags/4x3/sy.svg | 6 + .../flag-icon-css/flags/4x3/sz.svg | 45 + .../flag-icon-css/flags/4x3/tc.svg | 67 + .../flag-icon-css/flags/4x3/td.svg | 7 + .../flag-icon-css/flags/4x3/tf.svg | 15 + .../flag-icon-css/flags/4x3/tg.svg | 14 + .../flag-icon-css/flags/4x3/th.svg | 7 + .../flag-icon-css/flags/4x3/tj.svg | 22 + .../flag-icon-css/flags/4x3/tk.svg | 5 + .../flag-icon-css/flags/4x3/tl.svg | 13 + .../flag-icon-css/flags/4x3/tm.svg | 206 + .../flag-icon-css/flags/4x3/tn.svg | 13 + .../flag-icon-css/flags/4x3/to.svg | 10 + .../flag-icon-css/flags/4x3/tr.svg | 8 + .../flag-icon-css/flags/4x3/tt.svg | 5 + .../flag-icon-css/flags/4x3/tv.svg | 27 + .../flag-icon-css/flags/4x3/tw.svg | 14 + .../flag-icon-css/flags/4x3/tz.svg | 13 + .../flag-icon-css/flags/4x3/ua.svg | 6 + .../flag-icon-css/flags/4x3/ug.svg | 30 + .../flag-icon-css/flags/4x3/um.svg | 15 + .../flag-icon-css/flags/4x3/un.svg | 16 + .../flag-icon-css/flags/4x3/us.svg | 10 + .../flag-icon-css/flags/4x3/uy.svg | 28 + .../flag-icon-css/flags/4x3/uz.svg | 30 + .../flag-icon-css/flags/4x3/va.svg | 479 + .../flag-icon-css/flags/4x3/vc.svg | 8 + .../flag-icon-css/flags/4x3/ve.svg | 26 + .../flag-icon-css/flags/4x3/vg.svg | 127 + .../flag-icon-css/flags/4x3/vi.svg | 28 + .../flag-icon-css/flags/4x3/vn.svg | 11 + .../flag-icon-css/flags/4x3/vu.svg | 18 + .../flag-icon-css/flags/4x3/wf.svg | 7 + .../flag-icon-css/flags/4x3/ws.svg | 7 + .../flag-icon-css/flags/4x3/ye.svg | 7 + .../flag-icon-css/flags/4x3/yt.svg | 7 + .../flag-icon-css/flags/4x3/za.svg | 17 + .../flag-icon-css/flags/4x3/zm.svg | 27 + .../flag-icon-css/flags/4x3/zw.svg | 21 + .../flag-icon-css/less/flag-icon-base.less | 28 + .../flag-icon-css/less/flag-icon-list.less | 249 + .../flag-icon-css/less/flag-icon-more.less | 7 + .../flag-icon-css/less/flag-icon.less | 4 + .../flag-icon-css/less/variables.less | 3 + .../flag-icon-css/sass/_flag-icon-base.scss | 28 + .../flag-icon-css/sass/_flag-icon-list.scss | 249 + .../flag-icon-css/sass/_flag-icon-more.scss | 7 + .../flag-icon-css/sass/_variables.scss | 3 + .../flag-icon-css/sass/flag-icon.scss | 4 + web/bower_components/flag-icon-css/svgo.yaml | 13 + web/bower_components/flag-icon-css/yarn.lock | 1503 ++ web/bower_components/inputmask/.bower.json | 58 + web/bower_components/inputmask/bower.json | 40 + .../inputmask/bindings/inputmask.binding.js | 21 + .../inputmask.dependencyLib.jqlite.js | 62 + .../inputmask.dependencyLib.jquery.js | 13 + .../dependencyLibs/inputmask.dependencyLib.js | 133 + .../dist/inputmask/global/document.js | 11 + .../inputmask/dist/inputmask/global/window.js | 11 + .../inputmask/inputmask.date.extensions.js | 480 + .../dist/inputmask/inputmask.extensions.js | 97 + .../inputmask/dist/inputmask/inputmask.js | 1625 ++ .../inputmask/inputmask.numeric.extensions.js | 339 + .../inputmask/inputmask.phone.extensions.js | 59 + .../inputmask/inputmask.regex.extensions.js | 110 + .../dist/inputmask/jquery.inputmask.js | 62 + .../dist/inputmask/phone-codes/phone-be.js | 244 + .../dist/inputmask/phone-codes/phone-nl.js | 924 + .../dist/inputmask/phone-codes/phone-ru.js | 19240 ++++++++++++++++ .../dist/inputmask/phone-codes/phone-uk.js | 1009 + .../dist/inputmask/phone-codes/phone.js | 2111 ++ .../inputmask/dist/jquery.inputmask.bundle.js | 3055 +++ .../inputmask.date.extensions.min.js | 9 + .../min/inputmask/inputmask.extensions.min.js | 9 + .../dist/min/inputmask/inputmask.min.js | 9 + .../inputmask.numeric.extensions.min.js | 9 + .../inputmask.phone.extensions.min.js | 9 + .../inputmask.regex.extensions.min.js | 9 + .../min/inputmask/jquery.inputmask.min.js | 9 + .../dist/min/jquery.inputmask.bundle.min.js | 9 + web/bower_components/jquery/.bower.json | 25 + web/bower_components/jquery/AUTHORS.txt | 313 + web/bower_components/jquery/LICENSE.txt | 36 + web/bower_components/jquery/README.md | 67 + web/bower_components/jquery/bower.json | 14 + web/bower_components/jquery/dist/core.js | 399 + web/bower_components/jquery/dist/jquery.js | 10364 +++++++++ .../jquery/dist/jquery.min.js | 2 + .../jquery/dist/jquery.min.map | 1 + .../jquery/dist/jquery.slim.js | 8269 +++++++ .../jquery/dist/jquery.slim.min.js | 2 + .../jquery/dist/jquery.slim.min.map | 1 + .../jquery/external/sizzle/LICENSE.txt | 36 + .../jquery/external/sizzle/dist/sizzle.js | 2272 ++ .../jquery/external/sizzle/dist/sizzle.min.js | 3 + .../external/sizzle/dist/sizzle.min.map | 1 + .../jquery/src/.eslintrc.json | 5 + web/bower_components/jquery/src/ajax.js | 856 + web/bower_components/jquery/src/ajax/jsonp.js | 103 + web/bower_components/jquery/src/ajax/load.js | 77 + .../jquery/src/ajax/parseXML.js | 30 + .../jquery/src/ajax/script.js | 77 + .../jquery/src/ajax/var/location.js | 5 + .../jquery/src/ajax/var/nonce.js | 5 + .../jquery/src/ajax/var/rquery.js | 5 + web/bower_components/jquery/src/ajax/xhr.js | 170 + web/bower_components/jquery/src/attributes.js | 13 + .../jquery/src/attributes/attr.js | 141 + .../jquery/src/attributes/classes.js | 186 + .../jquery/src/attributes/prop.js | 143 + .../jquery/src/attributes/support.js | 33 + .../jquery/src/attributes/val.js | 191 + web/bower_components/jquery/src/callbacks.js | 236 + web/bower_components/jquery/src/core.js | 399 + .../jquery/src/core/DOMEval.js | 30 + .../jquery/src/core/access.js | 72 + .../jquery/src/core/camelCase.js | 23 + web/bower_components/jquery/src/core/init.js | 129 + .../jquery/src/core/nodeName.js | 13 + .../jquery/src/core/parseHTML.js | 65 + .../jquery/src/core/ready-no-deferred.js | 97 + web/bower_components/jquery/src/core/ready.js | 86 + .../jquery/src/core/readyException.js | 13 + .../jquery/src/core/stripAndCollapse.js | 14 + .../jquery/src/core/support.js | 20 + .../jquery/src/core/toType.js | 20 + .../jquery/src/core/var/rsingleTag.js | 6 + web/bower_components/jquery/src/css.js | 481 + .../jquery/src/css/addGetHookIf.js | 26 + .../jquery/src/css/adjustCSS.js | 73 + web/bower_components/jquery/src/css/curCSS.js | 65 + .../jquery/src/css/hiddenVisibleSelectors.js | 15 + .../jquery/src/css/showHide.js | 105 + .../jquery/src/css/support.js | 102 + .../jquery/src/css/var/cssExpand.js | 5 + .../jquery/src/css/var/getStyles.js | 17 + .../jquery/src/css/var/isHiddenWithinTree.js | 34 + .../jquery/src/css/var/rboxStyle.js | 7 + .../jquery/src/css/var/rnumnonpx.js | 7 + .../jquery/src/css/var/swap.js | 26 + web/bower_components/jquery/src/data.js | 180 + web/bower_components/jquery/src/data/Data.js | 162 + .../jquery/src/data/var/acceptData.js | 19 + .../jquery/src/data/var/dataPriv.js | 7 + .../jquery/src/data/var/dataUser.js | 7 + web/bower_components/jquery/src/deferred.js | 399 + .../jquery/src/deferred/exceptionHook.js | 21 + web/bower_components/jquery/src/deprecated.js | 98 + web/bower_components/jquery/src/dimensions.js | 57 + web/bower_components/jquery/src/effects.js | 702 + .../jquery/src/effects/Tween.js | 123 + .../jquery/src/effects/animatedSelector.js | 15 + web/bower_components/jquery/src/event.js | 748 + web/bower_components/jquery/src/event/ajax.js | 22 + .../jquery/src/event/alias.js | 29 + .../jquery/src/event/focusin.js | 55 + .../jquery/src/event/support.js | 11 + .../jquery/src/event/trigger.js | 199 + .../jquery/src/exports/amd.js | 26 + .../jquery/src/exports/global.js | 34 + web/bower_components/jquery/src/jquery.js | 40 + .../jquery/src/manipulation.js | 486 + .../jquery/src/manipulation/_evalUrl.js | 23 + .../jquery/src/manipulation/buildFragment.js | 105 + .../jquery/src/manipulation/getAll.js | 32 + .../jquery/src/manipulation/setGlobalEval.js | 22 + .../jquery/src/manipulation/support.js | 35 + .../src/manipulation/var/rcheckableType.js | 5 + .../src/manipulation/var/rscriptType.js | 5 + .../jquery/src/manipulation/var/rtagName.js | 5 + .../jquery/src/manipulation/wrapMap.js | 29 + web/bower_components/jquery/src/offset.js | 233 + web/bower_components/jquery/src/queue.js | 145 + .../jquery/src/queue/delay.js | 24 + .../jquery/src/selector-native.js | 237 + .../jquery/src/selector-sizzle.js | 19 + web/bower_components/jquery/src/selector.js | 3 + web/bower_components/jquery/src/serialize.js | 132 + web/bower_components/jquery/src/traversing.js | 191 + .../jquery/src/traversing/findFilter.js | 97 + .../jquery/src/traversing/var/dir.js | 22 + .../src/traversing/var/rneedsContext.js | 8 + .../jquery/src/traversing/var/siblings.js | 17 + .../jquery/src/var/ObjectFunctionString.js | 7 + web/bower_components/jquery/src/var/arr.js | 5 + .../jquery/src/var/class2type.js | 6 + web/bower_components/jquery/src/var/concat.js | 7 + .../jquery/src/var/document.js | 5 + .../jquery/src/var/documentElement.js | 7 + .../jquery/src/var/fnToString.js | 7 + .../jquery/src/var/getProto.js | 5 + web/bower_components/jquery/src/var/hasOwn.js | 7 + .../jquery/src/var/indexOf.js | 7 + .../jquery/src/var/isFunction.js | 13 + .../jquery/src/var/isWindow.js | 8 + web/bower_components/jquery/src/var/pnum.js | 5 + web/bower_components/jquery/src/var/push.js | 7 + .../jquery/src/var/rcssNum.js | 9 + .../jquery/src/var/rnothtmlwhite.js | 8 + web/bower_components/jquery/src/var/slice.js | 7 + .../jquery/src/var/support.js | 6 + .../jquery/src/var/toString.js | 7 + web/bower_components/jquery/src/wrap.js | 78 + web/css/style.css | 88 + web/images/small-loader.gif | Bin 0 -> 5631 bytes web/js/app-global.js | 15 + web/modules/employees/lib.js | 38 +- web/modules/travel/lib.js | 41 +- web/themecss/AdminLTE.css | 584 +- .../plugins/datatables/jquery.dataTables.js | 10 +- 1375 files changed, 175006 insertions(+), 2662 deletions(-) create mode 100644 core/lib/Mail/RFC822.php create mode 100644 core/lib/Mail/mail.php create mode 100644 core/lib/Mail/mock.php create mode 100644 core/lib/Mail/null.php create mode 100644 core/lib/Mail/sendmail.php create mode 100644 core/lib/Mail/smtp.php create mode 100644 core/lib/Mail/smtpmx.php mode change 120000 => 100755 core/lib/composer/vendor/bin/export-plural-rules mode change 120000 => 100755 core/lib/composer/vendor/bin/export-plural-rules.php create mode 100755 core/lib/composer/vendor/bin/markdown mode change 120000 => 100755 core/lib/composer/vendor/bin/phpunit mode change 120000 => 100755 core/lib/composer/vendor/bin/robo create mode 100644 core/lib/composer/vendor/cebe/markdown/.gitattributes create mode 100644 core/lib/composer/vendor/cebe/markdown/.gitignore create mode 100644 core/lib/composer/vendor/cebe/markdown/.scrutinizer.yml create mode 100644 core/lib/composer/vendor/cebe/markdown/.travis.yml create mode 100644 core/lib/composer/vendor/cebe/markdown/CHANGELOG.md create mode 100644 core/lib/composer/vendor/cebe/markdown/CONTRIBUTING.md create mode 100644 core/lib/composer/vendor/cebe/markdown/GithubMarkdown.php create mode 100644 core/lib/composer/vendor/cebe/markdown/LICENSE create mode 100644 core/lib/composer/vendor/cebe/markdown/Markdown.php create mode 100644 core/lib/composer/vendor/cebe/markdown/MarkdownExtra.php create mode 100644 core/lib/composer/vendor/cebe/markdown/Parser.php create mode 100644 core/lib/composer/vendor/cebe/markdown/README.md create mode 100755 core/lib/composer/vendor/cebe/markdown/bin/markdown create mode 100644 core/lib/composer/vendor/cebe/markdown/block/CodeTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/block/FencedCodeTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/block/HeadlineTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/block/HtmlTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/block/ListTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/block/QuoteTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/block/RuleTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/block/TableTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/composer.json create mode 100644 core/lib/composer/vendor/cebe/markdown/inline/CodeTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/inline/EmphStrongTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/inline/LinkTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/inline/StrikeoutTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/inline/UrlLinkTrait.php create mode 100644 core/lib/composer/vendor/cebe/markdown/phpunit.xml.dist create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/BaseMarkdownTest.php create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/GithubMarkdownTest.php create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/MarkdownExtraTest.php create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/MarkdownOLStartNumTest.php create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/MarkdownTest.php create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/ParserTest.php create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/bootstrap.php create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/code_in_lists.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/code_in_lists.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/fenced-code.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/fenced-code.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/non-tables.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/non-tables.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/special-attributes.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/special-attributes.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/tables.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/tables.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/test_precedence.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/extra-data/test_precedence.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/code_in_lists.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/code_in_lists.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/del.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/del.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers2.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers2.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/github-basics.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/github-basics.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/github-code-in-numbered-list.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/github-code-in-numbered-list.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/github-sample.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/github-sample.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-33.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-33.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-38.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-38.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-50.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-50.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/lists.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/lists.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/non-tables.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/non-tables.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/tables.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/tables.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/test_precedence.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/test_precedence.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/url.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/github-data/url.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/README create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote-nested.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote-nested.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/code.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/code.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dense-block-markers.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dense-block-markers.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos2.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos2.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/emphasis.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/emphasis.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/empty-line.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/empty-line.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/endless_loop_bug.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/endless_loop_bug.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/escape-in-link.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/escape-in-link.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/headline.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/headline.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/hr.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/hr.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/html-block.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/html-block.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/images.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/images.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/inline-html.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/inline-html.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/lazy-list.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/lazy-list.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/links.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/links.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-marker-in-paragraph.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-marker-in-paragraph.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-separated-by-hr.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-separated-by-hr.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_and_reference.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_and_reference.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_items_with_undefined_ref.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_items_with_undefined_ref.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_amps_and_angle_encoding.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_amps_and_angle_encoding.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_auto_links.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_auto_links.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_backslash_escapes.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_backslash_escapes.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_blockquotes_with_code_blocks.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_blockquotes_with_code_blocks.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_horizontal_rules.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_horizontal_rules.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_avanced.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_avanced.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_comments.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_comments.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_simple.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_simple.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_inline_style.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_inline_style.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_reference_style.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_reference_style.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_literal_quotes_in_titles.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_literal_quotes_in_titles.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_markdown_documentation_basics.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_markdown_documentation_basics.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_nested_blockquotes.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_nested_blockquotes.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_ordered_and_unordered_lists.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_ordered_and_unordered_lists.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_strong_and_em_together.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_strong_and_em_together.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tabs.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tabs.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tidyness.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tidyness.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/nested-lists.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/nested-lists.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/newline.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/newline.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/paragraph.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/paragraph.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/references.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/references.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/specs.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/specs.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/test_precedence.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/test_precedence.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/unicode.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/unicode.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/utf8-do-not-kill-characters.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-data/utf8-do-not-kill-characters.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/list.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/list.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/md1_ordered_and_unordered_lists.html create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/md1_ordered_and_unordered_lists.md create mode 100644 core/lib/composer/vendor/cebe/markdown/tests/profile.php delete mode 120000 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Config.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/ConfigInterface.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/GlobalOptionDefaultValuesInterface.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Inject/ConfigForCommand.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Inject/ConfigForSetters.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigLoader.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigLoaderInterface.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigProcessor.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/YamlConfigLoader.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ArrayUtil.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigFallback.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigGroup.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigMerge.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigOverlay.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/EnvConfig.php delete mode 120000 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigForCommandTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigForSettersTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigGroupTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigLoaderTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigOverlayTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigProcessorTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-1.yml create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-2.yml create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-3.yml create mode 100755 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/install-scenario create mode 100755 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/prep-dependencies create mode 100755 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/scenarios create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/ApplyConfigTestTarget.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/MyFooCommand.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/TestLoader.php delete mode 120000 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Config.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/ConfigInterface.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/GlobalOptionDefaultValuesInterface.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Inject/ConfigForCommand.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Inject/ConfigForSetters.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigLoader.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigLoaderInterface.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigProcessor.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/YamlConfigLoader.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ArrayUtil.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigFallback.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigGroup.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigMerge.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigOverlay.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/EnvConfig.php delete mode 120000 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigForCommandTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigForSettersTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigGroupTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigLoaderTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigOverlayTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigProcessorTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigTest.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-1.yml create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-2.yml create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-3.yml create mode 100755 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/install-scenario create mode 100755 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/prep-dependencies create mode 100755 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/scenarios create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/ApplyConfigTestTarget.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/MyFooCommand.php create mode 100644 core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/TestLoader.php delete mode 120000 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Application.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CallableTask.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Collection.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionBuilder.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionProcessHook.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CompletionWrapper.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Element.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/NestedCollectionInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/TaskForEach.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Temporary.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/BuilderAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/CommandArguments.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/CommandReceiver.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ConfigAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/DynamicParams.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecCommand.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecOneCommand.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/IO.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/InflectionTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/InputAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/OutputAdapter.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/OutputAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProcessExecutor.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProcessUtils.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProgressIndicator.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProgressIndicatorAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ResourceExistenceChecker.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/TaskIO.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/TimeKeeper.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/Timer.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/VerbosityThresholdTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config/Config.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config/GlobalOptionDefaultValuesInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/BuilderAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/CommandInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/CompletionInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/ConfigAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/IOAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/InflectionInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/OutputAdapterInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/OutputAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/PrintedInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/ProgressIndicatorAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/ProgressInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/RollbackInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/SimulatedInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/TaskInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/VerbosityThresholdInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/WrappedTaskInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Exception/TaskException.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Exception/TaskExitException.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/GlobalOptionsEventListener.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/LoadAllTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/ResultPrinter.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogLevel.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogStyle.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogger.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Result.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/ResultData.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Robo.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Runner.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/SelfUpdateCommand.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/Consumer.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/Data.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/StateAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/StateAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/ApiGen/ApiGen.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/ApiGen/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/Extract.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/Pack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/CssPreprocessor.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/ImageMinify.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Less.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Minify.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Scss.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/Exec.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/ExecStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/ParallelExec.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/SymfonyCommand.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/Watch.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/loadShortcuts.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/BaseTask.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Install.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Update.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/CommandStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Config.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/CreateProject.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/DumpAutoload.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Init.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Install.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Remove.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/RequireDependency.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Update.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Validate.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/Changelog.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GenerateMarkdownDoc.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GenerateTask.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GitHub.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GitHubRelease.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/OpenBrowser.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/PackPhar.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/PhpServer.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/SemVer.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Build.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Commit.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Exec.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Pull.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Remove.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Result.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Run.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Start.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Stop.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Concat.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Replace.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/TmpFile.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Write.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/BaseDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/CleanDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/CopyDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/DeleteDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/FilesystemStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/FlattenDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/MirrorDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/TmpDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/WorkDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/loadShortcuts.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/Run.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Install.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Update.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/Rsync.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/Ssh.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Simulator.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/StackBasedTask.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Atoum.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Behat.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Codecept.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/PHPUnit.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Phpspec.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/GitStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/HgStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/SvnStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/loadShortcuts.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/TaskAccessor.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/TaskInfo.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Tasks.php delete mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/tests/.gitkeep delete mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/.gitkeep delete mode 120000 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Application.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CallableTask.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Collection.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionBuilder.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionProcessHook.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CompletionWrapper.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Element.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/NestedCollectionInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/TaskForEach.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Temporary.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/BuilderAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/CommandArguments.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/CommandReceiver.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ConfigAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/DynamicParams.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecCommand.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecOneCommand.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/IO.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/InflectionTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/InputAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/OutputAdapter.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/OutputAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProcessExecutor.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProcessUtils.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProgressIndicator.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProgressIndicatorAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ResourceExistenceChecker.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/TaskIO.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/TimeKeeper.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/Timer.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/VerbosityThresholdTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config/Config.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config/GlobalOptionDefaultValuesInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/BuilderAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/CommandInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/CompletionInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/ConfigAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/IOAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/InflectionInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/OutputAdapterInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/OutputAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/PrintedInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/ProgressIndicatorAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/ProgressInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/RollbackInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/SimulatedInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/TaskInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/VerbosityThresholdInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/WrappedTaskInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Exception/TaskException.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Exception/TaskExitException.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/GlobalOptionsEventListener.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/LoadAllTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/ResultPrinter.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogLevel.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogStyle.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogger.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Result.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/ResultData.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Robo.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Runner.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/SelfUpdateCommand.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/Consumer.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/Data.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/StateAwareInterface.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/StateAwareTrait.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/ApiGen/ApiGen.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/ApiGen/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/Extract.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/Pack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/CssPreprocessor.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/ImageMinify.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Less.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Minify.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Scss.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/Exec.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/ExecStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/ParallelExec.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/SymfonyCommand.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/Watch.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/loadShortcuts.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/BaseTask.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Install.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Update.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/CommandStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Config.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/CreateProject.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/DumpAutoload.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Init.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Install.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Remove.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/RequireDependency.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Update.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Validate.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/Changelog.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GenerateMarkdownDoc.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GenerateTask.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GitHub.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GitHubRelease.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/OpenBrowser.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/PackPhar.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/PhpServer.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/SemVer.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Build.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Commit.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Exec.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Pull.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Remove.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Result.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Run.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Start.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Stop.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Concat.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Replace.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/TmpFile.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Write.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/BaseDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/CleanDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/CopyDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/DeleteDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/FilesystemStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/FlattenDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/MirrorDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/TmpDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/WorkDir.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/loadShortcuts.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/Run.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Base.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Install.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Update.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/Rsync.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/Ssh.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Simulator.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/StackBasedTask.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Atoum.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Behat.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Codecept.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/PHPUnit.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Phpspec.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/GitStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/HgStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/SvnStack.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/loadShortcuts.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/loadTasks.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/TaskAccessor.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/TaskInfo.php create mode 100644 core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Tasks.php delete mode 120000 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/src create mode 100644 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/src/Expander.php delete mode 120000 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests create mode 100644 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests/phpunit/ExpanderTest.php create mode 100644 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests/resources/valid.yml delete mode 120000 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/src create mode 100644 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/src/Expander.php delete mode 120000 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests create mode 100644 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests/phpunit/ExpanderTest.php create mode 100644 core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests/resources/valid.yml delete mode 100644 core/lib/composer/vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep create mode 100644 core/lib/composer/vendor/neitanod/forceutf8/README.md create mode 100644 core/lib/composer/vendor/neitanod/forceutf8/composer.json create mode 100644 core/lib/composer/vendor/neitanod/forceutf8/src/ForceUTF8/Encoding.php create mode 100644 core/lib/composer/vendor/neitanod/forceutf8/test/ForceUTF8Test.php create mode 100644 core/lib/composer/vendor/neitanod/forceutf8/test/Test.class.php create mode 100644 core/lib/composer/vendor/neitanod/forceutf8/test/data/russian.txt create mode 100644 core/lib/composer/vendor/neitanod/forceutf8/test/data/test1.txt create mode 100644 core/lib/composer/vendor/neitanod/forceutf8/test/data/test1Latin.txt mode change 120000 => 100644 core/lib/composer/vendor/pear/net_smtp/README.rst rename core/lib/composer/vendor/phpunit/phpunit/src/Util/{XML.php => Xml.php} (100%) rename core/lib/composer/vendor/phpunit/phpunit/tests/Util/{XMLTest.php => XmlTest.php} (100%) create mode 100644 core/lib/composer/vendor/spomky-labs/base64url/LICENSE create mode 100644 core/lib/composer/vendor/spomky-labs/base64url/composer.json create mode 100644 core/lib/composer/vendor/spomky-labs/base64url/src/Base64Url.php create mode 100644 core/migrations/v20180507_230001_update_travel_record_type.php create mode 100644 core/migrations/v20180514_230002_add_conversation_tables.php create mode 100644 core/templates/app/company_announcement.html create mode 100644 core/templates/menu/menuButtonLanguage.html create mode 100644 web/api/ConversationsAdapter.js create mode 100644 web/bower_components/flag-icon-css/.bower.json create mode 100644 web/bower_components/flag-icon-css/README.md create mode 100644 web/bower_components/flag-icon-css/bower.json create mode 100644 web/bower_components/flag-icon-css/composer.json create mode 100644 web/bower_components/flag-icon-css/css/flag-icon.css create mode 100644 web/bower_components/flag-icon-css/css/flag-icon.min.css create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ad.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ae.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/af.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ag.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ai.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/al.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/am.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ao.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/aq.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ar.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/as.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/at.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/au.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/aw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ax.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/az.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ba.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bb.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bd.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/be.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bf.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bh.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bi.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bj.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bl.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bo.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bq.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/br.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bs.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bt.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bv.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/by.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/bz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ca.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cc.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cd.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cf.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ch.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ci.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ck.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cl.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/co.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cu.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cv.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cx.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cy.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/cz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/de.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/dj.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/dk.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/dm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/do.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/dz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ec.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ee.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/eg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/eh.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/er.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/es-ct.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/es.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/et.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/eu.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/fi.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/fj.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/fk.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/fm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/fo.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/fr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ga.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gb-eng.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gb-nir.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gb-sct.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gb-wls.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gb.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gd.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ge.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gf.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gh.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gi.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gl.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gp.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gq.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gs.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gt.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gu.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/gy.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/hk.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/hm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/hn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/hr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ht.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/hu.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/id.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ie.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/il.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/im.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/in.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/io.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/iq.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ir.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/is.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/it.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/je.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/jm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/jo.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/jp.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ke.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/kg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/kh.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ki.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/km.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/kn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/kp.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/kr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/kw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ky.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/kz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/la.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/lb.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/lc.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/li.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/lk.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/lr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ls.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/lt.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/lu.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/lv.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ly.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ma.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mc.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/md.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/me.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mf.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mh.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mk.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ml.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mo.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mp.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mq.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ms.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mt.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mu.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mv.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mx.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/my.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/mz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/na.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/nc.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ne.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/nf.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ng.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ni.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/nl.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/no.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/np.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/nr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/nu.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/nz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/om.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pa.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pe.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pf.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ph.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pk.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pl.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ps.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pt.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/pw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/py.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/qa.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/re.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ro.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/rs.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ru.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/rw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sa.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sb.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sc.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sd.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/se.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sh.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/si.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sj.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sk.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sl.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/so.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ss.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/st.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sv.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sx.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sy.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/sz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tc.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/td.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tf.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/th.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tj.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tk.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tl.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/to.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tr.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tt.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tv.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tw.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/tz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ua.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ug.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/um.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/un.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/us.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/uy.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/uz.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/va.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/vc.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ve.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/vg.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/vi.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/vn.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/vu.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/wf.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ws.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/ye.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/yt.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/za.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/zm.svg create mode 100644 web/bower_components/flag-icon-css/flags/1x1/zw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ad.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ae.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/af.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ag.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ai.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/al.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/am.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ao.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/aq.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ar.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/as.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/at.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/au.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/aw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ax.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/az.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ba.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bb.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bd.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/be.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bf.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bh.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bi.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bj.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bl.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bo.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bq.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/br.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bs.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bt.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bv.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/by.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/bz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ca.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cc.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cd.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cf.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ch.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ci.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ck.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cl.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/co.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cu.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cv.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cx.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cy.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/cz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/de.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/dj.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/dk.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/dm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/do.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/dz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ec.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ee.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/eg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/eh.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/er.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/es-ct.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/es.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/et.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/eu.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/fi.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/fj.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/fk.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/fm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/fo.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/fr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ga.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gb-eng.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gb-nir.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gb-sct.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gb-wls.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gb.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gd.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ge.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gf.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gh.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gi.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gl.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gp.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gq.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gs.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gt.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gu.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/gy.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/hk.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/hm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/hn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/hr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ht.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/hu.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/id.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ie.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/il.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/im.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/in.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/io.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/iq.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ir.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/is.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/it.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/je.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/jm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/jo.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/jp.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ke.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/kg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/kh.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ki.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/km.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/kn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/kp.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/kr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/kw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ky.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/kz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/la.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/lb.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/lc.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/li.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/lk.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/lr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ls.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/lt.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/lu.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/lv.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ly.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ma.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mc.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/md.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/me.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mf.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mh.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mk.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ml.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mo.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mp.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mq.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ms.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mt.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mu.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mv.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mx.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/my.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/mz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/na.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/nc.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ne.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/nf.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ng.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ni.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/nl.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/no.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/np.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/nr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/nu.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/nz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/om.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pa.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pe.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pf.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ph.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pk.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pl.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ps.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pt.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/pw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/py.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/qa.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/re.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ro.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/rs.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ru.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/rw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sa.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sb.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sc.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sd.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/se.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sh.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/si.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sj.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sk.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sl.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/so.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ss.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/st.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sv.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sx.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sy.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/sz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tc.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/td.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tf.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/th.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tj.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tk.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tl.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/to.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tr.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tt.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tv.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tw.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/tz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ua.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ug.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/um.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/un.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/us.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/uy.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/uz.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/va.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/vc.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ve.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/vg.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/vi.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/vn.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/vu.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/wf.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ws.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/ye.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/yt.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/za.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/zm.svg create mode 100644 web/bower_components/flag-icon-css/flags/4x3/zw.svg create mode 100644 web/bower_components/flag-icon-css/less/flag-icon-base.less create mode 100644 web/bower_components/flag-icon-css/less/flag-icon-list.less create mode 100644 web/bower_components/flag-icon-css/less/flag-icon-more.less create mode 100644 web/bower_components/flag-icon-css/less/flag-icon.less create mode 100644 web/bower_components/flag-icon-css/less/variables.less create mode 100644 web/bower_components/flag-icon-css/sass/_flag-icon-base.scss create mode 100644 web/bower_components/flag-icon-css/sass/_flag-icon-list.scss create mode 100644 web/bower_components/flag-icon-css/sass/_flag-icon-more.scss create mode 100644 web/bower_components/flag-icon-css/sass/_variables.scss create mode 100644 web/bower_components/flag-icon-css/sass/flag-icon.scss create mode 100644 web/bower_components/flag-icon-css/svgo.yaml create mode 100644 web/bower_components/flag-icon-css/yarn.lock create mode 100644 web/bower_components/inputmask/.bower.json create mode 100644 web/bower_components/inputmask/bower.json create mode 100644 web/bower_components/inputmask/dist/inputmask/bindings/inputmask.binding.js create mode 100644 web/bower_components/inputmask/dist/inputmask/dependencyLibs/inputmask.dependencyLib.jqlite.js create mode 100644 web/bower_components/inputmask/dist/inputmask/dependencyLibs/inputmask.dependencyLib.jquery.js create mode 100644 web/bower_components/inputmask/dist/inputmask/dependencyLibs/inputmask.dependencyLib.js create mode 100644 web/bower_components/inputmask/dist/inputmask/global/document.js create mode 100644 web/bower_components/inputmask/dist/inputmask/global/window.js create mode 100644 web/bower_components/inputmask/dist/inputmask/inputmask.date.extensions.js create mode 100644 web/bower_components/inputmask/dist/inputmask/inputmask.extensions.js create mode 100644 web/bower_components/inputmask/dist/inputmask/inputmask.js create mode 100644 web/bower_components/inputmask/dist/inputmask/inputmask.numeric.extensions.js create mode 100644 web/bower_components/inputmask/dist/inputmask/inputmask.phone.extensions.js create mode 100644 web/bower_components/inputmask/dist/inputmask/inputmask.regex.extensions.js create mode 100644 web/bower_components/inputmask/dist/inputmask/jquery.inputmask.js create mode 100644 web/bower_components/inputmask/dist/inputmask/phone-codes/phone-be.js create mode 100644 web/bower_components/inputmask/dist/inputmask/phone-codes/phone-nl.js create mode 100644 web/bower_components/inputmask/dist/inputmask/phone-codes/phone-ru.js create mode 100644 web/bower_components/inputmask/dist/inputmask/phone-codes/phone-uk.js create mode 100644 web/bower_components/inputmask/dist/inputmask/phone-codes/phone.js create mode 100644 web/bower_components/inputmask/dist/jquery.inputmask.bundle.js create mode 100644 web/bower_components/inputmask/dist/min/inputmask/inputmask.date.extensions.min.js create mode 100644 web/bower_components/inputmask/dist/min/inputmask/inputmask.extensions.min.js create mode 100644 web/bower_components/inputmask/dist/min/inputmask/inputmask.min.js create mode 100644 web/bower_components/inputmask/dist/min/inputmask/inputmask.numeric.extensions.min.js create mode 100644 web/bower_components/inputmask/dist/min/inputmask/inputmask.phone.extensions.min.js create mode 100644 web/bower_components/inputmask/dist/min/inputmask/inputmask.regex.extensions.min.js create mode 100644 web/bower_components/inputmask/dist/min/inputmask/jquery.inputmask.min.js create mode 100644 web/bower_components/inputmask/dist/min/jquery.inputmask.bundle.min.js create mode 100644 web/bower_components/jquery/.bower.json create mode 100644 web/bower_components/jquery/AUTHORS.txt create mode 100644 web/bower_components/jquery/LICENSE.txt create mode 100644 web/bower_components/jquery/README.md create mode 100644 web/bower_components/jquery/bower.json create mode 100644 web/bower_components/jquery/dist/core.js create mode 100644 web/bower_components/jquery/dist/jquery.js create mode 100644 web/bower_components/jquery/dist/jquery.min.js create mode 100644 web/bower_components/jquery/dist/jquery.min.map create mode 100644 web/bower_components/jquery/dist/jquery.slim.js create mode 100644 web/bower_components/jquery/dist/jquery.slim.min.js create mode 100644 web/bower_components/jquery/dist/jquery.slim.min.map create mode 100644 web/bower_components/jquery/external/sizzle/LICENSE.txt create mode 100644 web/bower_components/jquery/external/sizzle/dist/sizzle.js create mode 100644 web/bower_components/jquery/external/sizzle/dist/sizzle.min.js create mode 100644 web/bower_components/jquery/external/sizzle/dist/sizzle.min.map create mode 100644 web/bower_components/jquery/src/.eslintrc.json create mode 100644 web/bower_components/jquery/src/ajax.js create mode 100644 web/bower_components/jquery/src/ajax/jsonp.js create mode 100644 web/bower_components/jquery/src/ajax/load.js create mode 100644 web/bower_components/jquery/src/ajax/parseXML.js create mode 100644 web/bower_components/jquery/src/ajax/script.js create mode 100644 web/bower_components/jquery/src/ajax/var/location.js create mode 100644 web/bower_components/jquery/src/ajax/var/nonce.js create mode 100644 web/bower_components/jquery/src/ajax/var/rquery.js create mode 100644 web/bower_components/jquery/src/ajax/xhr.js create mode 100644 web/bower_components/jquery/src/attributes.js create mode 100644 web/bower_components/jquery/src/attributes/attr.js create mode 100644 web/bower_components/jquery/src/attributes/classes.js create mode 100644 web/bower_components/jquery/src/attributes/prop.js create mode 100644 web/bower_components/jquery/src/attributes/support.js create mode 100644 web/bower_components/jquery/src/attributes/val.js create mode 100644 web/bower_components/jquery/src/callbacks.js create mode 100644 web/bower_components/jquery/src/core.js create mode 100644 web/bower_components/jquery/src/core/DOMEval.js create mode 100644 web/bower_components/jquery/src/core/access.js create mode 100644 web/bower_components/jquery/src/core/camelCase.js create mode 100644 web/bower_components/jquery/src/core/init.js create mode 100644 web/bower_components/jquery/src/core/nodeName.js create mode 100644 web/bower_components/jquery/src/core/parseHTML.js create mode 100644 web/bower_components/jquery/src/core/ready-no-deferred.js create mode 100644 web/bower_components/jquery/src/core/ready.js create mode 100644 web/bower_components/jquery/src/core/readyException.js create mode 100644 web/bower_components/jquery/src/core/stripAndCollapse.js create mode 100644 web/bower_components/jquery/src/core/support.js create mode 100644 web/bower_components/jquery/src/core/toType.js create mode 100644 web/bower_components/jquery/src/core/var/rsingleTag.js create mode 100644 web/bower_components/jquery/src/css.js create mode 100644 web/bower_components/jquery/src/css/addGetHookIf.js create mode 100644 web/bower_components/jquery/src/css/adjustCSS.js create mode 100644 web/bower_components/jquery/src/css/curCSS.js create mode 100644 web/bower_components/jquery/src/css/hiddenVisibleSelectors.js create mode 100644 web/bower_components/jquery/src/css/showHide.js create mode 100644 web/bower_components/jquery/src/css/support.js create mode 100644 web/bower_components/jquery/src/css/var/cssExpand.js create mode 100644 web/bower_components/jquery/src/css/var/getStyles.js create mode 100644 web/bower_components/jquery/src/css/var/isHiddenWithinTree.js create mode 100644 web/bower_components/jquery/src/css/var/rboxStyle.js create mode 100644 web/bower_components/jquery/src/css/var/rnumnonpx.js create mode 100644 web/bower_components/jquery/src/css/var/swap.js create mode 100644 web/bower_components/jquery/src/data.js create mode 100644 web/bower_components/jquery/src/data/Data.js create mode 100644 web/bower_components/jquery/src/data/var/acceptData.js create mode 100644 web/bower_components/jquery/src/data/var/dataPriv.js create mode 100644 web/bower_components/jquery/src/data/var/dataUser.js create mode 100644 web/bower_components/jquery/src/deferred.js create mode 100644 web/bower_components/jquery/src/deferred/exceptionHook.js create mode 100644 web/bower_components/jquery/src/deprecated.js create mode 100644 web/bower_components/jquery/src/dimensions.js create mode 100644 web/bower_components/jquery/src/effects.js create mode 100644 web/bower_components/jquery/src/effects/Tween.js create mode 100644 web/bower_components/jquery/src/effects/animatedSelector.js create mode 100644 web/bower_components/jquery/src/event.js create mode 100644 web/bower_components/jquery/src/event/ajax.js create mode 100644 web/bower_components/jquery/src/event/alias.js create mode 100644 web/bower_components/jquery/src/event/focusin.js create mode 100644 web/bower_components/jquery/src/event/support.js create mode 100644 web/bower_components/jquery/src/event/trigger.js create mode 100644 web/bower_components/jquery/src/exports/amd.js create mode 100644 web/bower_components/jquery/src/exports/global.js create mode 100644 web/bower_components/jquery/src/jquery.js create mode 100644 web/bower_components/jquery/src/manipulation.js create mode 100644 web/bower_components/jquery/src/manipulation/_evalUrl.js create mode 100644 web/bower_components/jquery/src/manipulation/buildFragment.js create mode 100644 web/bower_components/jquery/src/manipulation/getAll.js create mode 100644 web/bower_components/jquery/src/manipulation/setGlobalEval.js create mode 100644 web/bower_components/jquery/src/manipulation/support.js create mode 100644 web/bower_components/jquery/src/manipulation/var/rcheckableType.js create mode 100644 web/bower_components/jquery/src/manipulation/var/rscriptType.js create mode 100644 web/bower_components/jquery/src/manipulation/var/rtagName.js create mode 100644 web/bower_components/jquery/src/manipulation/wrapMap.js create mode 100644 web/bower_components/jquery/src/offset.js create mode 100644 web/bower_components/jquery/src/queue.js create mode 100644 web/bower_components/jquery/src/queue/delay.js create mode 100644 web/bower_components/jquery/src/selector-native.js create mode 100644 web/bower_components/jquery/src/selector-sizzle.js create mode 100644 web/bower_components/jquery/src/selector.js create mode 100644 web/bower_components/jquery/src/serialize.js create mode 100644 web/bower_components/jquery/src/traversing.js create mode 100644 web/bower_components/jquery/src/traversing/findFilter.js create mode 100644 web/bower_components/jquery/src/traversing/var/dir.js create mode 100644 web/bower_components/jquery/src/traversing/var/rneedsContext.js create mode 100644 web/bower_components/jquery/src/traversing/var/siblings.js create mode 100644 web/bower_components/jquery/src/var/ObjectFunctionString.js create mode 100644 web/bower_components/jquery/src/var/arr.js create mode 100644 web/bower_components/jquery/src/var/class2type.js create mode 100644 web/bower_components/jquery/src/var/concat.js create mode 100644 web/bower_components/jquery/src/var/document.js create mode 100644 web/bower_components/jquery/src/var/documentElement.js create mode 100644 web/bower_components/jquery/src/var/fnToString.js create mode 100644 web/bower_components/jquery/src/var/getProto.js create mode 100644 web/bower_components/jquery/src/var/hasOwn.js create mode 100644 web/bower_components/jquery/src/var/indexOf.js create mode 100644 web/bower_components/jquery/src/var/isFunction.js create mode 100644 web/bower_components/jquery/src/var/isWindow.js create mode 100644 web/bower_components/jquery/src/var/pnum.js create mode 100644 web/bower_components/jquery/src/var/push.js create mode 100644 web/bower_components/jquery/src/var/rcssNum.js create mode 100644 web/bower_components/jquery/src/var/rnothtmlwhite.js create mode 100644 web/bower_components/jquery/src/var/slice.js create mode 100644 web/bower_components/jquery/src/var/support.js create mode 100644 web/bower_components/jquery/src/var/toString.js create mode 100644 web/bower_components/jquery/src/wrap.js create mode 100644 web/images/small-loader.gif diff --git a/bower.json b/bower.json index c43cdc73..c77119ae 100644 --- a/bower.json +++ b/bower.json @@ -13,6 +13,8 @@ "d3-timeline": "^0.0.5", "vis": "^4.21.0", "handlebars": "^4.0.11", - "material-design-icons": "^3.0.1" + "material-design-icons": "^3.0.1", + "inputmask": "~3.3.11", + "flag-icon-css": "~3.1.0" } } diff --git a/build.xml b/build.xml index 727e13a5..622aa124 100644 --- a/build.xml +++ b/build.xml @@ -45,7 +45,6 @@ depends="clean" description="Prepare for build"> - @@ -81,7 +80,7 @@ - + @@ -95,7 +94,7 @@ - + diff --git a/core/admin/employees/customTemplates/myDetails.html b/core/admin/employees/customTemplates/myDetails.html index 50a46729..82b22bce 100644 --- a/core/admin/employees/customTemplates/myDetails.html +++ b/core/admin/employees/customTemplates/myDetails.html @@ -21,9 +21,9 @@
- - - + + +
@@ -46,17 +46,17 @@
-

Personal Information

+

Personal Information

@@ -93,7 +93,7 @@
-

Contact Information

+

Contact Information

@@ -133,7 +133,7 @@
-

Job Details

+

Job Details

@@ -170,7 +170,7 @@
- +
- +
@@ -196,8 +196,8 @@
@@ -250,4 +250,4 @@
-
\ No newline at end of file +
diff --git a/core/admin/fieldnames/meta.json b/core/admin/fieldnames/meta.json index e694b9eb..76530f4a 100644 --- a/core/admin/fieldnames/meta.json +++ b/core/admin/fieldnames/meta.json @@ -1,8 +1,8 @@ { - "label": "Field Names Setup", - "menu": "System", - "order": "7", - "icon": "fa-sort-alpha-asc", + "label": "Employee Custom Fields", + "menu": "Admin", + "order": "83", + "icon": "fa-sliders", "user_levels": [ "Admin" ], diff --git a/core/admin/travel/index.php b/core/admin/travel/index.php index 723f6909..0ce5216b 100644 --- a/core/admin/travel/index.php +++ b/core/admin/travel/index.php @@ -26,10 +26,16 @@ define('MODULE_PATH',dirname(__FILE__)); include APP_BASE_PATH.'header.php'; include APP_BASE_PATH.'modulejslibs.inc.php'; -$options = array(); -$options['setRemoteTable'] = 'true'; +$customFields = \Classes\BaseService::getInstance()->getCustomFields("EmployeeTravelRecord"); + +$travelRequestOptions = []; +$travelRequestOptions['setRemoteTable'] = 'true'; +$travelRequestOptions['setCustomFields'] = json_encode($customFields); + + $moduleBuilder = new \Classes\ModuleBuilder\ModuleBuilder(); + $moduleBuilder->addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab( 'EmployeeTravelRecord', 'EmployeeTravelRecord', @@ -38,8 +44,26 @@ $moduleBuilder->addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab( '', '', true, - $options + $travelRequestOptions )); + +if ($user->user_level === 'Admin') { + $travelCustomFieldOptions = []; + $travelCustomFieldOptions['setRemoteTable'] = 'true'; + $travelCustomFieldOptions['setTableType'] = '\'EmployeeTravelRecord\''; + + $moduleBuilder->addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab( + 'TravelCustomField', + 'CustomField', + 'Custom Fields', + 'CustomFieldAdapter', + '{"type":"EmployeeTravelRecord"}', + '', + false, + $travelCustomFieldOptions + )); +} + echo \Classes\UIManager::getInstance()->renderModule($moduleBuilder); diff --git a/core/config.base.php b/core/config.base.php index 00202e98..ff3da3c6 100644 --- a/core/config.base.php +++ b/core/config.base.php @@ -13,10 +13,10 @@ if(!defined('HOME_LINK_OTHERS')){ } //Version -define('VERSION', '22.0.0.OS'); -define('CACHE_VALUE', '22.0.0.OS'); -define('VERSION_NUMBER', '2200'); -define('VERSION_DATE', '28/04/2018'); +define('VERSION', '23.0.0.OS'); +define('CACHE_VALUE', '23.0.0.OS'); +define('VERSION_NUMBER', '2300'); +define('VERSION_DATE', '21/05/2018'); if(!defined('CONTACT_EMAIL')){define('CONTACT_EMAIL','icehrm@gamonoid.com');} if(!defined('KEY_PREFIX')){define('KEY_PREFIX','IceHrm');} diff --git a/core/configureUIManager.php b/core/configureUIManager.php index 9f2311a8..63e16319 100644 --- a/core/configureUIManager.php +++ b/core/configureUIManager.php @@ -11,3 +11,9 @@ foreach($moduleManagers as $moduleManagerObj){ $moduleManagerObj->initQuickAccessMenu(); } } + +$supportedLanguage = new \Metadata\Common\Model\SupportedLanguage(); +$supportedLanguages = $supportedLanguage->Find("1 = 1", []); +foreach ($supportedLanguages as $supportedLanguage) { + \Classes\UIManager::getInstance()->addLanguageMenuItem($supportedLanguage->name); +} diff --git a/core/header.php b/core/header.php index 9fac8d16..d2ded4d4 100644 --- a/core/header.php +++ b/core/header.php @@ -24,10 +24,11 @@ if (!defined('MODULE_NAME')) { define('MODULE_NAME', $moduleName); } include 'includes.inc.php'; + if(empty($user)){ - $actual_link = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; - \Utils\SessionUtils::saveSessionObject('loginRedirect',$actual_link); - header("Location:".CLIENT_BASE_URL."login.php"); + $actualLink = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; + header("Location:".CLIENT_BASE_URL."login.php?next=".\Base64Url\Base64Url::encode($actualLink)); + exit(); } if(empty($user->default_module)){ @@ -144,6 +145,7 @@ include('configureUIManager.php'); + @@ -157,6 +159,7 @@ include('configureUIManager.php'); + @@ -167,6 +170,7 @@ include('configureUIManager.php'); + diff --git a/core/includes.inc.php b/core/includes.inc.php index 3a3002cc..3589eb44 100644 --- a/core/includes.inc.php +++ b/core/includes.inc.php @@ -119,7 +119,7 @@ if(is_dir(MODULE_PATH.'/customTemplates/')){ $ams = scandir(MODULE_PATH.'/customTemplates/'); foreach($ams as $am){ if(!is_dir(MODULE_PATH.'/customTemplates/'.$am) && $am != '.' && $am != '..'){ - $customTemplates[$am] = file_get_contents(MODULE_PATH.'/customTemplates/'.$am); + $customTemplates[$am] = t(file_get_contents(MODULE_PATH.'/customTemplates/'.$am)); } } } diff --git a/core/lang/de.po b/core/lang/de.po index 4736a75f..d3eea6e6 100644 --- a/core/lang/de.po +++ b/core/lang/de.po @@ -1597,3 +1597,309 @@ msgstr "Anwenden" msgid "Back" msgstr "Zurück" + +msgid "Hours in Time Sheets" +msgstr "Stunden in Time Sheets" + +msgid "HR form" +msgstr "HR-Formular" + +msgid "HR Form Management" +msgstr "HR-Formular-Management" + +msgid "Form Name" +msgstr "Formularname" + +msgid "Fields" +msgstr "Felder" + +msgid "Employee Froms" +msgstr "Mitarbeiter Froms" + +msgid "Share Departments" +msgstr "Teilen Abteilungen" + +msgid "Share Employees" +msgstr "Aktie Mitarbeiter" + +msgid "Data Importers" +msgstr "Daten Importeure" + +msgid "Data Import Files" +msgstr "Data Import von Dateien" + +msgid "Data Type" +msgstr "Datentyp" + +msgid "Columns" +msgstr "Säulen" + +msgid "Field Title" +msgstr "Feld Titel" + +msgid "Depends On" +msgstr "Kommt drauf an" + +msgid "Depends On Field" +msgstr "Hängt Auf Feld" + +msgid "is Key Field" +msgstr "Schlüsselfeld ist" + +msgid "is ID Field" +msgstr "ID-Feld ist" + +msgid "Data Import Definitions" +msgstr "Datenimport Definitionen" + +msgid "File to Import" +msgstr "Datei zu importieren" + +msgid "Last Export Results" +msgstr "Letzte Ergebnisse exportieren" + +msgid "Time and Attendance" +msgstr "Zeit und Anwesenheit" + +msgid "Leave Timeline" +msgstr "Lassen Sie Timeline" + +msgid "Insights" +msgstr "Insights" + +msgid "Api Access" +msgstr "api-Zugang" + +msgid "Change User Password" +msgstr "Benutzer-Kennwort ändern" + +msgid "New Password" +msgstr "Neues Kennwort" + +msgid "Confirm Password" +msgstr "Bestätige das Passwort" + +msgid "Change Password" +msgstr "Passwort ändern" + +msgid "Not Now" +msgstr "Nicht jetzt" + +msgid "Contact Information" +msgstr "Kontakt Informationen" + +msgid "Job Details" +msgstr "Job Details" + +msgid "Edit Info" +msgstr "Bearbeitungs Information" + +msgid "Upload Profile Image" +msgstr "Laden Profilbild" + +msgid "Delete Profile Image" +msgstr "Löschen Profilbild" + +msgid "Direct Reports" +msgstr "Direkte Rückmeldung" + +msgid "Other Details" +msgstr "Andere Details" + +msgid "Family" +msgstr "Familie" + +msgid "Custom Fields" +msgstr "Benutzerdefinierte Felder" + +msgid "Means of Transportation" +msgstr "Transportmitteln" + +msgid "Plane" +msgstr "Ebene" + +msgid "Rail" +msgstr "Schiene" + +msgid "Taxi" +msgstr "Taxi" + +msgid "Own Vehicle" +msgstr "Eigenes Fahrzeug" + +msgid "Rented Vehicle" +msgstr "Mietfahrzeug" + +msgid "Female" +msgstr "Weiblich" + +msgid "Male" +msgstr "Männlich" + +msgid "Active" +msgstr "Aktiv" + +msgid "Inactive" +msgstr "Inaktiv" + +msgid "Draft" +msgstr "Entwurf" + +msgid "Not Clocked In" +msgstr "Nicht taktet" + +msgid "Clocked In" +msgstr "taktet" + +msgid "File" +msgstr "Datei" + +msgid "Active Employee Report" +msgstr "Aktive Mitarbeiterbericht" + +msgid "Employee Attendance Report" +msgstr "Angestellt-Anwesenheits-Bericht" + +msgid "Employee Details Report" +msgstr "Mitarbeiterdetails Bericht" + +msgid "Employee Leave Entitlement" +msgstr "Mitarbeiter Urlaubsanspruch" + +msgid "Employee Leaves Report" +msgstr "Mitarbeiter Blätter Bericht" + +msgid "Employee Time Entry Report" +msgstr "Mitarbeiterzeit Eintrag Bericht" + +msgid "Employee Time Sheet Report" +msgstr "Mitarbeiterzeitblatt Bericht" + +msgid "Employee Time Tracking Report" +msgstr "Mitarbeiterzeit Tracking Report" + +msgid "Expense Report" +msgstr "Spesenabrechnung" + +msgid "New Hires Employee Report" +msgstr "Neue Mitarbeiter Mitarbeiterbericht" + +msgid "Overtime Report" +msgstr "Überstunden Bericht" + +msgid "Overtime Request Report" +msgstr "Überstunden Anforderungsbericht" + +msgid "Overtime Summary Report" +msgstr "Überstunden Summary Report" + +msgid "Payroll Meta Data Export" +msgstr "Payroll Meta Data Export" + +msgid "Terminated Employee Report" +msgstr "Mitarbeiterbericht terminierte" + +msgid "Travel Request Report" +msgstr "Reiseantrag Bericht" + +msgid "Attendance Report" +msgstr "Teilnahmebericht" + +msgid "Client Project Time Report" +msgstr "Kunde Projektzeitbericht" + +msgid "Download Payslips" +msgstr "Herunterladen Lohnzettel" + +msgid "Leaves Report" +msgstr "Blätter Bericht" + +msgid "Time Entry Report" +msgstr "Zeiteintrag Bericht" + +msgid "Time Sheet Report" +msgstr "Zeitblatt Bericht" + +msgid "Time Tracking Report" +msgstr "Time Tracking Bericht" + +msgid "Data" +msgstr "Daten" + +msgid "Processed" +msgstr "Verarbeitet" + +msgid "Not Processed" +msgstr "Nicht verarbeitet" + +msgid "Elementary Proficiency" +msgstr "Grundkenntnisse" + +msgid "Limited Working Proficiency" +msgstr "Begrenzte Fließend" + +msgid "Professional Working Proficiency" +msgstr "Professionelle Arbeitsleistung" + +msgid "Full Professional Proficiency" +msgstr "Vollständiger Beruf Proficiency" + +msgid "Native or Bilingual Proficiency" +msgstr "Muttersprache oder Zweisprachig" + +msgid "Pending" +msgstr "steht aus" + +msgid "Approved" +msgstr "Genehmigt" + +msgid "Rejected" +msgstr "Abgelehnt" + +msgid "Cancelled" +msgstr "Abgebrochen" + +msgid "Continue" +msgstr "Fortsetzen" + +msgid "Cancellation Requested" +msgstr "Stornierung Gewünscht" + +msgid "Completed" +msgstr "Abgeschlossen" + +msgid "Discussions" +msgstr "Diskussionen" + +msgid "Load More" +msgstr "Mehr laden" + +msgid "Show More" +msgstr "Zeig mehr" + +msgid "Show Less" +msgstr "Zeige weniger" + +msgid "Publish" +msgstr "Veröffentlichen" + +msgid "Announcements" +msgstr "Ankündigungen" + +msgid "Send" +msgstr "Senden" + +msgid "Display" +msgstr "Anzeige" + +msgid "Public" +msgstr "Öffentlichkeit" + +msgid "View Announcements" +msgstr "Ansicht Ankündigungen" + +msgid "Conversations" +msgstr "Gespräche" + +msgid "Start Now" +msgstr "Jetzt anfangen" diff --git a/core/lang/en.po b/core/lang/en.po index 6aea4582..ff3da389 100644 --- a/core/lang/en.po +++ b/core/lang/en.po @@ -1597,3 +1597,309 @@ msgstr "Apply" msgid "Back" msgstr "Back" + +msgid "Hours in Time Sheets" +msgstr "Hours in Time Sheets" + +msgid "HR form" +msgstr "HR form" + +msgid "HR Form Management" +msgstr "HR Form Management" + +msgid "Form Name" +msgstr "Form Name" + +msgid "Fields" +msgstr "Fields" + +msgid "Employee Froms" +msgstr "Employee Froms" + +msgid "Share Departments" +msgstr "Share Departments" + +msgid "Share Employees" +msgstr "Share Employees" + +msgid "Data Importers" +msgstr "Data Importers" + +msgid "Data Import Files" +msgstr "Data Import Files" + +msgid "Data Type" +msgstr "Data Type" + +msgid "Columns" +msgstr "Columns" + +msgid "Field Title" +msgstr "Field Title" + +msgid "Depends On" +msgstr "Depends On" + +msgid "Depends On Field" +msgstr "Depends On Field" + +msgid "is Key Field" +msgstr "is Key Field" + +msgid "is ID Field" +msgstr "is ID Field" + +msgid "Data Import Definitions" +msgstr "Data Import Definitions" + +msgid "File to Import" +msgstr "File to Import" + +msgid "Last Export Results" +msgstr "Last Export Results" + +msgid "Time and Attendance" +msgstr "Time and Attendance" + +msgid "Leave Timeline" +msgstr "Leave Timeline" + +msgid "Insights" +msgstr "Insights" + +msgid "Api Access" +msgstr "Api Access" + +msgid "Change User Password" +msgstr "Change User Password" + +msgid "New Password" +msgstr "New Password" + +msgid "Confirm Password" +msgstr "Confirm Password" + +msgid "Change Password" +msgstr "Change Password" + +msgid "Not Now" +msgstr "Not Now" + +msgid "Contact Information" +msgstr "Contact Information" + +msgid "Job Details" +msgstr "Job Details" + +msgid "Edit Info" +msgstr "Edit Info" + +msgid "Upload Profile Image" +msgstr "Upload Profile Image" + +msgid "Delete Profile Image" +msgstr "Delete Profile Image" + +msgid "Direct Reports" +msgstr "Direct Reports" + +msgid "Other Details" +msgstr "Other Details" + +msgid "Family" +msgstr "Family" + +msgid "Custom Fields" +msgstr "Custom Fields" + +msgid "Means of Transportation" +msgstr "Means of Transportation" + +msgid "Plane" +msgstr "Plane" + +msgid "Rail" +msgstr "Rail" + +msgid "Taxi" +msgstr "Taxi" + +msgid "Own Vehicle" +msgstr "Own Vehicle" + +msgid "Rented Vehicle" +msgstr "Rented Vehicle" + +msgid "Female" +msgstr "Female" + +msgid "Male" +msgstr "Male" + +msgid "Active" +msgstr "Active" + +msgid "Inactive" +msgstr "Inactive" + +msgid "Draft" +msgstr "Draft" + +msgid "Not Clocked In" +msgstr "Not Clocked In" + +msgid "Clocked In" +msgstr "Clocked In" + +msgid "File" +msgstr "File" + +msgid "Active Employee Report" +msgstr "Active Employee Report" + +msgid "Employee Attendance Report" +msgstr "Employee Attendance Report" + +msgid "Employee Details Report" +msgstr "Employee Details Report" + +msgid "Employee Leave Entitlement" +msgstr "Employee Leave Entitlement" + +msgid "Employee Leaves Report" +msgstr "Employee Leaves Report" + +msgid "Employee Time Entry Report" +msgstr "Employee Time Entry Report" + +msgid "Employee Time Sheet Report" +msgstr "Employee Time Sheet Report" + +msgid "Employee Time Tracking Report" +msgstr "Employee Time Tracking Report" + +msgid "Expense Report" +msgstr "Expense Report" + +msgid "New Hires Employee Report" +msgstr "New Hires Employee Report" + +msgid "Overtime Report" +msgstr "Overtime Report" + +msgid "Overtime Request Report" +msgstr "Overtime Request Report" + +msgid "Overtime Summary Report" +msgstr "Overtime Summary Report" + +msgid "Payroll Meta Data Export" +msgstr "Payroll Meta Data Export" + +msgid "Terminated Employee Report" +msgstr "Terminated Employee Report" + +msgid "Travel Request Report" +msgstr "Travel Request Report" + +msgid "Attendance Report" +msgstr "Attendance Report" + +msgid "Client Project Time Report" +msgstr "Client Project Time Report" + +msgid "Download Payslips" +msgstr "Download Payslips" + +msgid "Leaves Report" +msgstr "Leaves Report" + +msgid "Time Entry Report" +msgstr "Time Entry Report" + +msgid "Time Sheet Report" +msgstr "Time Sheet Report" + +msgid "Time Tracking Report" +msgstr "Time Tracking Report" + +msgid "Data" +msgstr "Data" + +msgid "Processed" +msgstr "Processed" + +msgid "Not Processed" +msgstr "Not Processed" + +msgid "Elementary Proficiency" +msgstr "Elementary Proficiency" + +msgid "Limited Working Proficiency" +msgstr "Limited Working Proficiency" + +msgid "Professional Working Proficiency" +msgstr "Professional Working Proficiency" + +msgid "Full Professional Proficiency" +msgstr "Full Professional Proficiency" + +msgid "Native or Bilingual Proficiency" +msgstr "Native or Bilingual Proficiency" + +msgid "Pending" +msgstr "Pending" + +msgid "Approved" +msgstr "Approved" + +msgid "Rejected" +msgstr "Rejected" + +msgid "Cancelled" +msgstr "Cancelled" + +msgid "Continue" +msgstr "Continue" + +msgid "Cancellation Requested" +msgstr "Cancellation Requested" + +msgid "Completed" +msgstr "Completed" + +msgid "Discussions" +msgstr "Discussions" + +msgid "Load More" +msgstr "Load More" + +msgid "Show More" +msgstr "Show More" + +msgid "Show Less" +msgstr "Show Less" + +msgid "Publish" +msgstr "Publish" + +msgid "Announcements" +msgstr "Announcements" + +msgid "Send" +msgstr "Send" + +msgid "Display" +msgstr "Display" + +msgid "Public" +msgstr "Public" + +msgid "View Announcements" +msgstr "View Announcements" + +msgid "Conversations" +msgstr "Conversations" + +msgid "Start Now" +msgstr "Start Now" diff --git a/core/lang/es.po b/core/lang/es.po index 53cd2368..cde5c518 100644 --- a/core/lang/es.po +++ b/core/lang/es.po @@ -1597,3 +1597,309 @@ msgstr "Aplicar" msgid "Back" msgstr "Espalda" + +msgid "Hours in Time Sheets" +msgstr "Horas en hojas de tiempo" + +msgid "HR form" +msgstr "forma HR" + +msgid "HR Form Management" +msgstr "Gestión de formularios HR" + +msgid "Form Name" +msgstr "Nombre del formulario" + +msgid "Fields" +msgstr "Campos" + +msgid "Employee Froms" +msgstr "empleado froms" + +msgid "Share Departments" +msgstr "Departamentos de Acciones" + +msgid "Share Employees" +msgstr "Los empleados de Acciones" + +msgid "Data Importers" +msgstr "Los importadores de datos" + +msgid "Data Import Files" +msgstr "Importar archivos de datos" + +msgid "Data Type" +msgstr "Tipo de datos" + +msgid "Columns" +msgstr "columnas" + +msgid "Field Title" +msgstr "El campo Título" + +msgid "Depends On" +msgstr "Depende de" + +msgid "Depends On Field" +msgstr "Depende de Campo" + +msgid "is Key Field" +msgstr "El campo es la clave" + +msgid "is ID Field" +msgstr "es ID Campo" + +msgid "Data Import Definitions" +msgstr "Definiciones de los datos de importación" + +msgid "File to Import" +msgstr "Archivo para importar" + +msgid "Last Export Results" +msgstr "Los últimos resultados de exportación" + +msgid "Time and Attendance" +msgstr "Tiempo y asistencia" + +msgid "Leave Timeline" +msgstr "Deja Cronología" + +msgid "Insights" +msgstr "Insights" + +msgid "Api Access" +msgstr "acceso a la API" + +msgid "Change User Password" +msgstr "Cambiar contraseña del usuario" + +msgid "New Password" +msgstr "Nueva contraseña" + +msgid "Confirm Password" +msgstr "Confirmar contraseña" + +msgid "Change Password" +msgstr "Cambia la contraseña" + +msgid "Not Now" +msgstr "Ahora no" + +msgid "Contact Information" +msgstr "Información del contacto" + +msgid "Job Details" +msgstr "Detalles del trabajo" + +msgid "Edit Info" +msgstr "Editar información" + +msgid "Upload Profile Image" +msgstr "Sube Imagen del perfil" + +msgid "Delete Profile Image" +msgstr "Eliminar Imagen del perfil" + +msgid "Direct Reports" +msgstr "Reportes directos" + +msgid "Other Details" +msgstr "Otros detalles" + +msgid "Family" +msgstr "Familia" + +msgid "Custom Fields" +msgstr "Campos Personalizados" + +msgid "Means of Transportation" +msgstr "Medios de transporte" + +msgid "Plane" +msgstr "Avión" + +msgid "Rail" +msgstr "Carril" + +msgid "Taxi" +msgstr "Taxi" + +msgid "Own Vehicle" +msgstr "Vehículo propio" + +msgid "Rented Vehicle" +msgstr "Vehículo alquilado" + +msgid "Female" +msgstr "Hembra" + +msgid "Male" +msgstr "Masculino" + +msgid "Active" +msgstr "Activo" + +msgid "Inactive" +msgstr "Inactivo" + +msgid "Draft" +msgstr "Borrador" + +msgid "Not Clocked In" +msgstr "No cronometró" + +msgid "Clocked In" +msgstr "En Clocked" + +msgid "File" +msgstr "Archivo" + +msgid "Active Employee Report" +msgstr "Informe Empleado Activo" + +msgid "Employee Attendance Report" +msgstr "Informe de asistencia a los empleados" + +msgid "Employee Details Report" +msgstr "Empleado detalles Notificar" + +msgid "Employee Leave Entitlement" +msgstr "Empleado Derecho a vacaciones" + +msgid "Employee Leaves Report" +msgstr "Informe Hojas empleado" + +msgid "Employee Time Entry Report" +msgstr "Informe de registro de tiempo empleado" + +msgid "Employee Time Sheet Report" +msgstr "Hoja de Informe Tiempo empleado" + +msgid "Employee Time Tracking Report" +msgstr "Informe de seguimiento de tiempo empleado" + +msgid "Expense Report" +msgstr "Informe de gastos" + +msgid "New Hires Employee Report" +msgstr "Nuevos empleados Informe del Empleado" + +msgid "Overtime Report" +msgstr "Informe de las horas extraordinarias" + +msgid "Overtime Request Report" +msgstr "Solicitud de Informe de horas extras" + +msgid "Overtime Summary Report" +msgstr "Informe de resumen de horas extras" + +msgid "Payroll Meta Data Export" +msgstr "Nómina de Meta Data Export" + +msgid "Terminated Employee Report" +msgstr "Terminado Informe del Empleado" + +msgid "Travel Request Report" +msgstr "Solicitud de Informe de viaje" + +msgid "Attendance Report" +msgstr "Reporte de asistencia" + +msgid "Client Project Time Report" +msgstr "Proyecto cliente Hora del informe" + +msgid "Download Payslips" +msgstr "Los recibos de pago de descarga" + +msgid "Leaves Report" +msgstr "deja el Informe" + +msgid "Time Entry Report" +msgstr "Informe Hora entrada" + +msgid "Time Sheet Report" +msgstr "Informe de características TIEMPO" + +msgid "Time Tracking Report" +msgstr "Informe de seguimiento de tiempo" + +msgid "Data" +msgstr "Datos" + +msgid "Processed" +msgstr "Procesada" + +msgid "Not Processed" +msgstr "No procesado" + +msgid "Elementary Proficiency" +msgstr "Competencia básica" + +msgid "Limited Working Proficiency" +msgstr "Competencia básica limitada" + +msgid "Professional Working Proficiency" +msgstr "Competencia básica profesional" + +msgid "Full Professional Proficiency" +msgstr "Competencia profesional completa" + +msgid "Native or Bilingual Proficiency" +msgstr "Competencia bilingüe o nativa" + +msgid "Pending" +msgstr "Pendiente" + +msgid "Approved" +msgstr "Aprobado" + +msgid "Rejected" +msgstr "Rechazado" + +msgid "Cancelled" +msgstr "Cancelado" + +msgid "Continue" +msgstr "Continuar" + +msgid "Cancellation Requested" +msgstr "cancelación solicitada" + +msgid "Completed" +msgstr "Terminado" + +msgid "Discussions" +msgstr "discusiones" + +msgid "Load More" +msgstr "Carga más" + +msgid "Show More" +msgstr "Mostrar más" + +msgid "Show Less" +msgstr "Muestra menos" + +msgid "Publish" +msgstr "Publicar" + +msgid "Announcements" +msgstr "anuncios" + +msgid "Send" +msgstr "Enviar" + +msgid "Display" +msgstr "Monitor" + +msgid "Public" +msgstr "Público" + +msgid "View Announcements" +msgstr "Ver los anuncios" + +msgid "Conversations" +msgstr "conversaciones" + +msgid "Start Now" +msgstr "Empezar ahora" diff --git a/core/lang/fr.po b/core/lang/fr.po index 0a10f113..0017480d 100644 --- a/core/lang/fr.po +++ b/core/lang/fr.po @@ -1597,3 +1597,309 @@ msgstr "Appliquer" msgid "Back" msgstr "Arrière" + +msgid "Hours in Time Sheets" +msgstr "Heures feuilles de temps" + +msgid "HR form" +msgstr "sous forme de ressources humaines" + +msgid "HR Form Management" +msgstr "Gestion du formulaire RH" + +msgid "Form Name" +msgstr "Nom de forme" + +msgid "Fields" +msgstr "Des champs" + +msgid "Employee Froms" +msgstr "employé Froms" + +msgid "Share Departments" +msgstr "Départements Partager" + +msgid "Share Employees" +msgstr "Employés Share" + +msgid "Data Importers" +msgstr "Importateurs de données" + +msgid "Data Import Files" +msgstr "Importer des fichiers de données" + +msgid "Data Type" +msgstr "Type de données" + +msgid "Columns" +msgstr "colonnes" + +msgid "Field Title" +msgstr "Titre terrain" + +msgid "Depends On" +msgstr "Dépend de" + +msgid "Depends On Field" +msgstr "Sur le terrain dépend" + +msgid "is Key Field" +msgstr "est Key Field" + +msgid "is ID Field" +msgstr "est Champ ID" + +msgid "Data Import Definitions" +msgstr "Définitions Importer des données" + +msgid "File to Import" +msgstr "Fichier à importer" + +msgid "Last Export Results" +msgstr "Derniers résultats Export" + +msgid "Time and Attendance" +msgstr "Le temps et la fréquentation" + +msgid "Leave Timeline" +msgstr "Laissez Timeline" + +msgid "Insights" +msgstr "Insights" + +msgid "Api Access" +msgstr "Accès api" + +msgid "Change User Password" +msgstr "Changer mot de passe de l'utilisateur" + +msgid "New Password" +msgstr "nouveau mot de passe" + +msgid "Confirm Password" +msgstr "Confirmez le mot de passe" + +msgid "Change Password" +msgstr "Changer le mot de passe" + +msgid "Not Now" +msgstr "Pas maintenant" + +msgid "Contact Information" +msgstr "Informations de contact" + +msgid "Job Details" +msgstr "Détails du poste" + +msgid "Edit Info" +msgstr "Modifier les informations" + +msgid "Upload Profile Image" +msgstr "Ajouter un profil Photo" + +msgid "Delete Profile Image" +msgstr "Supprimer le profil image" + +msgid "Direct Reports" +msgstr "Rapports directs" + +msgid "Other Details" +msgstr "Autres détails" + +msgid "Family" +msgstr "Famille" + +msgid "Custom Fields" +msgstr "Les champs personnalisés" + +msgid "Means of Transportation" +msgstr "Moyens de transport" + +msgid "Plane" +msgstr "Avion" + +msgid "Rail" +msgstr "Rail" + +msgid "Taxi" +msgstr "Taxi" + +msgid "Own Vehicle" +msgstr "Propre véhicule" + +msgid "Rented Vehicle" +msgstr "véhicule loué" + +msgid "Female" +msgstr "Femelle" + +msgid "Male" +msgstr "Mâle" + +msgid "Active" +msgstr "actif" + +msgid "Inactive" +msgstr "Inactif" + +msgid "Draft" +msgstr "Brouillon" + +msgid "Not Clocked In" +msgstr "Non cadencées" + +msgid "Clocked In" +msgstr "cadencées" + +msgid "File" +msgstr "Fichier" + +msgid "Active Employee Report" +msgstr "Rapport actif employé" + +msgid "Employee Attendance Report" +msgstr "Rapport de présence des employés" + +msgid "Employee Details Report" +msgstr "Rapport de l'employé Détails" + +msgid "Employee Leave Entitlement" +msgstr "Employé droit au congé" + +msgid "Employee Leaves Report" +msgstr "Rapport feuilles des employés" + +msgid "Employee Time Entry Report" +msgstr "Rapport employé à temps d'entrée" + +msgid "Employee Time Sheet Report" +msgstr "Rapport de feuille de temps des employés" + +msgid "Employee Time Tracking Report" +msgstr "Rapport de suivi du temps des employés" + +msgid "Expense Report" +msgstr "Rapport de dépenses" + +msgid "New Hires Employee Report" +msgstr "Nouvelles embauches Rapport de l'employé" + +msgid "Overtime Report" +msgstr "Rapport des heures supplémentaires" + +msgid "Overtime Request Report" +msgstr "Rapport des heures supplémentaires de demande" + +msgid "Overtime Summary Report" +msgstr "Rapport sommaire des heures supplémentaires" + +msgid "Payroll Meta Data Export" +msgstr "Paie Meta Exporter les données" + +msgid "Terminated Employee Report" +msgstr "Rapport de l'employé Terminated" + +msgid "Travel Request Report" +msgstr "Rapport Demande de Voyage" + +msgid "Attendance Report" +msgstr "Rapport de présence" + +msgid "Client Project Time Report" +msgstr "Rapport sur le projet Client Temps" + +msgid "Download Payslips" +msgstr "Télécharger fiches de paie" + +msgid "Leaves Report" +msgstr "Rapport laisse" + +msgid "Time Entry Report" +msgstr "Rapport du temps d'entrée" + +msgid "Time Sheet Report" +msgstr "Rapport de feuille de temps" + +msgid "Time Tracking Report" +msgstr "Rapport de suivi du temps" + +msgid "Data" +msgstr "Les données" + +msgid "Processed" +msgstr "Traité" + +msgid "Not Processed" +msgstr "Non traité" + +msgid "Elementary Proficiency" +msgstr "Notions" + +msgid "Limited Working Proficiency" +msgstr "Compétence professionnelle limitée" + +msgid "Professional Working Proficiency" +msgstr "Compétence professionnelle" + +msgid "Full Professional Proficiency" +msgstr "Capacité professionnelle complète" + +msgid "Native or Bilingual Proficiency" +msgstr "Bilingue ou langue natale" + +msgid "Pending" +msgstr "en attendant" + +msgid "Approved" +msgstr "Approuvé" + +msgid "Rejected" +msgstr "Rejeté" + +msgid "Cancelled" +msgstr "Annulé" + +msgid "Continue" +msgstr "Continuer" + +msgid "Cancellation Requested" +msgstr "Annulation demandée" + +msgid "Completed" +msgstr "Terminé" + +msgid "Discussions" +msgstr "discussions" + +msgid "Load More" +msgstr "Charger plus" + +msgid "Show More" +msgstr "Montre plus" + +msgid "Show Less" +msgstr "Montre moins" + +msgid "Publish" +msgstr "Publier" + +msgid "Announcements" +msgstr "Annonces" + +msgid "Send" +msgstr "Envoyer" + +msgid "Display" +msgstr "Afficher" + +msgid "Public" +msgstr "Publique" + +msgid "View Announcements" +msgstr "Afficher les annonces" + +msgid "Conversations" +msgstr "conversations" + +msgid "Start Now" +msgstr "Commencez maintenant" diff --git a/core/lang/it.po b/core/lang/it.po index 0a8b19f6..26af59c1 100644 --- a/core/lang/it.po +++ b/core/lang/it.po @@ -12,7 +12,7 @@ msgstr "" "Language: Italian\n" msgid "Save" -msgstr "Salvare" +msgstr "Salva" msgid "Cancel" msgstr "Annulla" @@ -21,217 +21,217 @@ msgid "Done" msgstr "Fatto" msgid "Clocked In Employees" -msgstr "Clock In dipendenti" +msgstr "Timbratura Dipendenti" msgid "Candidates" -msgstr "I candidati" +msgstr "Candidati" msgid "View Employees" -msgstr "Vista dipendenti" +msgstr "Vista Dipendenti" msgid "Add a New Employee" -msgstr "Aggiungere un nuovo dipendente" +msgstr "Nuovo Dipendente" msgid "Leave Calendar" -msgstr "Lasciare Calendario" +msgstr "Calendario Permessi" msgid "Manage Client/Projects" -msgstr "Gestire client / Progetti" +msgstr "Gestire Clienti/Progetti" msgid "Home" -msgstr "Casa" +msgstr "Home" msgid "Quick Access" msgstr "Accesso veloce" msgid "Switch" -msgstr "Interruttore" +msgstr "Cambia Utente" msgid "Profile" msgstr "Profilo" msgid "Sign out" -msgstr "Disconnessione" +msgstr "Esci" msgid "Help" msgstr "Aiuto" msgid "About" -msgstr "Di" +msgstr "di" msgid "Version" msgstr "Versione" msgid "Release Date" -msgstr "Data di rilascio" +msgstr "Data Rilascio" msgid "Logged In" msgstr "Connesso" msgid "Admin" -msgstr "Admin" +msgstr "Amministratore" msgid "Dashboard" -msgstr "Scrivania" +msgstr "Home" msgid "Company Structure" -msgstr "Struttura aziendale" +msgstr "Config. Azienda" msgid "Job Details Setup" -msgstr "Dettagli lavoro di installazione" +msgstr "Config. Funzione" msgid "Qualifications Setup" -msgstr "Impostazione delle qualifiche" +msgstr "Config. Qualifiche" msgid "Training Setup" -msgstr "Impostazione Formazione" +msgstr "Config. Formazione" msgid "Projects/Client Setup" -msgstr "Progetti / Client Setup" +msgstr "Config. Clienti/Progetti" msgid "Leave Settings" -msgstr "Lasciare Impostazioni" +msgstr "Config. Permessi" msgid "Company Loans" -msgstr "Società di Prestiti" +msgstr "Config. Prestiti" msgid "Audit Log" -msgstr "Registro di controllo" +msgstr "Registro Attività Utenti" msgid "Employees" -msgstr "I dipendenti" +msgstr "Dipendenti" msgid "Employee History" -msgstr "Storia organigramma" +msgstr "Storico Dipendente" msgid "Document Management" -msgstr "Gestione documenti" +msgstr "Gestione Documenti" msgid "Travel Administration" -msgstr "Amministrazione di viaggio" +msgstr "Gestione Viaggi" msgid "Expense Administration" -msgstr "Spese di amministrazione" +msgstr "Gestione Spese" msgid "Monitor Attendance" -msgstr "Monitor presenze" +msgstr "Controllo Presenze" msgid "Performance Charts" -msgstr "Grafici prestazioni" +msgstr "Grafici Prestazioni" msgid "Overtime Administration" -msgstr "Amministrazione Overtime" +msgstr "Gestione Straordinari" msgid "Admin Reports" -msgstr "Rapporti Admin" +msgstr "Gestione Report" msgid "Reports" -msgstr "Rapporti" +msgstr "Report" msgid "Report Files" -msgstr "File di report" +msgstr "File dei Report" msgid "System" msgstr "Sistema" msgid "Settings" -msgstr "Impostazioni" +msgstr "Config." msgid "Users" msgstr "Utenti" msgid "Manage Modules" -msgstr "Gestire Moduli" +msgstr "Gestione Moduli" msgid "Manage Permissions" -msgstr "Gestisci autorizzazioni" +msgstr "Gestione Autorizzazioni" msgid "Upgrade" msgstr "Aggiornamento" msgid "Manage Metadata" -msgstr "Gestire i metadati" +msgstr "Gestione Metadati" msgid "Field Names Setup" -msgstr "Configurazione Nomi di campo" +msgstr "Gestione Nome Campi" msgid "Payroll" -msgstr "Libro paga" +msgstr "Libro Paga" msgid "Salary" msgstr "Stipendio" msgid "Payroll Reports" -msgstr "Rapporti per il personale" +msgstr "Report Salari" msgid "Recruitment" -msgstr "Reclutamento" +msgstr "Ricerca di Personale" msgid "Recruitment Setup" -msgstr "Impostazione di reclutamento" +msgstr "Gestione Ricerca di Personale" msgid "Job Positions" -msgstr "Posizioni di lavoro" +msgstr "Posizioni di Lavoro" msgid "Personal Information" -msgstr "Informazione personale" +msgstr "Informazioni Personali" msgid "Basic Information" -msgstr "Informazioni di base" +msgstr "Informazioni Base" msgid "Qualifications" -msgstr "Titoli di studio" +msgstr "Titoli Studio" msgid "Dependents" -msgstr "Dipendenti" +msgstr "Familiari" msgid "Emergency Contacts" -msgstr "Contatti di emergenza" +msgstr "Contatti di Emergenza" msgid "Leave" -msgstr "Partire" +msgstr "Permessi" msgid "Leave Management" -msgstr "Lasciare Gestione" +msgstr "Gestione Permessi" msgid "Time Management" -msgstr "Gestione del tempo" +msgstr "Gestione Attività" msgid "Projects" msgstr "Progetti" msgid "Attendance" -msgstr "Partecipazione" +msgstr "Presenze" msgid "Time Sheets" -msgstr "Fogli di presenza" +msgstr "Fogli Attività" msgid "Attendance Sheets" -msgstr "Fogli di presenza" +msgstr "Fogli Presenze" msgid "Overtime Requests" -msgstr "Le richieste di straordinario" +msgstr "Richiesta Straordinari" msgid "Documents" msgstr "Documenti" msgid "My Documents" -msgstr "I miei documenti" +msgstr "I Miei Documenti" msgid "Company" -msgstr "Società" +msgstr "Società" msgid "Staff Directory" -msgstr "Elenco del personale" +msgstr "Elenco del Personale" msgid "Training" msgstr "Formazione" msgid "Travel Management" -msgstr "Travel Management" +msgstr "Gestione Trasferte" msgid "Travel" -msgstr "Viaggio" +msgstr "Viaggi" msgid "Finance" msgstr "Finanza" @@ -243,25 +243,25 @@ msgid "Loans" msgstr "Prestiti" msgid "User Reports" -msgstr "Rapporti utente" +msgstr "Report Utente" msgid "People" msgstr "Persone" msgid "Manage" -msgstr "Gestire" +msgstr "Gestione" msgid "Departments" msgstr "Dipartimenti" msgid "Active Projects" -msgstr "Progetti attivi" +msgstr "Progetti Attivi" msgid "Update Clients/Projects" -msgstr "Aggiornare i client / Progetti" +msgstr "Gestione Clienti/Progetti" msgid "Entries Last Week" -msgstr "Le voci Ultima Settimana" +msgstr "Voci Ultima Settimana" msgid "Upcoming" msgstr "Prossime" @@ -270,22 +270,22 @@ msgid "View / Download Reports" msgstr "Visualizza / Scarica Report" msgid "Generate a Report" -msgstr "Genera un rapporto" +msgstr "Crea Report" msgid "Configure" -msgstr "Configurazione" +msgstr "Configura" msgid "Update" -msgstr "Aggiornare" +msgstr "Aggiorna" msgid "Applicants" -msgstr "I candidati" +msgstr "Candidati" msgid "Active Jobs" -msgstr "Lavori attivi" +msgstr "Posizioni Aperte" msgid "Jobs Posted" -msgstr "Offerte di lavoro pubblicate" +msgstr "Posizioni Pubblicate" msgid "Jobs" msgstr "Lavori" @@ -297,7 +297,7 @@ msgid "Requests" msgstr "Richieste" msgid "Document" -msgstr "Documento" +msgstr "Documenti" msgid "Management" msgstr "Gestione" @@ -306,7 +306,7 @@ msgid "Expense" msgstr "Spese" msgid "Permission" -msgstr "Autorizzazione" +msgstr "Autorizzazioni" msgid "Permissions" msgstr "Permessi" @@ -321,70 +321,70 @@ msgid "Make a Payment" msgstr "Effettua un pagamento" msgid "Switch Employee" -msgstr "Interruttore dipendenti" +msgstr "Collegati come ..." msgid "Select The Employee to Switch Into" -msgstr "Selezionare il dipendente di passare alla" +msgstr "Seleziona il dipendente con cui collegarti" msgid "Close" msgstr "Vicino" msgid "My Profile" -msgstr "Il mio profilo" +msgstr "Mio Profilo" msgid "Edit Details" -msgstr "Modifica i dettagli" +msgstr "Modifica Dettagli" msgid "View/Edit Profile" -msgstr "Vedi / Modifica profilo" +msgstr "Gestione Profilo" msgid "Punch In" -msgstr "Punch In" +msgstr "Mie Presenze" msgid "or" -msgstr "O" +msgstr "o" msgid "Punch Out" -msgstr "Registrarsi a uscita" +msgstr "Fine" msgid "Record Attendance" -msgstr "Record di presenze" +msgstr "Registra Presenza" msgid "Pending Leaves" -msgstr "Foglie in sospeso" +msgstr "In Sospeso" msgid "Check Leave Status" -msgstr "Controllare Leave Stato" +msgstr "Gestione Stato Permessi" msgid "Hours worked Last Week" -msgstr "Ore lavorate Ultima settimana" +msgstr "Ore lavorate ultima settimana" msgid "Update Time Sheet" -msgstr "Tempo di aggiornamento Sheet" +msgstr "Gestione Foglio Attività" msgid "My Projects" -msgstr "I miei progetti" +msgstr "Miei Progetti" msgid "Projects Assigned" -msgstr "Progetti assegnati" +msgstr "Progetti Assegnati" msgid "More info" -msgstr "Ulteriori informazioni" +msgstr "Gestione Miei Progetti" msgid "Store" -msgstr "Negozio" +msgstr "Repository" msgid "My Travel" -msgstr "Il mio viaggio" +msgstr "Miei Viaggi" msgid "My Expenses" -msgstr "Le mie spese" +msgstr "Mie Spese" msgid "Manage Expenses" -msgstr "Gestire le spese" +msgstr "Gestione Spese" msgid "ID" -msgstr "ID" +msgstr "Codice" msgid "Name" msgstr "Nome" @@ -393,64 +393,64 @@ msgid "Address" msgstr "Indirizzo" msgid "Type" -msgstr "Digitare" +msgstr "Tipo" msgid "Country" msgstr "Nazione" msgid "Time Zone" -msgstr "Fuso orario" +msgstr "Fuso Orario" msgid "Parent Structure" -msgstr "Struttura Parent" +msgstr "Padre" msgid "Details" msgstr "Dettagli" msgid "Heads" -msgstr "Teste" +msgstr "Responsabili" msgid "Code" msgstr "Codice" msgid "Job Title Code" -msgstr "Job Codice Titolo" +msgstr "Codice Titolo Professionale" msgid "Job Title" -msgstr "Titolo di lavoro" +msgstr "Titolo Professionale" msgid "Description" msgstr "Descrizione" msgid "Specification" -msgstr "Specificazione" +msgstr "Specifica" msgid "Currency" -msgstr "Moneta" +msgstr "Codice Valuta" msgid "Min Salary" -msgstr "Min Stipendio" +msgstr "Stipendio Min" msgid "Max Salary" -msgstr "Max Stipendio" +msgstr "Stipendio Max" msgid "Pay Grade Name" -msgstr "Nome Pay Grado" +msgstr "Nome Livello Stipendio" msgid "Employment Status" -msgstr "Stato di impiego" +msgstr "Tipo Occupazione" msgid "Coordinator" msgstr "Coordinatore" msgid "Trainer" -msgstr "Allenatore" +msgstr "Insegnante" msgid "Trainer Details" -msgstr "Trainer Dettagli" +msgstr "Dettagli Insegnante" msgid "Payment Type" -msgstr "Modalità di pagamento" +msgstr "Pagamento" msgid "Cost" msgstr "Costo" @@ -459,46 +459,46 @@ msgid "Status" msgstr "Stato" msgid "Course" -msgstr "Corso" +msgstr "Nome Corso" msgid "Scheduled Time" -msgstr "Orario pianificato" +msgstr "Data Inizio" msgid "Assignment Due Date" -msgstr "Assegnazione Due Date" +msgstr "Data Fine" msgid "Delivery Method" -msgstr "Metodo di consegna" +msgstr "Tipo" msgid "Delivery Location" -msgstr "Luogo della consegna" +msgstr "Luogo" msgid "Attendance Type" -msgstr "Tipo presenze" +msgstr "Presenza" msgid "Attachment" -msgstr "Allegati" +msgstr "Allegato" msgid "Training Certificate Required" -msgstr "Formazione certificato richiesto" +msgstr "Certificato Formazione" msgid "Employee" msgstr "Dipendente" msgid "Training Session" -msgstr "Sessione di allenamento" +msgstr "Nome Corso" msgid "Contact Number" -msgstr "Numero di contatto" +msgstr "Numero di Contatto" msgid "Contact Email" -msgstr "Contatto email" +msgstr "email" msgid "Company Url" -msgstr "Società URL" +msgstr "URL Società" msgid "First Contact Date" -msgstr "Primo contatto Data" +msgstr "Data Primo Contatto" msgid "Client" msgstr "Cliente" @@ -507,58 +507,58 @@ msgid "Project" msgstr "Progetto" msgid "Leave Name" -msgstr "Lascia Nome" +msgstr "Nome Permesso" msgid "Leave Accrue Enabled" -msgstr "Lasciare Accrue Abilitato" +msgstr "Accumulo Permessi Abilitato" msgid "Leave Carried Forward" -msgstr "Lasciare Carried Forward" +msgstr "Riporto Permessi Abilitato" msgid "Leaves Per Year" -msgstr "Foglie per Anno" +msgstr "Permessi per Anno" msgid "Leaves Group" -msgstr "Foglie Gruppo" +msgstr "Gruppo Permessi" msgid "Leaves Per Leave Period" -msgstr "Foglie per Leave Periodo" +msgstr "Quantità nel Periodo" msgid "Admin can assign leave to employees" -msgstr "L'amministratore può assegnare permesso ai dipendenti" +msgstr "L'amministratore può assegnare questo permesso ai dipendenti" msgid "Employees can apply for this leave type" -msgstr "I dipendenti possono fare domanda per questo tipo di congedo" +msgstr "I dipendenti possono richiedere questo permesso" msgid "Employees can apply beyond the current leave balance" -msgstr "I dipendenti possono applicare al di là della bilancia corrente congedo" +msgstr "I dipendenti possono richiedere permessi oltre la disponibilità" msgid "Percentage of Leaves Carried Forward" -msgstr "Percentuale di foglie portate a nuovo" +msgstr "Quota Permessi Riportati" msgid "Maximum Carried Forward Amount" -msgstr "Massima Carried Forward Importo" +msgstr "Nr. Max Permessi Riportati" msgid "Carried Forward Leave Availability Period" -msgstr "Portato periodo di disponibilità di andata Leave" +msgstr "Periodo di Riporto Permessi Disponibili" msgid "Proportionate leaves on Joined Date" -msgstr "Foglie proporzionato Data di registrazione" +msgstr "Quota Permessi Disponibili (da Assunzione)" msgid "Send Notification Emails" -msgstr "Inviare e-mail di notifica" +msgstr "Inviare email di notifica" msgid "Leave Group" -msgstr "Lascia il gruppo" +msgstr "Gruppo Permesso" msgid "Leave Color" -msgstr "Lasciare a colori" +msgstr "Colore Permesso" msgid "Period Start" -msgstr "Periodo di avvio" +msgstr "Inizio Periodo" msgid "Period End" -msgstr "Periodo Fine" +msgstr "Fine Periodo" msgid "Day" msgstr "Giorno" @@ -570,136 +570,136 @@ msgid "Date" msgstr "Data" msgid "Leave Type" -msgstr "Lasciare Tipo" +msgstr "Tipo Permesso" msgid "Propotionate leaves on Joined Date" -msgstr "Propotionate lascia sul Data di registrazione" +msgstr "Quota Assenze disponibili da Assunzione" msgid "Leaves Period" -msgstr "Lascia Periodo" +msgstr "Periodo Permesso" msgid "Leave Amount" -msgstr "Lasciare Importo" +msgstr "Totale Permessi" msgid "Leave Period" -msgstr "Lasciare Periodo" +msgstr "Periodo Permesso" msgid "Note" msgstr "Nota" msgid "All Employees" -msgstr "Tutti gli impiegati" +msgstr "Tutti i Dipendenti" msgid "All Leave Types" -msgstr "Tutti Lascia Tipi" +msgstr "Tutti i Tipi di Permesso" msgid "Loan Type" -msgstr "Tipo di prestito" +msgstr "Tipo Prestito" msgid "Loan Start Date" -msgstr "Loan Data di inizio" +msgstr "Data Inizio" msgid "Loan Period (Months)" -msgstr "Periodo di prestito (Mesi)" +msgstr "Durata Prestito (Mesi)" msgid "Amount" -msgstr "Quantità" +msgstr "Importo" msgid "Last Installment Date" -msgstr "Data ultima rata" +msgstr "Data Ultima Rata" msgid "Loan Amount" -msgstr "Ammontare del prestito" +msgstr "Importo Prestito" msgid "Monthly Installment" -msgstr "Rata mensile" +msgstr "Rata Mensile" msgid "Employee Number" -msgstr "Impiegato numero" +msgstr "Codice" msgid "First Name" msgstr "Nome" msgid "Middle Name" -msgstr "Secondo nome" +msgstr "Secondo Nome" msgid "Last Name" msgstr "Cognome" msgid "Nationality" -msgstr "Nazionalità" +msgstr "Nazionalità" msgid "Date of Birth" -msgstr "Data di nascita" +msgstr "Data Nascita" msgid "Gender" -msgstr "Genere" +msgstr "Sesso" msgid "Marital Status" -msgstr "Stato civile" +msgstr "Stato Civile" msgid "Ethnicity" -msgstr "Razza" +msgstr "Etnia" msgid "Immigration Status" -msgstr "Stato di immigrazione" +msgstr "Stato Immigrazione" msgid "SSN/NRIC" -msgstr "SSN / NRIC" +msgstr "Cod. Fiscale" msgid "NIC" -msgstr "NIC" +msgstr "AVS" msgid "Other ID" -msgstr "Altro ID" +msgstr "Altro Codice" msgid "Driving License No" -msgstr "Patente di guida No" +msgstr "Nr. Patente Guida" msgid "Pay Grade" -msgstr "Pay grado" +msgstr "Livello Retributivo" msgid "Work Station Id" -msgstr "Lavorare ID stazione" +msgstr "S/N Notebook" msgid "Address Line 1" -msgstr "Indirizzo Linea 1" +msgstr "Indirizzo 1" msgid "Address Line 2" msgstr "Indirizzo 2" msgid "City" -msgstr "Città" +msgstr "Città" msgid "Province" msgstr "Provincia" msgid "Postal/Zip Code" -msgstr "Codice postale" +msgstr "CAP" msgid "Home Phone" -msgstr "Telefono di casa" +msgstr "Telefono Privato" msgid "Mobile Phone" msgstr "Cellulare" msgid "Work Phone" -msgstr "Telefono del lavoro" +msgstr "Telefono Ufficio" msgid "Work Email" -msgstr "Work-mail" +msgstr "Email Aziendale" msgid "Private Email" -msgstr "Email privato" +msgstr "Email Privata" msgid "Joined Date" -msgstr "Data di registrazione" +msgstr "Data Assunzione" msgid "Confirmation Date" -msgstr "Conferma Data" +msgstr "Data Conferma (Fine Prova)" msgid "Termination Date" -msgstr "Terminazione Data" +msgstr "Data Fine Collaborazione" msgid "Department" msgstr "Dipartimento" @@ -708,22 +708,22 @@ msgid "Supervisor" msgstr "Supervisore" msgid "Indirect Supervisors" -msgstr "Le autorità di vigilanza indiretta" +msgstr "Supervisore Indiretto" msgid "First Level Approver" -msgstr "Primo Livello Approver" +msgstr "I Liv. Approvazione" msgid "Second Level Approver" -msgstr "Secondo Livello Approver" +msgstr "II Liv. Approvazione" msgid "Third Level Approver" -msgstr "Terzo Livello Approver" +msgstr "III Liv. Approvazione" msgid "Notes" msgstr "Note" msgid "Time (GMT)" -msgstr "Time (GMT)" +msgstr "Orario (GMT)" msgid "User" msgstr "Utente" @@ -732,64 +732,64 @@ msgid "IP Address" msgstr "Indirizzo IP" msgid "Logged In Employee" -msgstr "Effettuato l'accesso dei dipendenti" +msgstr "Dipendente Collegato" msgid "Skill" -msgstr "Abilità" +msgstr "Competenze" msgid "Qualification" -msgstr "Qualificazione" +msgstr "Qualifica" msgid "Institute" msgstr "Istituto" msgid "Start Date" -msgstr "Data d'inizio" +msgstr "Data Inizio" msgid "Completed On" -msgstr "Completato il" +msgstr "Data Fine" msgid "Certification" -msgstr "Certificazione" +msgstr "Certificazioni" msgid "Granted On" -msgstr "Concessi a" +msgstr "Concesso il" msgid "Valid Thru" -msgstr "Valido Thru" +msgstr "Valido Fino" msgid "Language" msgstr "Lingua" msgid "Reading" -msgstr "Lettura" +msgstr "Letta" msgid "Speaking" -msgstr "A proposito di" +msgstr "Parlata" msgid "Writing" -msgstr "Scrittura" +msgstr "Scritta" msgid "Understanding" msgstr "Comprensione" msgid "Date Added" -msgstr "Data aggiunta" +msgstr "Data Aggiunta" msgid "Valid Until" -msgstr "Valido fino" +msgstr "Valido Fino a" msgid "Relationship" msgstr "Relazione" msgid "Id Number" -msgstr "Numero Id" +msgstr "Tipo e Nr. Documento Identità" msgid "All Job Titles" -msgstr "Tutti i titoli di lavoro" +msgstr "Tutti i Titoli di Lavoro" msgid "All Departments" -msgstr "Tutte le categorie" +msgstr "Tutte le Categorie" msgid "Anyone" msgstr "Chiunque" @@ -801,7 +801,7 @@ msgid "Old Value" msgstr "Vecchio Valore" msgid "New Value" -msgstr "Nuovo valore" +msgstr "Nuovo Valore" msgid "Modified By" msgstr "Modificato da" @@ -810,100 +810,100 @@ msgid "Created" msgstr "Creato" msgid "Notify Expiry" -msgstr "Notifica di scadenza" +msgstr "Notifica Scadenza" msgid "Notify Expiry Before One Month" -msgstr "Notifica di scadenza prima di un mese" +msgstr "Notifica Scadenza (un mese prima)" msgid "Notify Expiry Before One Week" -msgstr "Notifica di scadenza prima di una settimana" +msgstr "Notifica Scadenza (una settimana prima)" msgid "Notify Expiry Before One Day" -msgstr "Notifica di scadenza Prima di One Day" +msgstr "Notifica Scadenza (un giorno prima)" msgid "Travel Type" -msgstr "Tipo di viaggio" +msgstr "Tipo Viaggio" msgid "Purpose of Travel" -msgstr "Proposta di viaggio" +msgstr "Scopo Viaggio" msgid "Travel From" -msgstr "Come raggiungerci Da" +msgstr "Partenza da" msgid "Travel To" -msgstr "Per viaggiare" +msgstr "Destinazione" msgid "Travel Date" -msgstr "Data di viaggio" +msgstr "Data Andata" msgid "Return Date" -msgstr "Data di ritorno" +msgstr "Data Ritorno" msgid "Total Funding Proposed" -msgstr "Il finanziamento totale proposto" +msgstr "Stima Importo Totale" msgid "Itinerary / Cab Receipt" -msgstr "Itinerario / Ricevuta Cab" +msgstr "Allegato 1" msgid "Other Attachment 1" -msgstr "Altro Allegato 1" +msgstr "Allegato 2" msgid "Other Attachment 2" -msgstr "Altro Allegato 2" +msgstr "Allegato 3" msgid "Payment Method" -msgstr "Metodo di pagamento" +msgstr "Metodo Pagamento" msgid "Transaction / Ref No" -msgstr "Operazioni / Rif" +msgstr "Nr. Riferimento" msgid "Payee" msgstr "Beneficiario" msgid "Expense Category" -msgstr "Spesa Categoria" +msgstr "Categoria Spesa" msgid "Receipt" msgstr "Ricevuta" msgid "Time-In" -msgstr "Time-In" +msgstr "Entrata" msgid "Time-Out" -msgstr "Tempo scaduto" +msgstr "Uscita" msgid "Clocked In Status" -msgstr "Clock In Stato" +msgstr "Stato Entrata" msgid "End Date" -msgstr "Data di fine" +msgstr "Data Fine" msgid "Category" msgstr "Categoria" msgid "Start Time" -msgstr "Ora di inizio" +msgstr "Data/Ora Inizio" msgid "End Time" -msgstr "Fine del tempo" +msgstr "Data/Ora Fine" msgid "Leave Status" -msgstr "Lasciare Stato" +msgstr "Stato Permesso" msgid "Select Client" -msgstr "Selezionare client" +msgstr "Seleziona Cliente" msgid "Not Selected" msgstr "Non selezionato" msgid "Or Project" -msgstr "O progetto" +msgstr "o Progetto" msgid "All Projects" msgstr "Tutti i progetti" msgid "All Status" -msgstr "Tutto Stato" +msgstr "Tutti gli Stati" msgid "Value" msgstr "Valore" @@ -912,25 +912,25 @@ msgid "Logo" msgstr "Logo" msgid "User Name" -msgstr "Nome utente" +msgstr "Nome Utente" msgid "Authentication Email" -msgstr "Autenticazione Email" +msgstr "Autenticazione email" msgid "User Level" -msgstr "Livello utente" +msgstr "Tipo Utente" msgid "Email" -msgstr "E-mail" +msgstr "email" msgid "User Roles" -msgstr "Ruoli utente" +msgstr "Ruolo Utente" msgid "Default Module" -msgstr "Modulo di default" +msgstr "Modulo Predefinito" msgid "No Default Module" -msgstr "Nessun modulo predefinito" +msgstr "Nessun Modulo Predefinito" msgid "Menu" msgstr "Menu" @@ -942,13 +942,13 @@ msgid "Order" msgstr "Ordine" msgid "Path" -msgstr "Il percorso" +msgstr "Percorso" msgid "Label" msgstr "Etichetta" msgid "User Levels" -msgstr "Gradi" +msgstr "Livelli Utente" msgid "Module" msgstr "Modulo" @@ -957,79 +957,79 @@ msgid "All Modules" msgstr "Tutti i moduli" msgid "Invoice Period Start" -msgstr "Fattura Periodo Inizio" +msgstr "Inizio Periodo Fatturazione" msgid "Invoice Period End" -msgstr "Fattura fine periodo" +msgstr "Fine Periodo Fatturazione" msgid "Due date" msgstr "Scadenza" msgid "Url" -msgstr "Url" +msgstr "url" msgid "Original Text" -msgstr "Testo originale" +msgstr "Testo Originale" msgid "Mapped Text" -msgstr "Testo mappata" +msgstr "Testo Mappato" msgid "Display Status" -msgstr "Display di stato" +msgstr "Visualizzazione" msgid "Field Type" -msgstr "Tipo di campo" +msgstr "Tipo di Campo" msgid "Field Label" -msgstr "Campo Label" +msgstr "Titolo Campo" msgid "Validation" msgstr "Validazione" msgid "Field Options" -msgstr "Opzioni per i campi" +msgstr "Opzioni dei Campi" msgid "Priority" -msgstr "Priorità" +msgstr "Priorità" msgid "Display Section" -msgstr "Sezione display" +msgstr "Sezione Visualizzazione" msgid "Salary Component Type" -msgstr "Stipendio tipo di componente" +msgstr "Tipo Componente Stipendio" msgid "Salary Component" -msgstr "Stipendio Componente" +msgstr "Componente Stipendio" msgid "Pay Frequency" -msgstr "Pay Frequenza" +msgstr "Frequenza Pagamento" msgid "Calculation Group" -msgstr "Calcolo Gruppo" +msgstr "Gruppo Calcolo" msgid "None" -msgstr "Nessuna" +msgstr "Nessuno/a" msgid "Calculation Exemptions" -msgstr "Esenzioni di calcolo" +msgstr "Esenzioni Calcolo" msgid "Calculations Assigned" -msgstr "Calcoli assegnato" +msgstr "Calcoli Assegnati" msgid "Date Start" -msgstr "Data di inizio" +msgstr "Data Inizio" msgid "Date End" -msgstr "Data fine" +msgstr "Data Fine" msgid "Payslip Template" -msgstr "Busta paga Template" +msgstr "Template Busta Paga" msgid "Payroll Columns" -msgstr "Colonne Payroll" +msgstr "Colonne Libro Paga" msgid "Calculation Method" -msgstr "Metodo di calcolo" +msgstr "Metodo Calcolo" msgid "Editable" msgstr "Modificabile" @@ -1038,64 +1038,64 @@ msgid "Enabled" msgstr "Abilitato" msgid "Predefined Calculations" -msgstr "Calcoli predefiniti" +msgstr "Calcoli Predefiniti" msgid "Salary Components" -msgstr "Componenti stipendio" +msgstr "Componenti Stipendio" msgid "Columns to Add" -msgstr "Colonne per aggiungere" +msgstr "Colonne da Aggiungere" msgid "Columns to Subtract" -msgstr "Colonne da sottrarre" +msgstr "Colonne da Sottrarre" msgid "Column Order" -msgstr "Ordine delle colonne" +msgstr "Ordine delle Colonne" msgid "Default Value" -msgstr "Valore di default" +msgstr "Valore Predefinito" msgid "Calculation Columns" -msgstr "Colonne di calcolo" +msgstr "Colonne di Calcolo" msgid "Function" msgstr "Funzione" msgid "Payroll Report Column" -msgstr "Payroll Rapporto Colonna" +msgstr "Colonna Report Libro Paga" msgid "Calculation Process" -msgstr "Processo di calcolo" +msgstr "Processo di Calcolo" msgid "Payslip Fields" -msgstr "Busta paga campi" +msgstr "Campi Busta Paga" msgid "Payroll Column" -msgstr "Payroll Colonna" +msgstr "Colonna Libro Paga" msgid "Text" msgstr "Testo" msgid "Lower Limit Condition" -msgstr "Limite inferiore Stato" +msgstr "Condizione Limite Inferiore" msgid "Lower Limit" -msgstr "Limite inferiore" +msgstr "Limite Inferiore" msgid "Upper Limit Condition" -msgstr "Superiore condizione limite" +msgstr "Condizione Limite Superiore" msgid "Upper Limit" -msgstr "Limite superiore" +msgstr "Limite Superiore" msgid "Column" msgstr "Colonna" msgid "Job Code" -msgstr "Codice Job" +msgstr "Codice Lavoro" msgid "Short Description" -msgstr "Breve descrizione" +msgstr "Descrizione" msgid "Requirements" msgstr "Requisiti" @@ -1104,115 +1104,115 @@ msgid "Benefits" msgstr "Benefici" msgid "Employment Type" -msgstr "Tipo di impiego" +msgstr "Tipo di Impiego" msgid "Any Employment Type" -msgstr "Qualsiasi Tipo di impiego" +msgstr "Qualsiasi Tipo di Impiego" msgid "Experience Level" -msgstr "Livello di esperienza" +msgstr "Livello di Esperienza" msgid "Any Experience Level" -msgstr "Qualsiasi livello Esperienza" +msgstr "Qualsiasi Livello Esperienza" msgid "Job Function" msgstr "Funzione Lavorativa" msgid "Any Job Function" -msgstr "Qualsiasi funzione Job" +msgstr "Qualsiasi Funzione Lavorativa" msgid "Education Level" -msgstr "Livello di educazione" +msgstr "Livello Istruzione" msgid "Any Education Level" -msgstr "Qualsiasi Livello di istruzione" +msgstr "Qualsiasi Livello di Istruzione" msgid "Show Salary" msgstr "Visualizza Stipendio" msgid "Salary Min" -msgstr "Retribuzione min" +msgstr "Stipendio Min" msgid "Salary Max" msgstr "Stipendio Max" msgid "Keywords" -msgstr "Parole" +msgstr "Parole Chiave" msgid "Closing Date" -msgstr "Data di chiusura" +msgstr "Data Chiusura" msgid "Image" msgstr "Immagine" msgid "Display Type" -msgstr "Tipo di visualizzazione" +msgstr "Tipo Visualizzazione" msgid "Profile Image" -msgstr "Profilo Immagine" +msgstr "Immagine del Profilo" msgid "Telephone" msgstr "Telefono" msgid "Resume Title" -msgstr "Riprendi Titolo" +msgstr "Nome CV" msgid "Resume" -msgstr "Curriculum vitae" +msgstr "Curriculum Vitae" msgid "Resume Headline" -msgstr "Riprendi Headline" +msgstr "Titolo CV" msgid "Profile Summary" -msgstr "Riassunto del profilo" +msgstr "Riassunto Profilo" msgid "Work History" -msgstr "Storia del lavoro" +msgstr "Esperienze Lavorative" msgid "Education" -msgstr "Educazione" +msgstr "Istruzione" msgid "Skills" -msgstr "Abilità" +msgstr "Competenze" msgid "Referees" -msgstr "Arbitri" +msgstr "Referenze" msgid "From Year" msgstr "Da Anno" msgid "From Month" -msgstr "Dal mese" +msgstr "Da Mese" msgid "To Year" -msgstr "Per Anno" +msgstr "Ad Anno" msgid "To Month" -msgstr "Per Mese" +msgstr "A Mese" msgid "Currently Work Here" -msgstr "Attualmente Lavora qui" +msgstr "Lavoro Attuale" msgid "Degree/Diploma" -msgstr "Diploma di laurea" +msgstr "Laurea/Diploma" msgid "Currently Studying" -msgstr "Attualmente studia" +msgstr "Studio Attuale" msgid "Skill Level" -msgstr "Livello di abilità" +msgstr "Livello di Competenza" msgid "Last Used Year" -msgstr "Ultimo usato anno" +msgstr "Ultimo Anno Usato" msgid "Last Used Month" -msgstr "Ultimo mese Usato" +msgstr "Ultimo Mese Usato" msgid "Years of Experience" -msgstr "Anni di esperienza" +msgstr "Anni di Esperienza" msgid "Designation" -msgstr "Designazione" +msgstr "Nomina" msgid "Phone" msgstr "Telefono" @@ -1224,40 +1224,40 @@ msgid "Candidate" msgstr "Candidato" msgid "Referred By" -msgstr "Riferito da" +msgstr "Referenziato da" msgid "Leave Start Date" -msgstr "Lasciare Data di inizio" +msgstr "Data Inizio" msgid "Leave End Date" -msgstr "Lasciare Data fine" +msgstr "Data Fine" msgid "Reason" -msgstr "Ragionare" +msgstr "Motivo" msgid "Available Leaves" -msgstr "Foglie disponibili" +msgstr "Disponibili" msgid "Approved Leaves" -msgstr "Foglie approvati" +msgstr "Approvati" msgid "Rejected Leaves" -msgstr "Foglie rifiutati" +msgstr "Rifiutati" msgid "Leaves to be Accrued" -msgstr "Lascia maturerà" +msgstr "Accumulati" msgid "Leaves Carried Forward" -msgstr "Foglie Carried Forward" +msgstr "Riportati" msgid "Apply Leave" -msgstr "Applicare Leave" +msgstr "Richiesta Permesso" msgid "Filter" msgstr "Filtro" msgid "Add New" -msgstr "Aggiungere nuova" +msgstr "Aggiungi Nuovo" msgid "Time" msgstr "Tempo" @@ -1266,205 +1266,205 @@ msgid "Purpose" msgstr "Scopo" msgid "From" -msgstr "Da parte di" +msgstr "Da" msgid "To" msgstr "A" msgid "Created (GMT)" -msgstr "Creato (GMT)" +msgstr "Data Creazione" msgid "Download" -msgstr "Scaricare" +msgstr "Scaricato" msgid "Submit" -msgstr "Invio" +msgstr "Invia" msgid "Upload" -msgstr "Caricare" +msgstr "Carica" msgid "Remove" -msgstr "Rimuovere" +msgstr "Rimuovi" msgid "Add" -msgstr "Aggiungere" +msgstr "Aggiungi" msgid "Reset" msgstr "Reset" msgid "Add Time Entry" -msgstr "Aggiungere Tempo Entry" +msgstr "Aggiungi Orario" msgid "Current Clocked In Status" -msgstr "Corrente Clocked In Stato" +msgstr "Stato Attuale Timbratura" msgid "Attendance entry should be within a single day" -msgstr "Ingresso frequenza dovrebbe essere all'interno di un solo giorno" +msgstr "La presenza deve essere inserita entro un giorno" msgid "Account Balance" -msgstr "Saldo conto" +msgstr "Saldo Conto" msgid "Plan" msgstr "Piano" msgid "Transactions" -msgstr "Le transazioni" +msgstr "Transazioni" msgid "Applications" -msgstr "Applicazioni" +msgstr "Richieste" msgid "Attendance Graph" -msgstr "La partecipazione Grafico" +msgstr "Grafico Presenza" msgid "Hours in Office vs Hours Worked Graph" -msgstr "Ore in Office vs grafico ore lavorate" +msgstr "Ore in Uffice / Grafico Ore Lavorate" msgid "Company Graph" -msgstr "Società Grafico" +msgstr "Struttura Società" msgid "Company Documents" -msgstr "Documenti aziendali" +msgstr "Documenti Aziendali" msgid "Document Types" -msgstr "Tipi di documenti" +msgstr "Tipi Documenti" msgid "Employee Documents" -msgstr "Documenti per i dipendenti" +msgstr "Documenti dei Dipendenti" msgid "Employee Basic Details" -msgstr "Impiegato Dettagli di base" +msgstr "Dettagli Base Dipendenti" msgid "Employees (Direct Reports)" -msgstr "Dipendenti (Rapporti diretti)" +msgstr "Dipendenti (Riporti Diretti)" msgid "Certifications" msgstr "Certificazioni" msgid "Languages" -msgstr "Le lingue" +msgstr "Lingue" msgid "Deactivated Employees" -msgstr "I dipendenti Disattivato" +msgstr "Dipendenti Licenziati" msgid "Temporarily Deactivated Employees" -msgstr "I dipendenti temporaneamente Disattivato" +msgstr "Dipendenti Temporaneamente Licenziati" msgid "Terminated Employee Data" -msgstr "Terminato dati dei dipendenti" +msgstr "Dati Dipendenti Licenziati" msgid "Employee Saved Successfully" -msgstr "Impiegato salvato con successo" +msgstr "Dipendente Salvato" msgid "Employee needs a User to login to IceHrm. Do you want to create a user for this employee now?" -msgstr "Dipendente ha bisogno di un utente per accedere a IceHrm. Vuoi creare un utente per questo dipendente ora?" +msgstr "Serve un utente per accedere. Vuoi creare un utente associato a questo dipendente ora?" msgid "You can do this later through Users module if required." -msgstr "È possibile farlo in seguito tramite modulo utenti, se necessario." +msgstr "È possibile farlo in seguito tramite il modulo utenti, se necessario." msgid "Expenses Categories" -msgstr "Spese Categorie" +msgstr "Categorie Spese" msgid "Payment Methods" -msgstr "Modalità di pagamento" +msgstr "Modalità Pagamento" msgid "Employee Expenses" -msgstr "Spese dei dipendenti" +msgstr "Spese Dipendenti" msgid "Salary Component Types" -msgstr "Tipi Stipendio componenti" +msgstr "Tipi Componenti Stipendio" msgid "Employee Salary Components" -msgstr "Componenti di stipendio ai dipendenti" +msgstr "Componenti Stipendio Dipendenti" msgid "Company Payroll" -msgstr "Società Payroll" +msgstr "Libro Paga Società" msgid "Calculation Groups" -msgstr "Gruppi di calcolo" +msgstr "Gruppi di Calcoli" msgid "Calculation Methods" -msgstr "Metodi di calcolo" +msgstr "Metodi di Calcolo" msgid "Payslip Templates" -msgstr "Modelli busta paga" +msgstr "Modelli Busta Paga" msgid "Edit Employment Types" -msgstr "Tipi Modifica occupazione" +msgstr "Modifica Tipi Occupazione" msgid "Edit Experience Levels" -msgstr "Livelli Modifica Experience" +msgstr "Modifica Livelli Esperienza" msgid "Edit Job Functions" -msgstr "Funzioni Modifica lavoro" +msgstr "Modifica Funzioni Lavorative" msgid "Edit Education Levels" -msgstr "Livelli Modifica Istruzione" +msgstr "Modifica Livelli Istruzione" msgid "Edit Benefits" -msgstr "Modifica Vantaggi" +msgstr "Modifica Benefit" msgid "Application" -msgstr "Applicazione" +msgstr "Richiesta" msgid "Job Titles" -msgstr "Titolo di lavoro" +msgstr "Titolo Lavoro" msgid "Pay Grades" -msgstr "Gradi pay" +msgstr "Livelli Retributivi" msgid "Training Sessions" -msgstr "Sessione di allenamento" +msgstr "Corsi Formazione" msgid "Employee Training Sessions" -msgstr "Employee Training Sessions" +msgstr "Corsi Formazione Dipendenti" msgid "Clients" msgstr "Clienti" msgid "Employee Projects" -msgstr "Progetti per i dipendenti" +msgstr "Progetti Dipendenti" msgid "Leave Types" -msgstr "Lasciare Tipi" +msgstr "Tipi Permesso" msgid "Work Week" -msgstr "Settimana lavorativa" +msgstr "Settimana Lavorativa" msgid "Holidays" msgstr "Vacanze" msgid "Leave Rules" -msgstr "Lascia Regole" +msgstr "Regole Permessi" msgid "Paid Time Off" -msgstr "Tempo paid fuori" +msgstr "Permesso Retribuito" msgid "Leave Groups" -msgstr "Lascia Gruppi" +msgstr "Gruppi Permessi" msgid "Edit Leave Groups" -msgstr "Modifica Lasciare Gruppi" +msgstr "Modifica Gruppi Permessi" msgid "Leave Group Employees" -msgstr "Lasciare Dipendenti del Gruppo" +msgstr "Gruppi Permessi Dipendenti" msgid "Employee Leave List" -msgstr "Employee List Leave" +msgstr "Elenco Permessi Dipendenti" msgid "Loan Types" -msgstr "Tipi di prestito" +msgstr "Tipi Prestito" msgid "Employee Loans" -msgstr "Prestiti dipendenti" +msgstr "Prestiti Dipendenti" msgid "Travel Requests" -msgstr "Le richieste di viaggio" +msgstr "Richieste Trasferta" msgid "Overtime Categories" -msgstr "Overtime Categorie" +msgstr "Categorie Straordinari" msgid "Leave / PTO" -msgstr "Lasciare / PTO" +msgstr "Permesso" msgid "Other" msgstr "Altro" @@ -1479,121 +1479,427 @@ msgid "Provinces" msgstr "Province" msgid "Currency Types" -msgstr "Tipi di valuta" +msgstr "Tipi di Valuta" msgid "Employee Custom Fields" -msgstr "Impiegato campi personalizzati" +msgstr "Campi Personalizzati Dipendente" msgid "Employee Field Names" -msgstr "Dipendenti Nomi di campo" +msgstr "Nomi Campo Dipendente" msgid "My Details" -msgstr "I miei dettagli" +msgstr "I Miei Dettagli" msgid "All My Leaves" -msgstr "Tutte le mie foglie" +msgstr "Elenco Miei Permessi" msgid "Leave Entitlement" -msgstr "Lasciare diritto" +msgstr "Diritto al Permesso" msgid "Approved Leave" -msgstr "Lasciare approvato" +msgstr "Permesso Approvato" msgid "Pending Leave" -msgstr "In attesa Leave" +msgstr "Permesso in Attesa" msgid "Subordinate Leave" -msgstr "Lasciare subordinato" +msgstr "Permesso Subordinato" msgid "Cancellation Requests" -msgstr "Le richieste di annullamento" +msgstr "Richieste Cancellazione" msgid "Approval Requests" -msgstr "Le richieste di approvazione" +msgstr "Richieste Approvazione" msgid "Approved TimeSheets" -msgstr "Schede attività approvate" +msgstr "Fogli Attività Approvati" msgid "All My TimeSheets" -msgstr "Tutte le mie schede attività" +msgstr "I Miei Fogli Attività" msgid "Pending TimeSheets" -msgstr "Schede attività in sospeso" +msgstr "Fogli Attività in Sospeso" msgid "Subordinate TimeSheets" -msgstr "Schede attività subordinate" +msgstr "Fogli Attività Subordinati" msgid "Approved Attendance Sheets" -msgstr "Fogli di presenza approvati" +msgstr "Fogli Attività Approvati" msgid "All My Attendance Sheets" -msgstr "Tutte le mie presenze fogli" +msgstr "I Miei Fogli Presenza" msgid "Pending Attendance Sheets" -msgstr "In attesa di fogli di presenza" +msgstr "Fogli Presenza in Sospeso" msgid "Subordinate Attendance Sheets" -msgstr "Fogli di presenza subordinato" +msgstr "Fogli Presenza Subordinati" msgid "Subordinate Overtime Requests" -msgstr "Richieste Overtime subordinato" +msgstr "Richieste Straordinari Subordinati" msgid "Overtime Request Approval" -msgstr "Overtime Richiesta di approvazione" +msgstr "Richiesta Approvazione Straordinari" msgid "My Training Sessions" -msgstr "Le mie sessioni di formazione" +msgstr "I Miei Corsi di Formazione" msgid "All Training Sessions" -msgstr "Tutti gli allenamenti" +msgstr "Tutti i Corsi di Formazione" msgid "Training Sessions of Direct Reports" -msgstr "Le sessioni di formazione di rapporti diretti" +msgstr "Corsi Formazione dei Diretti Riporti" msgid "Subordinate Travel Requests" -msgstr "Le richieste di viaggio subordinato" +msgstr "Richieste Viaggio dei Subordinati" msgid "Travel Request Approval" -msgstr "Richiesta di Viaggio Soddisfazione" +msgstr "Richiesta Approvazione Trasferta" msgid "Subordinate Expenses" -msgstr "Le spese subordinato" +msgstr "Spese dei Subordinati" msgid "Expenses Approval" -msgstr "Le spese di approvazione" +msgstr "Approvazione Spese" msgid "Loans Taken" -msgstr "Prestiti contratti" +msgstr "Prestiti Contratti" msgid "Change Leave Status" -msgstr "Cambiare Leave Stato" +msgstr "Cambiare Stato Permesso" msgid "Status Change Note" -msgstr "Modifica stato Nota" +msgstr "Nota Cambio Stato" msgid "Leave Summary" -msgstr "Lasciare Sommario" +msgstr "Sommario Permessi" msgid "Approved Leave Count" -msgstr "Conte Leave Approvato" +msgstr "Totale Permessi Approvati" msgid "Pending Leave Count" -msgstr "In attesa di Conte Leave" +msgstr "Totale Permessi in Attesa" msgid "Available Leave Count" -msgstr "Disponibile Conte Leave" +msgstr "Totale Permessi Disponibili" msgid "Leave Dates" -msgstr "Lascia le date" +msgstr "Date Permessi" msgid "Leave Date" -msgstr "Data Lascia" +msgstr "Data Permesso" msgid "Leave Notes" -msgstr "Lascia Note" +msgstr "Note Permesso" msgid "Apply" -msgstr "Applicare" +msgstr "Richiedi" msgid "Back" msgstr "Indietro" + +msgid "Hours in Time Sheets" +msgstr "Ore in tempo Sheets" + +msgid "HR form" +msgstr "modulo HR" + +msgid "HR Form Management" +msgstr "Gestione forma HR" + +msgid "Form Name" +msgstr "Nome modulo" + +msgid "Fields" +msgstr "campi" + +msgid "Employee Froms" +msgstr "Impiegato Froms" + +msgid "Share Departments" +msgstr "Dipartimenti Condividi" + +msgid "Share Employees" +msgstr "I dipendenti Condividi" + +msgid "Data Importers" +msgstr "Importatori dati" + +msgid "Data Import Files" +msgstr "Importa file di dati" + +msgid "Data Type" +msgstr "Tipo di dati" + +msgid "Columns" +msgstr "colonne" + +msgid "Field Title" +msgstr "campo Titolo" + +msgid "Depends On" +msgstr "Dipende da" + +msgid "Depends On Field" +msgstr "Dipende dal Campo" + +msgid "is Key Field" +msgstr "è Key Field" + +msgid "is ID Field" +msgstr "è ID Campo" + +msgid "Data Import Definitions" +msgstr "Importare i dati Definizioni" + +msgid "File to Import" +msgstr "File da importare" + +msgid "Last Export Results" +msgstr "Ultimi Esporta risultati" + +msgid "Time and Attendance" +msgstr "Rilevazione Presenze" + +msgid "Leave Timeline" +msgstr "Lascia Timeline" + +msgid "Insights" +msgstr "Approfondimenti" + +msgid "Api Access" +msgstr "Api di accesso" + +msgid "Change User Password" +msgstr "Cambia password utente" + +msgid "New Password" +msgstr "nuova password" + +msgid "Confirm Password" +msgstr "conferma password" + +msgid "Change Password" +msgstr "Cambia la password" + +msgid "Not Now" +msgstr "Non adesso" + +msgid "Contact Information" +msgstr "Informazioni sui contatti" + +msgid "Job Details" +msgstr "Dettagli di lavoro" + +msgid "Edit Info" +msgstr "Modifica informazioni" + +msgid "Upload Profile Image" +msgstr "Carica Immagine" + +msgid "Delete Profile Image" +msgstr "Elimina profilo Immagine" + +msgid "Direct Reports" +msgstr "Rapporti diretti" + +msgid "Other Details" +msgstr "Altri dettagli" + +msgid "Family" +msgstr "Famiglia" + +msgid "Custom Fields" +msgstr "Campi personalizzati" + +msgid "Means of Transportation" +msgstr "Mezzi di trasporto" + +msgid "Plane" +msgstr "Aereo" + +msgid "Rail" +msgstr "Rotaia" + +msgid "Taxi" +msgstr "Taxi" + +msgid "Own Vehicle" +msgstr "Il proprio veicolo" + +msgid "Rented Vehicle" +msgstr "veicolo noleggiato" + +msgid "Female" +msgstr "Femmina" + +msgid "Male" +msgstr "Maschio" + +msgid "Active" +msgstr "Attivo" + +msgid "Inactive" +msgstr "Inattivo" + +msgid "Draft" +msgstr "Bozza" + +msgid "Not Clocked In" +msgstr "Non cronometrato dentro" + +msgid "Clocked In" +msgstr "In clock" + +msgid "File" +msgstr "File" + +msgid "Active Employee Report" +msgstr "Rapporto attivo dei dipendenti" + +msgid "Employee Attendance Report" +msgstr "Impiegato frequenza Rapporto" + +msgid "Employee Details Report" +msgstr "Impiegato dettagli Segnala" + +msgid "Employee Leave Entitlement" +msgstr "Impiegato diritto alle ferie" + +msgid "Employee Leaves Report" +msgstr "Dipendente lascia Rapporto" + +msgid "Employee Time Entry Report" +msgstr "Impiegato Tempo voce del report" + +msgid "Employee Time Sheet Report" +msgstr "Time Foglio Relazione" + +msgid "Employee Time Tracking Report" +msgstr "Employee Tracking Report Tempo" + +msgid "Expense Report" +msgstr "Expense report" + +msgid "New Hires Employee Report" +msgstr "Nuovi assunti rapporto dei dipendenti" + +msgid "Overtime Report" +msgstr "Overtime Rapporto" + +msgid "Overtime Request Report" +msgstr "Richiesta Straordinario rapporto" + +msgid "Overtime Summary Report" +msgstr "Overtime Summary Report" + +msgid "Payroll Meta Data Export" +msgstr "Payroll Meta Data Export" + +msgid "Terminated Employee Report" +msgstr "Terminato Rapporto dei dipendenti" + +msgid "Travel Request Report" +msgstr "Richiesta di Viaggio Rapporto" + +msgid "Attendance Report" +msgstr "Rapporto di partecipazione" + +msgid "Client Project Time Report" +msgstr "Cliente Progetto di Rapporto" + +msgid "Download Payslips" +msgstr "Scarica buste paga" + +msgid "Leaves Report" +msgstr "lascia Rapporto" + +msgid "Time Entry Report" +msgstr "Tempo di entrata Rapporto" + +msgid "Time Sheet Report" +msgstr "Time Sheet Rapporto" + +msgid "Time Tracking Report" +msgstr "Tracking Report Tempo" + +msgid "Data" +msgstr "Dati" + +msgid "Processed" +msgstr "Processed" + +msgid "Not Processed" +msgstr "Non processato" + +msgid "Elementary Proficiency" +msgstr "Competenza elementare" + +msgid "Limited Working Proficiency" +msgstr "Conoscenza lavorativa limitata" + +msgid "Professional Working Proficiency" +msgstr "Conoscenza professionale" + +msgid "Full Professional Proficiency" +msgstr "Piena competenza professionale" + +msgid "Native or Bilingual Proficiency" +msgstr "Conoscenza madrelingua o bilingue" + +msgid "Pending" +msgstr "in attesa di" + +msgid "Approved" +msgstr "Approvato" + +msgid "Rejected" +msgstr "Respinto" + +msgid "Cancelled" +msgstr "Annullato" + +msgid "Continue" +msgstr "Continua" + +msgid "Cancellation Requested" +msgstr "Annullamento richiesto" + +msgid "Completed" +msgstr "Completato" + +msgid "Discussions" +msgstr "discussioni" + +msgid "Load More" +msgstr "Carica di più" + +msgid "Show More" +msgstr "Mostra di più" + +msgid "Show Less" +msgstr "Mostra meno" + +msgid "Publish" +msgstr "Pubblicare" + +msgid "Announcements" +msgstr "Annunci" + +msgid "Send" +msgstr "Inviare" + +msgid "Display" +msgstr "Display" + +msgid "Public" +msgstr "Pubblico" + +msgid "View Announcements" +msgstr "Visualizza annunci" + +msgid "Conversations" +msgstr "conversazioni" + +msgid "Start Now" +msgstr "Avviare ora" diff --git a/core/lang/ja.po b/core/lang/ja.po index 51848544..26337513 100644 --- a/core/lang/ja.po +++ b/core/lang/ja.po @@ -1597,3 +1597,309 @@ msgstr "é©ç”¨ã—ã¾ã™" msgid "Back" msgstr "ãƒãƒƒã‚¯" + +msgid "Hours in Time Sheets" +msgstr "ã‚¿ã‚¤ãƒ ã‚·ãƒ¼ãƒˆã§æ™‚é–“" + +msgid "HR form" +msgstr "HRフォーム" + +msgid "HR Form Management" +msgstr "HRフォームã®ç®¡ç†" + +msgid "Form Name" +msgstr "フォームå" + +msgid "Fields" +msgstr "フィールド" + +msgid "Employee Froms" +msgstr "従業員ã¯Froms" + +msgid "Share Departments" +msgstr "æ ªå¼éƒ¨é–€" + +msgid "Share Employees" +msgstr "共有従業員" + +msgid "Data Importers" +msgstr "データ輸入" + +msgid "Data Import Files" +msgstr "データã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆãƒ•ァイル" + +msgid "Data Type" +msgstr "データ・タイプ" + +msgid "Columns" +msgstr "コラム" + +msgid "Field Title" +msgstr "フィールドã®ã‚¿ã‚¤ãƒˆãƒ«" + +msgid "Depends On" +msgstr "ä¾å­˜" + +msgid "Depends On Field" +msgstr "フィールドã«ä¾å­˜ã—ã¾ã™" + +msgid "is Key Field" +msgstr "キー・フィールドã§ã‚りã¾ã™" + +msgid "is ID Field" +msgstr "IDフィールドã¯ã€" + +msgid "Data Import Definitions" +msgstr "データã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã®å®šç¾©" + +msgid "File to Import" +msgstr "インãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ァイル" + +msgid "Last Export Results" +msgstr "æœ€çµ‚çµæžœã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ" + +msgid "Time and Attendance" +msgstr "時間ã¨å‡ºå¸­" + +msgid "Leave Timeline" +msgstr "タイムラインを残ã—ã¾ã™" + +msgid "Insights" +msgstr "洞察" + +msgid "Api Access" +msgstr "APIアクセス" + +msgid "Change User Password" +msgstr "ユーザパスワードã®å¤‰æ›´" + +msgid "New Password" +msgstr "æ–°ã—ã„パスワード" + +msgid "Confirm Password" +msgstr "パスワードをèªè¨¼ã™ã‚‹" + +msgid "Change Password" +msgstr "パスワードを変更ã™ã‚‹" + +msgid "Not Now" +msgstr "今ã¯ã‚„ã‚ã‚" + +msgid "Contact Information" +msgstr "連絡先" + +msgid "Job Details" +msgstr "仕事ã®è©³ç´°" + +msgid "Edit Info" +msgstr "編集情報" + +msgid "Upload Profile Image" +msgstr "プロフィール画åƒã‚’アップロード" + +msgid "Delete Profile Image" +msgstr "プロフィール画åƒã‚’削除ã—ã¾ã™" + +msgid "Direct Reports" +msgstr "直接レãƒãƒ¼ãƒˆ" + +msgid "Other Details" +msgstr "ãã®ä»–ã®æƒ…å ±" + +msgid "Family" +msgstr "å®¶æ—" + +msgid "Custom Fields" +msgstr "カスタムフィールド" + +msgid "Means of Transportation" +msgstr "ç¿»è¨³ã®æ„味" + +msgid "Plane" +msgstr "飛行機" + +msgid "Rail" +msgstr "レール" + +msgid "Taxi" +msgstr "タクシー" + +msgid "Own Vehicle" +msgstr "自車" + +msgid "Rented Vehicle" +msgstr "レンタル車" + +msgid "Female" +msgstr "女性" + +msgid "Male" +msgstr "男性" + +msgid "Active" +msgstr "アクティブ" + +msgid "Inactive" +msgstr "䏿´»ç™º" + +msgid "Draft" +msgstr "ドラフト" + +msgid "Not Clocked In" +msgstr "クロックインã§ã¯ã‚りã¾ã›ã‚“" + +msgid "Clocked In" +msgstr "クロックイン" + +msgid "File" +msgstr "ファイル" + +msgid "Active Employee Report" +msgstr "アクティブãªå¾“業員レãƒãƒ¼ãƒˆ" + +msgid "Employee Attendance Report" +msgstr "従業員ã®å‡ºå¸­ãƒ¬ãƒãƒ¼ãƒˆ" + +msgid "Employee Details Report" +msgstr "従業員詳細レãƒãƒ¼ãƒˆ" + +msgid "Employee Leave Entitlement" +msgstr "従業員ã®ä¼‘暇資格" + +msgid "Employee Leaves Report" +msgstr "従業員ã®è‘‰ãƒ¬ãƒãƒ¼ãƒˆ" + +msgid "Employee Time Entry Report" +msgstr "従業員ã®ã‚¿ã‚¤ãƒ ã‚¨ãƒ³ãƒˆãƒªãƒ¬ãƒãƒ¼ãƒˆ" + +msgid "Employee Time Sheet Report" +msgstr "従業員ã®ã‚¿ã‚¤ãƒ ã‚·ãƒ¼ãƒˆãƒ¬ãƒãƒ¼ãƒˆ" + +msgid "Employee Time Tracking Report" +msgstr "従業員ã®ã‚¿ã‚¤ãƒ ãƒˆãƒ©ãƒƒã‚­ãƒ³ã‚°ãƒ¬ãƒãƒ¼ãƒˆ" + +msgid "Expense Report" +msgstr "経費報告書" + +msgid "New Hires Employee Report" +msgstr "新入社員従業員レãƒãƒ¼ãƒˆ" + +msgid "Overtime Report" +msgstr "残業レãƒãƒ¼ãƒˆ" + +msgid "Overtime Request Report" +msgstr "残業リクエストレãƒãƒ¼ãƒˆ" + +msgid "Overtime Summary Report" +msgstr "æ®‹æ¥­ã®æ¦‚è¦ãƒ¬ãƒãƒ¼ãƒˆ" + +msgid "Payroll Meta Data Export" +msgstr "給与メタデータã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ" + +msgid "Terminated Employee Report" +msgstr "退è·ã—ãŸå¾“業員レãƒãƒ¼ãƒˆ" + +msgid "Travel Request Report" +msgstr "トラベルリクエストレãƒãƒ¼ãƒˆ" + +msgid "Attendance Report" +msgstr "出席報告書" + +msgid "Client Project Time Report" +msgstr "クライアントã®ãƒ—ロジェクト時間レãƒãƒ¼ãƒˆ" + +msgid "Download Payslips" +msgstr "ダウンロード給与明細" + +msgid "Leaves Report" +msgstr "報告書ã¯ã€è‘‰" + +msgid "Time Entry Report" +msgstr "タイムエントリレãƒãƒ¼ãƒˆ" + +msgid "Time Sheet Report" +msgstr "タイムシートã®ãƒ¬ãƒãƒ¼ãƒˆ" + +msgid "Time Tracking Report" +msgstr "タイムトラッキングレãƒãƒ¼ãƒˆ" + +msgid "Data" +msgstr "データ" + +msgid "Processed" +msgstr "処ç†ã•れã¾ã—ãŸ" + +msgid "Not Processed" +msgstr "処ç†ã•れã¦ã„ã¾ã›ã‚“" + +msgid "Elementary Proficiency" +msgstr "å°å­¦æ ¡èƒ½åŠ›" + +msgid "Limited Working Proficiency" +msgstr "リミテッド作業能力" + +msgid "Professional Working Proficiency" +msgstr "プロフェッショナルã®ä½œæ¥­èƒ½åŠ›" + +msgid "Full Professional Proficiency" +msgstr "完全ãªãƒ—ロフェッショナル能力" + +msgid "Native or Bilingual Proficiency" +msgstr "æ¯å›½èªžã¾ãŸã¯ãƒã‚¤ãƒªãƒ³ã‚¬ãƒ«" + +msgid "Pending" +msgstr "ä¿ç•™ä¸­" + +msgid "Approved" +msgstr "承èª" + +msgid "Rejected" +msgstr "æ‹’å¦ã•れã¾ã—ãŸ" + +msgid "Cancelled" +msgstr "キャンセル" + +msgid "Continue" +msgstr "æŒç¶šã™ã‚‹" + +msgid "Cancellation Requested" +msgstr "ã‚­ãƒ£ãƒ³ã‚»ãƒ«è¦æ±‚" + +msgid "Completed" +msgstr "完æˆã—ã¾ã—ãŸ" + +msgid "Discussions" +msgstr "è­°è«–" + +msgid "Load More" +msgstr "以上ã®è² è·" + +msgid "Show More" +msgstr "ã‚‚ã£ã¨è¦‹ã›ã‚‹" + +msgid "Show Less" +msgstr "レスを表示" + +msgid "Publish" +msgstr "出版ã—ã¾ã™" + +msgid "Announcements" +msgstr "ãŠçŸ¥ã‚‰ã›" + +msgid "Send" +msgstr "é€ã‚Šã¾ã™" + +msgid "Display" +msgstr "表示" + +msgid "Public" +msgstr "パブリック" + +msgid "View Announcements" +msgstr "ビューã®ãŠçŸ¥ã‚‰ã›" + +msgid "Conversations" +msgstr "会話" + +msgid "Start Now" +msgstr "今ã™ãé–‹å§‹" diff --git a/core/lang/pl.po b/core/lang/pl.po index ae1037d5..bb5f5658 100644 --- a/core/lang/pl.po +++ b/core/lang/pl.po @@ -1597,3 +1597,309 @@ msgstr "Zastosować" msgid "Back" msgstr "Plecy" + +msgid "Hours in Time Sheets" +msgstr "Godzin w kartach czasu" + +msgid "HR form" +msgstr "Formularz HR" + +msgid "HR Form Management" +msgstr "Formularz ZarzÄ…dzanie HR" + +msgid "Form Name" +msgstr "Nazwa formularza" + +msgid "Fields" +msgstr "pola" + +msgid "Employee Froms" +msgstr "froms pracownik" + +msgid "Share Departments" +msgstr "Departamenty dzielÄ…" + +msgid "Share Employees" +msgstr "Pracownicy Share" + +msgid "Data Importers" +msgstr "Importerzy danych" + +msgid "Data Import Files" +msgstr "Pliki importu danych" + +msgid "Data Type" +msgstr "Typ danych" + +msgid "Columns" +msgstr "kolumny" + +msgid "Field Title" +msgstr "pole TytuÅ‚" + +msgid "Depends On" +msgstr "Zależy od" + +msgid "Depends On Field" +msgstr "Zależy na pole" + +msgid "is Key Field" +msgstr "Pole jest klucz" + +msgid "is ID Field" +msgstr "Pole jest ID" + +msgid "Data Import Definitions" +msgstr "Import danych Definicje" + +msgid "File to Import" +msgstr "Plik do importu" + +msgid "Last Export Results" +msgstr "Ostatnio Wyniki eksportu" + +msgid "Time and Attendance" +msgstr "Rejestracja czasu pracy" + +msgid "Leave Timeline" +msgstr "Zostaw Timeline" + +msgid "Insights" +msgstr "Insights" + +msgid "Api Access" +msgstr "DostÄ™p do API" + +msgid "Change User Password" +msgstr "Zmiana użytkownika HasÅ‚o" + +msgid "New Password" +msgstr "nowe hasÅ‚o" + +msgid "Confirm Password" +msgstr "Potwierdź hasÅ‚o" + +msgid "Change Password" +msgstr "ZmieÅ„ hasÅ‚o" + +msgid "Not Now" +msgstr "Nie teraz" + +msgid "Contact Information" +msgstr "Informacje kontaktowe" + +msgid "Job Details" +msgstr "Szczegóły pracy" + +msgid "Edit Info" +msgstr "Edytuj informacje" + +msgid "Upload Profile Image" +msgstr "PrzeÅ›lij zdjÄ™cie profilowe" + +msgid "Delete Profile Image" +msgstr "UsuÅ„ Profil obraz" + +msgid "Direct Reports" +msgstr "BezpoÅ›rednie raporty" + +msgid "Other Details" +msgstr "Inne szczegóły" + +msgid "Family" +msgstr "Rodzina" + +msgid "Custom Fields" +msgstr "Pola niestandardowe" + +msgid "Means of Transportation" +msgstr "Åšrodki transportu" + +msgid "Plane" +msgstr "Samolot" + +msgid "Rail" +msgstr "Szyna" + +msgid "Taxi" +msgstr "Taxi" + +msgid "Own Vehicle" +msgstr "WÅ‚asny pojazd" + +msgid "Rented Vehicle" +msgstr "wynajÄ™ty pojazd" + +msgid "Female" +msgstr "PÅ‚eć żeÅ„ska" + +msgid "Male" +msgstr "MÄ™ski" + +msgid "Active" +msgstr "Aktywny" + +msgid "Inactive" +msgstr "Nieaktywny" + +msgid "Draft" +msgstr "Wersja robocza" + +msgid "Not Clocked In" +msgstr "W nie Clocked" + +msgid "Clocked In" +msgstr "W taktowany" + +msgid "File" +msgstr "Plik" + +msgid "Active Employee Report" +msgstr "Pracownik aktywny Report" + +msgid "Employee Attendance Report" +msgstr "Pracownik Frekwencja Report" + +msgid "Employee Details Report" +msgstr "Pracownik Szczegóły Report" + +msgid "Employee Leave Entitlement" +msgstr "Pracownik Leave Prawo" + +msgid "Employee Leaves Report" +msgstr "Pracownik LiÅ›cie Report" + +msgid "Employee Time Entry Report" +msgstr "Pracownik Czas ZgÅ‚oÅ› Entry" + +msgid "Employee Time Sheet Report" +msgstr "Etat Arkusz Report" + +msgid "Employee Time Tracking Report" +msgstr "Pracownik Time Tracking Report" + +msgid "Expense Report" +msgstr "Raport z wydatków" + +msgid "New Hires Employee Report" +msgstr "Nowych pracowników Employee Report" + +msgid "Overtime Report" +msgstr "Raport nadgodziny" + +msgid "Overtime Request Report" +msgstr "Nadgodziny Zapytanie Report" + +msgid "Overtime Summary Report" +msgstr "Nadgodziny Raport zbiorczy" + +msgid "Payroll Meta Data Export" +msgstr "PÅ‚ace Meta Data Export" + +msgid "Terminated Employee Report" +msgstr "Raport zakoÅ„czony Employee" + +msgid "Travel Request Report" +msgstr "Zapytanie Travel Report" + +msgid "Attendance Report" +msgstr "Lista obecnoÅ›ci" + +msgid "Client Project Time Report" +msgstr "Klient Projekt Raport czasowy" + +msgid "Download Payslips" +msgstr "Pobierz paski wypÅ‚at pensji" + +msgid "Leaves Report" +msgstr "Raport pozostawia" + +msgid "Time Entry Report" +msgstr "Czas ZgÅ‚oÅ› Entry" + +msgid "Time Sheet Report" +msgstr "Czas Sheet Report" + +msgid "Time Tracking Report" +msgstr "Time Tracking Report" + +msgid "Data" +msgstr "Dane" + +msgid "Processed" +msgstr "Obrobiony" + +msgid "Not Processed" +msgstr "Nieprzetworzony" + +msgid "Elementary Proficiency" +msgstr "Podstawowa znajomość" + +msgid "Limited Working Proficiency" +msgstr "Ograniczona wydajność pracy" + +msgid "Professional Working Proficiency" +msgstr "Profesjonalna biegÅ‚ość w pracy" + +msgid "Full Professional Proficiency" +msgstr "PeÅ‚na biegÅ‚ość zawodowa" + +msgid "Native or Bilingual Proficiency" +msgstr "JÄ™zyk ojczysty lub biegÅ‚ość dwujÄ™zyczna" + +msgid "Pending" +msgstr "W oczekiwaniu" + +msgid "Approved" +msgstr "Zatwierdzony" + +msgid "Rejected" +msgstr "odrzucony" + +msgid "Cancelled" +msgstr "Anulowany" + +msgid "Continue" +msgstr "dalej" + +msgid "Cancellation Requested" +msgstr "Rezygnacja Zamówiony" + +msgid "Completed" +msgstr "ZakoÅ„czony" + +msgid "Discussions" +msgstr "dyskusje" + +msgid "Load More" +msgstr "ZaÅ‚aduj wiÄ™cej" + +msgid "Show More" +msgstr "Pokaż wiÄ™cej" + +msgid "Show Less" +msgstr "Pokaż mniej" + +msgid "Publish" +msgstr "Publikować" + +msgid "Announcements" +msgstr "OgÅ‚oszenia" + +msgid "Send" +msgstr "WysÅ‚ać" + +msgid "Display" +msgstr "Pokaz" + +msgid "Public" +msgstr "Publiczny" + +msgid "View Announcements" +msgstr "Zobacz ogÅ‚oszenia" + +msgid "Conversations" +msgstr "rozmowy" + +msgid "Start Now" +msgstr "Zacząć teraz" diff --git a/core/lang/zh.po b/core/lang/zh.po index 360c1f2d..8596be8a 100644 --- a/core/lang/zh.po +++ b/core/lang/zh.po @@ -18,10 +18,10 @@ msgid "Cancel" msgstr "å–æ¶ˆ" msgid "Done" -msgstr "åš" +msgstr "完æˆ" msgid "Clocked In Employees" -msgstr "主频在员工" +msgstr "打å¡å‘˜å·¥" msgid "Candidates" msgstr "候选人" @@ -33,34 +33,34 @@ msgid "Add a New Employee" msgstr "添加新员工" msgid "Leave Calendar" -msgstr "离开日历" +msgstr "休凿—¥åކ" msgid "Manage Client/Projects" -msgstr "管ç†å®¢æˆ·ç«¯/项目" +msgstr "管ç†å®¢æˆ·/项目" msgid "Home" -msgstr "å®¶" +msgstr "主页" msgid "Quick Access" msgstr "快速访问" msgid "Switch" -msgstr "开关" +msgstr "角色切æ¢" msgid "Profile" -msgstr "轮廓" +msgstr "档案" msgid "Sign out" msgstr "退出" msgid "Help" -msgstr "帮帮我" +msgstr "帮助" msgid "About" msgstr "关于" msgid "Version" -msgstr "版" +msgstr "版本" msgid "Release Date" msgstr "å‘布日期" @@ -69,7 +69,7 @@ msgid "Logged In" msgstr "登录" msgid "Admin" -msgstr "è”ç³»" +msgstr "管ç†å‘˜" msgid "Dashboard" msgstr "仪表æ¿" @@ -78,7 +78,7 @@ msgid "Company Structure" msgstr "å…¬å¸ç»“æž„" msgid "Job Details Setup" -msgstr "æ‹›è˜ä¿¡æ¯çš„设定" +msgstr "æ‹›è˜ä¿¡æ¯è®¾ç½®" msgid "Qualifications Setup" msgstr "资格设置" @@ -87,10 +87,10 @@ msgid "Training Setup" msgstr "培训设置" msgid "Projects/Client Setup" -msgstr "项目/客户端安装" +msgstr "项目/客户设置" msgid "Leave Settings" -msgstr "离开设置" +msgstr "休å‡è®¾ç½®" msgid "Company Loans" msgstr "å…¬å¸è´·æ¬¾" @@ -99,7 +99,7 @@ msgid "Audit Log" msgstr "审计日志" msgid "Employees" -msgstr "雇员" +msgstr "员工" msgid "Employee History" msgstr "员工历å²" @@ -108,7 +108,7 @@ msgid "Document Management" msgstr "文档管ç†" msgid "Travel Administration" -msgstr "旅游管ç†" +msgstr "差旅管ç†" msgid "Expense Administration" msgstr "费用管ç†" @@ -117,7 +117,7 @@ msgid "Monitor Attendance" msgstr "监控考勤" msgid "Performance Charts" -msgstr "性能图表" +msgstr "绩效图表" msgid "Overtime Administration" msgstr "加ç­ç®¡ç†" @@ -129,7 +129,7 @@ msgid "Reports" msgstr "报告" msgid "Report Files" -msgstr "报告文件" +msgstr "报告文档" msgid "System" msgstr "系统" @@ -183,16 +183,16 @@ msgid "Qualifications" msgstr "资格" msgid "Dependents" -msgstr "眷" +msgstr "供养关系" msgid "Emergency Contacts" -msgstr "紧急è”络" +msgstr "紧急è”络人" msgid "Leave" -msgstr "离开" +msgstr "休å‡" msgid "Leave Management" -msgstr "离开管ç†" +msgstr "休å‡ç®¡ç†" msgid "Time Management" msgstr "时间管ç†" @@ -201,43 +201,43 @@ msgid "Projects" msgstr "项目" msgid "Attendance" -msgstr "护ç†" +msgstr "出勤" msgid "Time Sheets" -msgstr "考勤表" +msgstr "工时表" msgid "Attendance Sheets" -msgstr "签到表" +msgstr "出勤表" msgid "Overtime Requests" -msgstr "加ç­çš„请求" +msgstr "加ç­ç”³è¯·" msgid "Documents" -msgstr "文件" +msgstr "文档" msgid "My Documents" -msgstr "我的文件" +msgstr "我的文档" msgid "Company" msgstr "å…¬å¸" msgid "Staff Directory" -msgstr "æ•™èŒå‘˜å录" +msgstr "员工å录" msgid "Training" -msgstr "训练" +msgstr "培训" msgid "Travel Management" -msgstr "旅游管ç†" +msgstr "差旅管ç†" msgid "Travel" -msgstr "旅行" +msgstr "差旅" msgid "Finance" msgstr "金èž" msgid "Expenses" -msgstr "花费" +msgstr "费用" msgid "Loans" msgstr "贷款" @@ -246,7 +246,7 @@ msgid "User Reports" msgstr "用户报告" msgid "People" -msgstr "人" +msgstr "人员" msgid "Manage" msgstr "管ç†" @@ -261,7 +261,7 @@ msgid "Update Clients/Projects" msgstr "更新客户端/项目" msgid "Entries Last Week" -msgstr "æ¡ç›®ä¸Šå‘¨" +msgstr "上周æ¡ç›®" msgid "Upcoming" msgstr "å³å°†åˆ°æ¥" @@ -282,22 +282,22 @@ msgid "Applicants" msgstr "申请人" msgid "Active Jobs" -msgstr "活动作业" +msgstr "在招èŒä½" msgid "Jobs Posted" -msgstr "乔布斯å‘布" +msgstr "èŒä½å‘布" msgid "Jobs" -msgstr "工作" +msgstr "èŒä½" msgid "Courses" -msgstr "培训ç­" +msgstr "课程" msgid "Requests" -msgstr "è¦æ±‚" +msgstr "申请" msgid "Document" -msgstr "文件" +msgstr "文档" msgid "Management" msgstr "管ç†" @@ -306,7 +306,7 @@ msgid "Expense" msgstr "费用" msgid "Permission" -msgstr "å…许" +msgstr "æƒé™" msgid "Permissions" msgstr "æƒé™" @@ -321,7 +321,7 @@ msgid "Make a Payment" msgstr "进行付款" msgid "Switch Employee" -msgstr "开关员工" +msgstr "切æ¢å‘˜å·¥" msgid "Select The Employee to Switch Into" msgstr "选择切æ¢åˆ°å‘˜å·¥" @@ -330,7 +330,7 @@ msgid "Close" msgstr "å…³" msgid "My Profile" -msgstr "我的简历" +msgstr "我的档案" msgid "Edit Details" msgstr "编辑详情" @@ -342,25 +342,25 @@ msgid "Punch In" msgstr "切入" msgid "or" -msgstr "è¦ä¹ˆ" +msgstr "或者" msgid "Punch Out" msgstr "切出" msgid "Record Attendance" -msgstr "出席记录" +msgstr "出勤记录" msgid "Pending Leaves" -msgstr "å¾…å¶" +msgstr "待处ç†çš„休å‡" msgid "Check Leave Status" msgstr "检查休å‡çжæ€" msgid "Hours worked Last Week" -msgstr "工作时间上周" +msgstr "上周工作时长" msgid "Update Time Sheet" -msgstr "更新时间表" +msgstr "更新工时表" msgid "My Projects" msgstr "我的项目" @@ -375,7 +375,7 @@ msgid "Store" msgstr "商店" msgid "My Travel" -msgstr "我的旅行" +msgstr "我的差旅" msgid "My Expenses" msgstr "我的费用" @@ -402,7 +402,7 @@ msgid "Time Zone" msgstr "时区" msgid "Parent Structure" -msgstr "æ¯ä½“结构" +msgstr "父结构" msgid "Details" msgstr "细节" @@ -411,10 +411,10 @@ msgid "Heads" msgstr "头" msgid "Code" -msgstr "ç " +msgstr "ç¼–ç " msgid "Job Title Code" -msgstr "èŒä½ä»£ç " +msgstr "èŒä½ç¼–ç " msgid "Job Title" msgstr "èŒç§°" @@ -429,7 +429,7 @@ msgid "Currency" msgstr "è´§å¸" msgid "Min Salary" -msgstr "闵工资" +msgstr "最低工资" msgid "Max Salary" msgstr "最高工资" @@ -438,16 +438,16 @@ msgid "Pay Grade Name" msgstr "工资等级åç§°" msgid "Employment Status" -msgstr "就业状况" +msgstr "就业状æ€" msgid "Coordinator" -msgstr "å调员" +msgstr "组织者" msgid "Trainer" -msgstr "训练者" +msgstr "培训师" msgid "Trainer Details" -msgstr "培训师详细" +msgstr "培训师详细信æ¯" msgid "Payment Type" msgstr "付款方å¼" @@ -465,7 +465,7 @@ msgid "Scheduled Time" msgstr "计划的时间" msgid "Assignment Due Date" -msgstr "交作业的日期" +msgstr "交付的日期" msgid "Delivery Method" msgstr "è¿è¾“æ–¹å¼" @@ -483,7 +483,7 @@ msgid "Training Certificate Required" msgstr "培训è¯ä¹¦è¦æ±‚" msgid "Employee" -msgstr "雇员" +msgstr "员工" msgid "Training Session" msgstr "培训课程" @@ -507,58 +507,58 @@ msgid "Project" msgstr "项目" msgid "Leave Name" -msgstr "留下姓å" +msgstr "休å‡åç§°" msgid "Leave Accrue Enabled" -msgstr "离开计æå¯ç”¨" +msgstr "休å‡è®¡æ" msgid "Leave Carried Forward" -msgstr "离开结转" +msgstr "休å‡ç»“转" msgid "Leaves Per Year" -msgstr "å¶æ¯å¹´" +msgstr "凿œŸ/å¹´" msgid "Leaves Group" -msgstr "å¶ç»„" +msgstr "休å‡ç»„" msgid "Leaves Per Leave Period" -msgstr "å¶æ¯ä¼‘凿œŸé—´" +msgstr "休å‡/休凿—¶æ®µ" msgid "Admin can assign leave to employees" -msgstr "管ç†å‘˜å¯ä»¥æŒ‡å®šä¼‘å‡çš„员工" +msgstr "管ç†å‘˜å¯ä»¥ä¸ºå‘˜å·¥åˆ†é…休å‡" msgid "Employees can apply for this leave type" -msgstr "员工å¯ä»¥ç”³è¯·è¿™ä¸ªå‡æœŸç±»åž‹" +msgstr "员工å¯ä»¥ç”³è¯·è¿™ä¸ªä¼‘å‡ç±»åž‹" msgid "Employees can apply beyond the current leave balance" -msgstr "员工å¯ä»¥ç”³è¯·è¶…出了目å‰çš„平衡休å‡" +msgstr "员工å¯ä»¥ç”³è¯·è¶…é¢ä¼‘å‡" msgid "Percentage of Leaves Carried Forward" -msgstr "å¶ç™¾åˆ†æ¯”推进型" +msgstr "æµè½¬çš„休å‡ç™¾åˆ†æ¯”" msgid "Maximum Carried Forward Amount" msgstr "最大结转金é¢" msgid "Carried Forward Leave Availability Period" -msgstr "ç»“è½¬ä¼‘å‡æœŸå¯ç”¨æ€§" +msgstr "Periodo di Riporto Permessi Disponibili" msgid "Proportionate leaves on Joined Date" -msgstr "å¶æˆæ¯”例的注册日期" +msgstr "已分é…凿œŸ" msgid "Send Notification Emails" msgstr "å‘é€ç”µâ€‹â€‹å­é‚®ä»¶é€šçŸ¥" msgid "Leave Group" -msgstr "离开组" +msgstr "休å‡ç»„" msgid "Leave Color" -msgstr "离开颜色" +msgstr "休å‡é¢œè‰²" msgid "Period Start" msgstr "周期开始" msgid "Period End" -msgstr "期末" +msgstr "周期结æŸ" msgid "Day" msgstr "天" @@ -573,19 +573,19 @@ msgid "Leave Type" msgstr "休å‡ç±»åž‹" msgid "Propotionate leaves on Joined Date" -msgstr "Propotionateå¶æ³¨å†Œæ—¥æœŸ" +msgstr "已分é…凿œŸ" msgid "Leaves Period" -msgstr "å¶æœŸ" +msgstr "休凿—¶æ®µ" msgid "Leave Amount" -msgstr "离开金é¢" +msgstr "休凿€»é‡" msgid "Leave Period" -msgstr "休凿œŸé—´" +msgstr "休凿—¶æ®µ" msgid "Note" -msgstr "注æ„" +msgstr "说明" msgid "All Employees" msgstr "所有员工" @@ -603,7 +603,7 @@ msgid "Loan Period (Months)" msgstr "贷款期é™ï¼ˆæœˆï¼‰" msgid "Amount" -msgstr "é‡" +msgstr "总é‡" msgid "Last Installment Date" msgstr "最åŽåˆ†æœŸä»˜æ¬¾æ—¥æœŸ" @@ -624,7 +624,7 @@ msgid "Middle Name" msgstr "中间åå­—" msgid "Last Name" -msgstr "å§“" +msgstr "å§“æ°" msgid "Nationality" msgstr "国ç±" @@ -654,7 +654,7 @@ msgid "Other ID" msgstr "å…¶ä»–ID" msgid "Driving License No" -msgstr "驾驶执照无" +msgstr "驾照编å·" msgid "Pay Grade" msgstr "工资等级" @@ -663,7 +663,7 @@ msgid "Work Station Id" msgstr "工作站标识" msgid "Address Line 1" -msgstr "åœ°å€æ 1" +msgstr "地å€è¡Œ1" msgid "Address Line 2" msgstr "地å€è¡Œ2" @@ -675,7 +675,7 @@ msgid "Province" msgstr "çœ" msgid "Postal/Zip Code" -msgstr "邮政/邮编" +msgstr "邮编" msgid "Home Phone" msgstr "家庭电è¯" @@ -702,25 +702,25 @@ msgid "Termination Date" msgstr "终止日期" msgid "Department" -msgstr "部" +msgstr "部门" msgid "Supervisor" -msgstr "监" +msgstr "主管" msgid "Indirect Supervisors" -msgstr "间接监事" +msgstr "间接主管" msgid "First Level Approver" msgstr "第一级审批" msgid "Second Level Approver" -msgstr "二级审批" +msgstr "第二级审批" msgid "Third Level Approver" msgstr "第三级审批" msgid "Notes" -msgstr "笔记" +msgstr "说明" msgid "Time (GMT)" msgstr "时间(GMT)" @@ -732,13 +732,13 @@ msgid "IP Address" msgstr "IP地å€" msgid "Logged In Employee" -msgstr "记录在员工" +msgstr "登录的员工" msgid "Skill" msgstr "技能" msgid "Qualification" -msgstr "åˆæ ¼" +msgstr "资格" msgid "Institute" msgstr "研究所" @@ -762,10 +762,10 @@ msgid "Language" msgstr "语言" msgid "Reading" -msgstr "读" +msgstr "阅读" msgid "Speaking" -msgstr "请讲" +msgstr "å£è¯­" msgid "Writing" msgstr "写作" @@ -789,7 +789,7 @@ msgid "All Job Titles" msgstr "所有èŒä½åç§°" msgid "All Departments" -msgstr "所有" +msgstr "所有部门" msgid "Anyone" msgstr "任何人" @@ -801,7 +801,7 @@ msgid "Old Value" msgstr "旧值" msgid "New Value" -msgstr "新价值" +msgstr "新值" msgid "Modified By" msgstr "修改者" @@ -822,13 +822,13 @@ msgid "Notify Expiry Before One Day" msgstr "通知到期的å‰ä¸€å¤©" msgid "Travel Type" -msgstr "旅游方å¼" +msgstr "差旅方å¼" msgid "Purpose of Travel" -msgstr "旅行的目的" +msgstr "差旅的目的" msgid "Travel From" -msgstr "从旅游" +msgstr "从" msgid "Travel To" msgstr "å‰å¾€" @@ -867,13 +867,13 @@ msgid "Receipt" msgstr "æ”¶æ®" msgid "Time-In" -msgstr "时间在" +msgstr "ä¸Šç­æ‰“å¡" msgid "Time-Out" -msgstr "æš‚åœ" +msgstr "ä¸‹ç­æ‰“å¡" msgid "Clocked In Status" -msgstr "主频在状æ€" +msgstr "打å¡çжæ€" msgid "End Date" msgstr "ç»“æŸæ—¥æœŸ" @@ -885,13 +885,13 @@ msgid "Start Time" msgstr "开始时间" msgid "End Time" -msgstr "时间结æŸ" +msgstr "ç»“æŸæ—¶é—´" msgid "Leave Status" -msgstr "离开状æ€" +msgstr "休å‡çжæ€" msgid "Select Client" -msgstr "选择客户端" +msgstr "选择客户" msgid "Not Selected" msgstr "未选择" @@ -909,7 +909,7 @@ msgid "Value" msgstr "值" msgid "Logo" -msgstr "商标" +msgstr "图标" msgid "User Name" msgstr "用户å" @@ -960,7 +960,7 @@ msgid "Invoice Period Start" msgstr "å‘票周期开始" msgid "Invoice Period End" -msgstr "å‘票期末" +msgstr "å‘票周期结æŸ" msgid "Due date" msgstr "截止日期" @@ -990,7 +990,7 @@ msgid "Field Options" msgstr "域选项" msgid "Priority" -msgstr "优先" +msgstr "优先级" msgid "Display Section" msgstr "显示部分" @@ -1002,10 +1002,10 @@ msgid "Salary Component" msgstr "薪金部分" msgid "Pay Frequency" -msgstr "收费频率" +msgstr "付款频率" msgid "Calculation Group" -msgstr "计算集团" +msgstr "计算群组" msgid "None" msgstr "没有" @@ -1044,10 +1044,10 @@ msgid "Salary Components" msgstr "工资组件" msgid "Columns to Add" -msgstr "列添加" +msgstr "添加列" msgid "Columns to Subtract" -msgstr "列å‡åŽ»" +msgstr "å‡åŽ»åˆ—" msgid "Column Order" msgstr "列顺åº" @@ -1068,7 +1068,7 @@ msgid "Calculation Process" msgstr "计算过程" msgid "Payslip Fields" -msgstr "工资å•场" +msgstr "工资å•字段" msgid "Payroll Column" msgstr "工资列" @@ -1089,19 +1089,19 @@ msgid "Upper Limit" msgstr "上é™" msgid "Column" -msgstr "柱" +msgstr "列" msgid "Job Code" msgstr "èŒä½ä»£ç " msgid "Short Description" -msgstr "简短的介ç»" +msgstr "简短介ç»" msgid "Requirements" -msgstr "è¦æ±‚" +msgstr "申请" msgid "Benefits" -msgstr "优点" +msgstr "收益" msgid "Employment Type" msgstr "雇佣类型" @@ -1125,16 +1125,16 @@ msgid "Education Level" msgstr "教育程度" msgid "Any Education Level" -msgstr "任何教育水平" +msgstr "任何教育程度" msgid "Show Salary" msgstr "显示工资" msgid "Salary Min" -msgstr "工资æ•" +msgstr "最低工资" msgid "Salary Max" -msgstr "工资最高" +msgstr "最高工资" msgid "Keywords" msgstr "关键è¯" @@ -1164,7 +1164,7 @@ msgid "Resume Headline" msgstr "简历标题" msgid "Profile Summary" -msgstr "æ¦‚è¦æ–‡ä»¶æ‘˜è¦" +msgstr "文件摘è¦" msgid "Work History" msgstr "工作ç»åކ" @@ -1176,7 +1176,7 @@ msgid "Skills" msgstr "技能" msgid "Referees" -msgstr "è£åˆ¤" +msgstr "推è人" msgid "From Year" msgstr "从新年" @@ -1188,7 +1188,7 @@ msgid "To Year" msgstr "至年" msgid "To Month" -msgstr "为月" +msgstr "至月" msgid "Currently Work Here" msgstr "现在在这里工作" @@ -1203,10 +1203,10 @@ msgid "Skill Level" msgstr "技能等级" msgid "Last Used Year" -msgstr "去年二手年份" +msgstr "上一过去年份" msgid "Last Used Month" -msgstr "上次使用一个月" +msgstr "上一过去月份" msgid "Years of Experience" msgstr "多年ç»éªŒ" @@ -1224,31 +1224,31 @@ msgid "Candidate" msgstr "候选人" msgid "Referred By" -msgstr "ç”±......推è" +msgstr "推è自" msgid "Leave Start Date" -msgstr "离开开始日期" +msgstr "休å‡å¼€å§‹æ—¥æœŸ" msgid "Leave End Date" -msgstr "ç¦»å¼€ç»“æŸæ—¥æœŸ" +msgstr "休å‡ç»“æŸæ—¥æœŸ" msgid "Reason" msgstr "原因" msgid "Available Leaves" -msgstr "å¶å¯ç”¨" +msgstr "å¯ç”¨ä¼‘å‡" msgid "Approved Leaves" -msgstr "å¶æ‰¹å‡†" +msgstr "批准的休å‡" msgid "Rejected Leaves" -msgstr "å¶è¢«æ‹’ç»" +msgstr "æ‹’ç»çš„休å‡" msgid "Leaves to be Accrued" -msgstr "å¶è®¡å…¥" +msgstr "计入的休å‡" msgid "Leaves Carried Forward" -msgstr "å¶ç»“转" +msgstr "结转的休å‡" msgid "Apply Leave" msgstr "申请休å‡" @@ -1257,13 +1257,13 @@ msgid "Filter" msgstr "过滤" msgid "Add New" -msgstr "添新" +msgstr "添加" msgid "Time" msgstr "æ—¶é—´" msgid "Purpose" -msgstr "目的" +msgstr "Scopo" msgid "From" msgstr "从" @@ -1284,19 +1284,19 @@ msgid "Upload" msgstr "上传" msgid "Remove" -msgstr "去掉" +msgstr "删除" msgid "Add" -msgstr "加" +msgstr "添加" msgid "Reset" msgstr "é‡å¯" msgid "Add Time Entry" -msgstr "添加时间输入" +msgstr "添加时间æ¡ç›®" msgid "Current Clocked In Status" -msgstr "ç›®å‰ç§»å…¥çжæ€" +msgstr "ç›®å‰æ‰“å¡çжæ€" msgid "Attendance entry should be within a single day" msgstr "出席æ¡ç›®åº”在一天内" @@ -1317,25 +1317,25 @@ msgid "Attendance Graph" msgstr "考勤图" msgid "Hours in Office vs Hours Worked Graph" -msgstr "å°æ—¶åœ¨åŠžå…¬å®¤VS工时图" +msgstr "办公室时长和工作时长图" msgid "Company Graph" -msgstr "å…¬å¸å›¾" +msgstr "å…¬å¸ç»“构图" msgid "Company Documents" -msgstr "公叿–‡ä»¶" +msgstr "公叿–‡æ¡£" msgid "Document Types" msgstr "文档类型" msgid "Employee Documents" -msgstr "员工的文档" +msgstr "员工文档" msgid "Employee Basic Details" -msgstr "èŒå·¥åŸºæœ¬ç»†èŠ‚" +msgstr "员工基本信æ¯" msgid "Employees (Direct Reports)" -msgstr "员工(直接报告)" +msgstr "员工(直接汇报)" msgid "Certifications" msgstr "认è¯" @@ -1344,10 +1344,10 @@ msgid "Languages" msgstr "语言" msgid "Deactivated Employees" -msgstr "åœç”¨å‘˜å·¥" +msgstr "离èŒå‘˜å·¥" msgid "Temporarily Deactivated Employees" -msgstr "临时ç¦ç”¨å‘˜å·¥" +msgstr "临时离èŒå‘˜å·¥" msgid "Terminated Employee Data" msgstr "离èŒå‘˜å·¥èµ„æ–™" @@ -1356,10 +1356,10 @@ msgid "Employee Saved Successfully" msgstr "员工æˆåŠŸä¿å­˜" msgid "Employee needs a User to login to IceHrm. Do you want to create a user for this employee now?" -msgstr "员工需è¦ç”¨æˆ·ç™»å½•到IceHrm。你想创建现在这个员工的用户?" +msgstr "aby zalogować siÄ™ IceHrm. Czy chcesz utworzyć użytkownika dla tego pracownika teraz?\"" msgid "You can do this later through Users module if required." -msgstr "如果需è¦ï¼Œå¯ä»¥é€šè¿‡ç”¨æˆ·æ¨¡å—åŽåšåˆ°è¿™ä¸€ç‚¹ã€‚" +msgstr "à travers le module des utilisateurs si nécessaire.\"" msgid "Expenses Categories" msgstr "费用分类" @@ -1401,7 +1401,7 @@ msgid "Edit Education Levels" msgstr "编辑教育程度" msgid "Edit Benefits" -msgstr "编辑好处" +msgstr "编辑收益" msgid "Application" msgstr "应用" @@ -1425,7 +1425,7 @@ msgid "Employee Projects" msgstr "员工项目" msgid "Leave Types" -msgstr "离开类型" +msgstr "休å‡ç±»åž‹" msgid "Work Week" msgstr "工作周" @@ -1434,19 +1434,19 @@ msgid "Holidays" msgstr "凿œŸ" msgid "Leave Rules" -msgstr "离开规则" +msgstr "休å‡è§„则" msgid "Paid Time Off" msgstr "带薪休å‡" msgid "Leave Groups" -msgstr "离开组" +msgstr "休å‡ç»„" msgid "Edit Leave Groups" msgstr "编辑休å‡ç»„" msgid "Leave Group Employees" -msgstr "离开集团的员工" +msgstr "休å‡ç»„的员工" msgid "Employee Leave List" msgstr "员工休å‡åå•" @@ -1458,13 +1458,13 @@ msgid "Employee Loans" msgstr "员工贷款" msgid "Travel Requests" -msgstr "差旅请求" +msgstr "差旅申请" msgid "Overtime Categories" msgstr "加ç­åˆ†ç±»" msgid "Leave / PTO" -msgstr "离开/ PTO" +msgstr "ä¼‘å‡ / PTO" msgid "Other" msgstr "å…¶ä»–" @@ -1491,52 +1491,52 @@ msgid "My Details" msgstr "我的详细资料" msgid "All My Leaves" -msgstr "我所有的树å¶" +msgstr "我所有的休å‡" msgid "Leave Entitlement" -msgstr "休凿ƒåˆ©" +msgstr "应休休å‡" msgid "Approved Leave" -msgstr "批准休å‡" +msgstr "批准的休å‡" msgid "Pending Leave" -msgstr "待离开" +msgstr "待处ç†çš„休å‡" msgid "Subordinate Leave" msgstr "下属休å‡" msgid "Cancellation Requests" -msgstr "å–æ¶ˆè¯·æ±‚" +msgstr "å–æ¶ˆç”³è¯·" msgid "Approval Requests" -msgstr "批准请求" +msgstr "批准申请" msgid "Approved TimeSheets" -msgstr "批准称TimeSheets" +msgstr "批准的工时表" msgid "All My TimeSheets" -msgstr "所有我的时间表" +msgstr "所有我的工时表" msgid "Pending TimeSheets" -msgstr "待定称TimeSheets" +msgstr "待处ç†çš„工时表" msgid "Subordinate TimeSheets" -msgstr "下属称TimeSheets" +msgstr "下属工时表" msgid "Approved Attendance Sheets" -msgstr "批准签到表" +msgstr "已批准的考勤表" msgid "All My Attendance Sheets" msgstr "我所有的考勤表" msgid "Pending Attendance Sheets" -msgstr "待签到表" +msgstr "待批准的考勤表" msgid "Subordinate Attendance Sheets" -msgstr "下属签到表" +msgstr "下属考勤表" msgid "Subordinate Overtime Requests" -msgstr "下属加ç­è¯·æ±‚" +msgstr "下属加ç­ç”³è¯·" msgid "Overtime Request Approval" msgstr "加ç­ç”³è¯·å®¡æ‰¹" @@ -1551,49 +1551,355 @@ msgid "Training Sessions of Direct Reports" msgstr "直接下属的培训课程" msgid "Subordinate Travel Requests" -msgstr "下属差旅请求" +msgstr "下属差旅申请" msgid "Travel Request Approval" -msgstr "旅行请求审批" +msgstr "旅行申请审批" msgid "Subordinate Expenses" msgstr "下属费用" msgid "Expenses Approval" -msgstr "支出审批" +msgstr "费用审批" msgid "Loans Taken" -msgstr "采å–贷款" +msgstr "已获得贷款" msgid "Change Leave Status" msgstr "更改休å‡çжæ€" msgid "Status Change Note" -msgstr "çŠ¶æ€æ›´æ”¹æ³¨" +msgstr "çŠ¶æ€æ›´æ”¹è¯´æ˜Ž" msgid "Leave Summary" -msgstr "离开摘è¦" +msgstr "休凿‘˜è¦" msgid "Approved Leave Count" msgstr "批准休å‡è®¡æ•°" msgid "Pending Leave Count" -msgstr "待离开计数" +msgstr "待处ç†ä¼‘å‡è®¡æ•°" msgid "Available Leave Count" -msgstr "å¯ç”¨è®¡æ•°ä¼‘å‡" +msgstr "å¯ç”¨ä¼‘å‡è®¡æ•°" msgid "Leave Dates" -msgstr "离开日期" +msgstr "休å‡å¤©æ•°" msgid "Leave Date" -msgstr "离开日期" +msgstr "休凿—¥æœŸ" msgid "Leave Notes" -msgstr "留便æ¡" +msgstr "休å‡è¯´æ˜Ž" msgid "Apply" msgstr "应用" msgid "Back" -msgstr "背部" +msgstr "返回" + +msgid "Hours in Time Sheets" +msgstr "åœ¨è€ƒå‹¤è¡¨å°æ—¶" + +msgid "HR form" +msgstr "人力资æºè¡¨æ ¼" + +msgid "HR Form Management" +msgstr "人力资æºè¡¨æ ¼ç®¡ç†" + +msgid "Form Name" +msgstr "表格åç§°" + +msgid "Fields" +msgstr "字段" + +msgid "Employee Froms" +msgstr "员工栌" + +msgid "Share Departments" +msgstr "共享部门" + +msgid "Share Employees" +msgstr "共享员工" + +msgid "Data Importers" +msgstr "æ•°æ®å¯¼å…¥å™¨" + +msgid "Data Import Files" +msgstr "æ•°æ®å¯¼å…¥æ–‡ä»¶" + +msgid "Data Type" +msgstr "æ•°æ®ç±»åž‹" + +msgid "Columns" +msgstr "列" + +msgid "Field Title" +msgstr "字段标题" + +msgid "Depends On" +msgstr "ä¾èµ–于" + +msgid "Depends On Field" +msgstr "å–决于现场" + +msgid "is Key Field" +msgstr "键值字段" + +msgid "is ID Field" +msgstr "ID字段" + +msgid "Data Import Definitions" +msgstr "æ•°æ®å¯¼å…¥å®šä¹‰" + +msgid "File to Import" +msgstr "è¦å¯¼å…¥çš„æ–‡ä»¶" + +msgid "Last Export Results" +msgstr "最åŽå¯¼å‡ºç»“æžœ" + +msgid "Time and Attendance" +msgstr "工时和出勤" + +msgid "Leave Timeline" +msgstr "休凿—¶é—´è½´" + +msgid "Insights" +msgstr "时长分æž" + +msgid "Api Access" +msgstr "API访问" + +msgid "Change User Password" +msgstr "更改用户密ç " + +msgid "New Password" +msgstr "新密ç " + +msgid "Confirm Password" +msgstr "确认密ç " + +msgid "Change Password" +msgstr "更改密ç " + +msgid "Not Now" +msgstr "䏿˜¯çŽ°åœ¨" + +msgid "Contact Information" +msgstr "è”系信æ¯" + +msgid "Job Details" +msgstr "æ‹›è˜è¯¦æƒ…" + +msgid "Edit Info" +msgstr "编辑信æ¯" + +msgid "Upload Profile Image" +msgstr "上传简介的图片" + +msgid "Delete Profile Image" +msgstr "删除个人资料图片" + +msgid "Direct Reports" +msgstr "直接报告" + +msgid "Other Details" +msgstr "其他详情" + +msgid "Family" +msgstr "家庭" + +msgid "Custom Fields" +msgstr "自定义字段" + +msgid "Means of Transportation" +msgstr "交通方å¼" + +msgid "Plane" +msgstr "å¹³é¢" + +msgid "Rail" +msgstr "轨" + +msgid "Taxi" +msgstr "出租车" + +msgid "Own Vehicle" +msgstr "车辆" + +msgid "Rented Vehicle" +msgstr "租用的车辆" + +msgid "Female" +msgstr "女" + +msgid "Male" +msgstr "ç”·" + +msgid "Active" +msgstr "活性" + +msgid "Inactive" +msgstr "待用" + +msgid "Draft" +msgstr "è‰æ¡ˆ" + +msgid "Not Clocked In" +msgstr "没有时钟在" + +msgid "Clocked In" +msgstr "移入" + +msgid "File" +msgstr "文件" + +msgid "Active Employee Report" +msgstr "ç§¯æžæ´»è·ƒçš„员工报告" + +msgid "Employee Attendance Report" +msgstr "员工考勤报表" + +msgid "Employee Details Report" +msgstr "å‘˜å·¥è¯¦ç»†ä¿¡æ¯æŠ¥å‘Š" + +msgid "Employee Leave Entitlement" +msgstr "å‘˜å·¥ä¼‘å‡æƒåˆ©" + +msgid "Employee Leaves Report" +msgstr "员工离开报告" + +msgid "Employee Time Entry Report" +msgstr "员工的时间记录报告" + +msgid "Employee Time Sheet Report" +msgstr "员工时间表报告" + +msgid "Employee Time Tracking Report" +msgstr "员工时间跟踪报告" + +msgid "Expense Report" +msgstr "开支报告" + +msgid "New Hires Employee Report" +msgstr "新员工员工报告" + +msgid "Overtime Report" +msgstr "åŠ ç­æŠ¥å‘Š" + +msgid "Overtime Request Report" +msgstr "加ç­è¯·æ±‚报告" + +msgid "Overtime Summary Report" +msgstr "åŠ ç­æ€»ç»“报告" + +msgid "Payroll Meta Data Export" +msgstr "薪资元数æ®å¯¼å‡º" + +msgid "Terminated Employee Report" +msgstr "离èŒå‘˜å·¥æŠ¥å‘Š" + +msgid "Travel Request Report" +msgstr "旅行请求报告" + +msgid "Attendance Report" +msgstr "出席报告" + +msgid "Client Project Time Report" +msgstr "客户项目时间报告" + +msgid "Download Payslips" +msgstr "下载工资å•" + +msgid "Leaves Report" +msgstr "å¶æŠ¥å‘Š" + +msgid "Time Entry Report" +msgstr "时间记录报告" + +msgid "Time Sheet Report" +msgstr "时间表报告" + +msgid "Time Tracking Report" +msgstr "时间跟踪报告" + +msgid "Data" +msgstr "æ•°æ®" + +msgid "Processed" +msgstr "处ç†" + +msgid "Not Processed" +msgstr "ä¸å¤„ç†" + +msgid "Elementary Proficiency" +msgstr "基础熟练程度" + +msgid "Limited Working Proficiency" +msgstr "有é™çš„工作能力" + +msgid "Professional Working Proficiency" +msgstr "专业工作能力" + +msgid "Full Professional Proficiency" +msgstr "全程专业能力" + +msgid "Native or Bilingual Proficiency" +msgstr "æ¯è¯­æˆ–åŒè¯­ç†Ÿç»ƒç¨‹åº¦" + +msgid "Pending" +msgstr "有待" + +msgid "Approved" +msgstr "批准" + +msgid "Rejected" +msgstr "æ‹’ç»" + +msgid "Cancelled" +msgstr "å–æ¶ˆ" + +msgid "Continue" +msgstr "ç»§ç»­" + +msgid "Cancellation Requested" +msgstr "å–æ¶ˆè¯·æ±‚" + +msgid "Completed" +msgstr "已完æˆ" + +msgid "Discussions" +msgstr "讨论" + +msgid "Load More" +msgstr "装载更多" + +msgid "Show More" +msgstr "展示更多" + +msgid "Show Less" +msgstr "显示较少" + +msgid "Publish" +msgstr "å‘布" + +msgid "Announcements" +msgstr "通告" + +msgid "Send" +msgstr "å‘é€" + +msgid "Display" +msgstr "显示" + +msgid "Public" +msgstr "上市" + +msgid "View Announcements" +msgstr "查看公告" + +msgid "Conversations" +msgstr "对è¯" + +msgid "Start Now" +msgstr "现在开始" diff --git a/core/lib/Mail/RFC822.php b/core/lib/Mail/RFC822.php new file mode 100644 index 00000000..58d36465 --- /dev/null +++ b/core/lib/Mail/RFC822.php @@ -0,0 +1,951 @@ + + * @author Chuck Hagenbuch + * @author Chuck Hagenbuch + * @version $Revision: 294749 $ + * @license BSD + * @package Mail + */ +class Mail_RFC822 { + + /** + * The address being parsed by the RFC822 object. + * @var string $address + */ + var $address = ''; + + /** + * The default domain to use for unqualified addresses. + * @var string $default_domain + */ + var $default_domain = 'localhost'; + + /** + * Should we return a nested array showing groups, or flatten everything? + * @var boolean $nestGroups + */ + var $nestGroups = true; + + /** + * Whether or not to validate atoms for non-ascii characters. + * @var boolean $validate + */ + var $validate = true; + + /** + * The array of raw addresses built up as we parse. + * @var array $addresses + */ + var $addresses = array(); + + /** + * The final array of parsed address information that we build up. + * @var array $structure + */ + var $structure = array(); + + /** + * The current error message, if any. + * @var string $error + */ + var $error = null; + + /** + * An internal counter/pointer. + * @var integer $index + */ + var $index = null; + + /** + * The number of groups that have been found in the address list. + * @var integer $num_groups + * @access public + */ + var $num_groups = 0; + + /** + * A variable so that we can tell whether or not we're inside a + * Mail_RFC822 object. + * @var boolean $mailRFC822 + */ + var $mailRFC822 = true; + + /** + * A limit after which processing stops + * @var int $limit + */ + var $limit = null; + + /** + * Sets up the object. The address must either be set here or when + * calling parseAddressList(). One or the other. + * + * @access public + * @param string $address The address(es) to validate. + * @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost. + * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. + * @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. + * + * @return object Mail_RFC822 A new Mail_RFC822 object. + */ + function Mail_RFC822($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) + { + if (isset($address)) $this->address = $address; + if (isset($default_domain)) $this->default_domain = $default_domain; + if (isset($nest_groups)) $this->nestGroups = $nest_groups; + if (isset($validate)) $this->validate = $validate; + if (isset($limit)) $this->limit = $limit; + } + + /** + * Starts the whole process. The address must either be set here + * or when creating the object. One or the other. + * + * @access public + * @param string $address The address(es) to validate. + * @param string $default_domain Default domain/host etc. + * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. + * @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. + * + * @return array A structured array of addresses. + */ + function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) + { + if (!isset($this) || !isset($this->mailRFC822)) { + $obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit); + return $obj->parseAddressList(); + } + + if (isset($address)) $this->address = $address; + if (isset($default_domain)) $this->default_domain = $default_domain; + if (isset($nest_groups)) $this->nestGroups = $nest_groups; + if (isset($validate)) $this->validate = $validate; + if (isset($limit)) $this->limit = $limit; + + $this->structure = array(); + $this->addresses = array(); + $this->error = null; + $this->index = null; + + // Unfold any long lines in $this->address. + $this->address = preg_replace('/\r?\n/', "\r\n", $this->address); + $this->address = preg_replace('/\r\n(\t| )+/', ' ', $this->address); + + while ($this->address = $this->_splitAddresses($this->address)); + + if ($this->address === false || isset($this->error)) { + require_once 'PEAR.php'; + return PEAR::raiseError($this->error); + } + + // Validate each address individually. If we encounter an invalid + // address, stop iterating and return an error immediately. + foreach ($this->addresses as $address) { + $valid = $this->_validateAddress($address); + + if ($valid === false || isset($this->error)) { + require_once 'PEAR.php'; + return PEAR::raiseError($this->error); + } + + if (!$this->nestGroups) { + $this->structure = array_merge($this->structure, $valid); + } else { + $this->structure[] = $valid; + } + } + + return $this->structure; + } + + /** + * Splits an address into separate addresses. + * + * @access private + * @param string $address The addresses to split. + * @return boolean Success or failure. + */ + function _splitAddresses($address) + { + if (!empty($this->limit) && count($this->addresses) == $this->limit) { + return ''; + } + + if ($this->_isGroup($address) && !isset($this->error)) { + $split_char = ';'; + $is_group = true; + } elseif (!isset($this->error)) { + $split_char = ','; + $is_group = false; + } elseif (isset($this->error)) { + return false; + } + + // Split the string based on the above ten or so lines. + $parts = explode($split_char, $address); + $string = $this->_splitCheck($parts, $split_char); + + // If a group... + if ($is_group) { + // If $string does not contain a colon outside of + // brackets/quotes etc then something's fubar. + + // First check there's a colon at all: + if (strpos($string, ':') === false) { + $this->error = 'Invalid address: ' . $string; + return false; + } + + // Now check it's outside of brackets/quotes: + if (!$this->_splitCheck(explode(':', $string), ':')) { + return false; + } + + // We must have a group at this point, so increase the counter: + $this->num_groups++; + } + + // $string now contains the first full address/group. + // Add to the addresses array. + $this->addresses[] = array( + 'address' => trim($string), + 'group' => $is_group + ); + + // Remove the now stored address from the initial line, the +1 + // is to account for the explode character. + $address = trim(substr($address, strlen($string) + 1)); + + // If the next char is a comma and this was a group, then + // there are more addresses, otherwise, if there are any more + // chars, then there is another address. + if ($is_group && substr($address, 0, 1) == ','){ + $address = trim(substr($address, 1)); + return $address; + + } elseif (strlen($address) > 0) { + return $address; + + } else { + return ''; + } + + // If you got here then something's off + return false; + } + + /** + * Checks for a group at the start of the string. + * + * @access private + * @param string $address The address to check. + * @return boolean Whether or not there is a group at the start of the string. + */ + function _isGroup($address) + { + // First comma not in quotes, angles or escaped: + $parts = explode(',', $address); + $string = $this->_splitCheck($parts, ','); + + // Now we have the first address, we can reliably check for a + // group by searching for a colon that's not escaped or in + // quotes or angle brackets. + if (count($parts = explode(':', $string)) > 1) { + $string2 = $this->_splitCheck($parts, ':'); + return ($string2 !== $string); + } else { + return false; + } + } + + /** + * A common function that will check an exploded string. + * + * @access private + * @param array $parts The exloded string. + * @param string $char The char that was exploded on. + * @return mixed False if the string contains unclosed quotes/brackets, or the string on success. + */ + function _splitCheck($parts, $char) + { + $string = $parts[0]; + + for ($i = 0; $i < count($parts); $i++) { + if ($this->_hasUnclosedQuotes($string) + || $this->_hasUnclosedBrackets($string, '<>') + || $this->_hasUnclosedBrackets($string, '[]') + || $this->_hasUnclosedBrackets($string, '()') + || substr($string, -1) == '\\') { + if (isset($parts[$i + 1])) { + $string = $string . $char . $parts[$i + 1]; + } else { + $this->error = 'Invalid address spec. Unclosed bracket or quotes'; + return false; + } + } else { + $this->index = $i; + break; + } + } + + return $string; + } + + /** + * Checks if a string has unclosed quotes or not. + * + * @access private + * @param string $string The string to check. + * @return boolean True if there are unclosed quotes inside the string, + * false otherwise. + */ + function _hasUnclosedQuotes($string) + { + $string = trim($string); + $iMax = strlen($string); + $in_quote = false; + $i = $slashes = 0; + + for (; $i < $iMax; ++$i) { + switch ($string[$i]) { + case '\\': + ++$slashes; + break; + + case '"': + if ($slashes % 2 == 0) { + $in_quote = !$in_quote; + } + // Fall through to default action below. + + default: + $slashes = 0; + break; + } + } + + return $in_quote; + } + + /** + * Checks if a string has an unclosed brackets or not. IMPORTANT: + * This function handles both angle brackets and square brackets; + * + * @access private + * @param string $string The string to check. + * @param string $chars The characters to check for. + * @return boolean True if there are unclosed brackets inside the string, false otherwise. + */ + function _hasUnclosedBrackets($string, $chars) + { + $num_angle_start = substr_count($string, $chars[0]); + $num_angle_end = substr_count($string, $chars[1]); + + $this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]); + $this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]); + + if ($num_angle_start < $num_angle_end) { + $this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')'; + return false; + } else { + return ($num_angle_start > $num_angle_end); + } + } + + /** + * Sub function that is used only by hasUnclosedBrackets(). + * + * @access private + * @param string $string The string to check. + * @param integer &$num The number of occurences. + * @param string $char The character to count. + * @return integer The number of occurences of $char in $string, adjusted for backslashes. + */ + function _hasUnclosedBracketsSub($string, &$num, $char) + { + $parts = explode($char, $string); + for ($i = 0; $i < count($parts); $i++){ + if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i])) + $num--; + if (isset($parts[$i + 1])) + $parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1]; + } + + return $num; + } + + /** + * Function to begin checking the address. + * + * @access private + * @param string $address The address to validate. + * @return mixed False on failure, or a structured array of address information on success. + */ + function _validateAddress($address) + { + $is_group = false; + $addresses = array(); + + if ($address['group']) { + $is_group = true; + + // Get the group part of the name + $parts = explode(':', $address['address']); + $groupname = $this->_splitCheck($parts, ':'); + $structure = array(); + + // And validate the group part of the name. + if (!$this->_validatePhrase($groupname)){ + $this->error = 'Group name did not validate.'; + return false; + } else { + // Don't include groups if we are not nesting + // them. This avoids returning invalid addresses. + if ($this->nestGroups) { + $structure = new stdClass; + $structure->groupname = $groupname; + } + } + + $address['address'] = ltrim(substr($address['address'], strlen($groupname . ':'))); + } + + // If a group then split on comma and put into an array. + // Otherwise, Just put the whole address in an array. + if ($is_group) { + while (strlen($address['address']) > 0) { + $parts = explode(',', $address['address']); + $addresses[] = $this->_splitCheck($parts, ','); + $address['address'] = trim(substr($address['address'], strlen(end($addresses) . ','))); + } + } else { + $addresses[] = $address['address']; + } + + // Check that $addresses is set, if address like this: + // Groupname:; + // Then errors were appearing. + if (!count($addresses)){ + $this->error = 'Empty group.'; + return false; + } + + // Trim the whitespace from all of the address strings. + array_map('trim', $addresses); + + // Validate each mailbox. + // Format could be one of: name + // geezer@domain.com + // geezer + // ... or any other format valid by RFC 822. + for ($i = 0; $i < count($addresses); $i++) { + if (!$this->validateMailbox($addresses[$i])) { + if (empty($this->error)) { + $this->error = 'Validation failed for: ' . $addresses[$i]; + } + return false; + } + } + + // Nested format + if ($this->nestGroups) { + if ($is_group) { + $structure->addresses = $addresses; + } else { + $structure = $addresses[0]; + } + + // Flat format + } else { + if ($is_group) { + $structure = array_merge($structure, $addresses); + } else { + $structure = $addresses; + } + } + + return $structure; + } + + /** + * Function to validate a phrase. + * + * @access private + * @param string $phrase The phrase to check. + * @return boolean Success or failure. + */ + function _validatePhrase($phrase) + { + // Splits on one or more Tab or space. + $parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY); + + $phrase_parts = array(); + while (count($parts) > 0){ + $phrase_parts[] = $this->_splitCheck($parts, ' '); + for ($i = 0; $i < $this->index + 1; $i++) + array_shift($parts); + } + + foreach ($phrase_parts as $part) { + // If quoted string: + if (substr($part, 0, 1) == '"') { + if (!$this->_validateQuotedString($part)) { + return false; + } + continue; + } + + // Otherwise it's an atom: + if (!$this->_validateAtom($part)) return false; + } + + return true; + } + + /** + * Function to validate an atom which from rfc822 is: + * atom = 1* + * + * If validation ($this->validate) has been turned off, then + * validateAtom() doesn't actually check anything. This is so that you + * can split a list of addresses up before encoding personal names + * (umlauts, etc.), for example. + * + * @access private + * @param string $atom The string to check. + * @return boolean Success or failure. + */ + function _validateAtom($atom) + { + if (!$this->validate) { + // Validation has been turned off; assume the atom is okay. + return true; + } + + // Check for any char from ASCII 0 - ASCII 127 + if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) { + return false; + } + + // Check for specials: + if (preg_match('/[][()<>@,;\\:". ]/', $atom)) { + return false; + } + + // Check for control characters (ASCII 0-31): + if (preg_match('/[\\x00-\\x1F]+/', $atom)) { + return false; + } + + return true; + } + + /** + * Function to validate quoted string, which is: + * quoted-string = <"> *(qtext/quoted-pair) <"> + * + * @access private + * @param string $qstring The string to check + * @return boolean Success or failure. + */ + function _validateQuotedString($qstring) + { + // Leading and trailing " + $qstring = substr($qstring, 1, -1); + + // Perform check, removing quoted characters first. + return !preg_match('/[\x0D\\\\"]/', preg_replace('/\\\\./', '', $qstring)); + } + + /** + * Function to validate a mailbox, which is: + * mailbox = addr-spec ; simple address + * / phrase route-addr ; name and route-addr + * + * @access public + * @param string &$mailbox The string to check. + * @return boolean Success or failure. + */ + function validateMailbox(&$mailbox) + { + // A couple of defaults. + $phrase = ''; + $comment = ''; + $comments = array(); + + // Catch any RFC822 comments and store them separately. + $_mailbox = $mailbox; + while (strlen(trim($_mailbox)) > 0) { + $parts = explode('(', $_mailbox); + $before_comment = $this->_splitCheck($parts, '('); + if ($before_comment != $_mailbox) { + // First char should be a (. + $comment = substr(str_replace($before_comment, '', $_mailbox), 1); + $parts = explode(')', $comment); + $comment = $this->_splitCheck($parts, ')'); + $comments[] = $comment; + + // +2 is for the brackets + $_mailbox = substr($_mailbox, strpos($_mailbox, '('.$comment)+strlen($comment)+2); + } else { + break; + } + } + + foreach ($comments as $comment) { + $mailbox = str_replace("($comment)", '', $mailbox); + } + + $mailbox = trim($mailbox); + + // Check for name + route-addr + if (substr($mailbox, -1) == '>' && substr($mailbox, 0, 1) != '<') { + $parts = explode('<', $mailbox); + $name = $this->_splitCheck($parts, '<'); + + $phrase = trim($name); + $route_addr = trim(substr($mailbox, strlen($name.'<'), -1)); + + if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) { + return false; + } + + // Only got addr-spec + } else { + // First snip angle brackets if present. + if (substr($mailbox, 0, 1) == '<' && substr($mailbox, -1) == '>') { + $addr_spec = substr($mailbox, 1, -1); + } else { + $addr_spec = $mailbox; + } + + if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { + return false; + } + } + + // Construct the object that will be returned. + $mbox = new stdClass(); + + // Add the phrase (even if empty) and comments + $mbox->personal = $phrase; + $mbox->comment = isset($comments) ? $comments : array(); + + if (isset($route_addr)) { + $mbox->mailbox = $route_addr['local_part']; + $mbox->host = $route_addr['domain']; + $route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : ''; + } else { + $mbox->mailbox = $addr_spec['local_part']; + $mbox->host = $addr_spec['domain']; + } + + $mailbox = $mbox; + return true; + } + + /** + * This function validates a route-addr which is: + * route-addr = "<" [route] addr-spec ">" + * + * Angle brackets have already been removed at the point of + * getting to this function. + * + * @access private + * @param string $route_addr The string to check. + * @return mixed False on failure, or an array containing validated address/route information on success. + */ + function _validateRouteAddr($route_addr) + { + // Check for colon. + if (strpos($route_addr, ':') !== false) { + $parts = explode(':', $route_addr); + $route = $this->_splitCheck($parts, ':'); + } else { + $route = $route_addr; + } + + // If $route is same as $route_addr then the colon was in + // quotes or brackets or, of course, non existent. + if ($route === $route_addr){ + unset($route); + $addr_spec = $route_addr; + if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { + return false; + } + } else { + // Validate route part. + if (($route = $this->_validateRoute($route)) === false) { + return false; + } + + $addr_spec = substr($route_addr, strlen($route . ':')); + + // Validate addr-spec part. + if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { + return false; + } + } + + if (isset($route)) { + $return['adl'] = $route; + } else { + $return['adl'] = ''; + } + + $return = array_merge($return, $addr_spec); + return $return; + } + + /** + * Function to validate a route, which is: + * route = 1#("@" domain) ":" + * + * @access private + * @param string $route The string to check. + * @return mixed False on failure, or the validated $route on success. + */ + function _validateRoute($route) + { + // Split on comma. + $domains = explode(',', trim($route)); + + foreach ($domains as $domain) { + $domain = str_replace('@', '', trim($domain)); + if (!$this->_validateDomain($domain)) return false; + } + + return $route; + } + + /** + * Function to validate a domain, though this is not quite what + * you expect of a strict internet domain. + * + * domain = sub-domain *("." sub-domain) + * + * @access private + * @param string $domain The string to check. + * @return mixed False on failure, or the validated domain on success. + */ + function _validateDomain($domain) + { + // Note the different use of $subdomains and $sub_domains + $subdomains = explode('.', $domain); + + while (count($subdomains) > 0) { + $sub_domains[] = $this->_splitCheck($subdomains, '.'); + for ($i = 0; $i < $this->index + 1; $i++) + array_shift($subdomains); + } + + foreach ($sub_domains as $sub_domain) { + if (!$this->_validateSubdomain(trim($sub_domain))) + return false; + } + + // Managed to get here, so return input. + return $domain; + } + + /** + * Function to validate a subdomain: + * subdomain = domain-ref / domain-literal + * + * @access private + * @param string $subdomain The string to check. + * @return boolean Success or failure. + */ + function _validateSubdomain($subdomain) + { + if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){ + if (!$this->_validateDliteral($arr[1])) return false; + } else { + if (!$this->_validateAtom($subdomain)) return false; + } + + // Got here, so return successful. + return true; + } + + /** + * Function to validate a domain literal: + * domain-literal = "[" *(dtext / quoted-pair) "]" + * + * @access private + * @param string $dliteral The string to check. + * @return boolean Success or failure. + */ + function _validateDliteral($dliteral) + { + return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && $matches[1] != '\\'; + } + + /** + * Function to validate an addr-spec. + * + * addr-spec = local-part "@" domain + * + * @access private + * @param string $addr_spec The string to check. + * @return mixed False on failure, or the validated addr-spec on success. + */ + function _validateAddrSpec($addr_spec) + { + $addr_spec = trim($addr_spec); + + // Split on @ sign if there is one. + if (strpos($addr_spec, '@') !== false) { + $parts = explode('@', $addr_spec); + $local_part = $this->_splitCheck($parts, '@'); + $domain = substr($addr_spec, strlen($local_part . '@')); + + // No @ sign so assume the default domain. + } else { + $local_part = $addr_spec; + $domain = $this->default_domain; + } + + if (($local_part = $this->_validateLocalPart($local_part)) === false) return false; + if (($domain = $this->_validateDomain($domain)) === false) return false; + + // Got here so return successful. + return array('local_part' => $local_part, 'domain' => $domain); + } + + /** + * Function to validate the local part of an address: + * local-part = word *("." word) + * + * @access private + * @param string $local_part + * @return mixed False on failure, or the validated local part on success. + */ + function _validateLocalPart($local_part) + { + $parts = explode('.', $local_part); + $words = array(); + + // Split the local_part into words. + while (count($parts) > 0){ + $words[] = $this->_splitCheck($parts, '.'); + for ($i = 0; $i < $this->index + 1; $i++) { + array_shift($parts); + } + } + + // Validate each word. + foreach ($words as $word) { + // If this word contains an unquoted space, it is invalid. (6.2.4) + if (strpos($word, ' ') && $word[0] !== '"') + { + return false; + } + + if ($this->_validatePhrase(trim($word)) === false) return false; + } + + // Managed to get here, so return the input. + return $local_part; + } + + /** + * Returns an approximate count of how many addresses are in the + * given string. This is APPROXIMATE as it only splits based on a + * comma which has no preceding backslash. Could be useful as + * large amounts of addresses will end up producing *large* + * structures when used with parseAddressList(). + * + * @param string $data Addresses to count + * @return int Approximate count + */ + function approximateCount($data) + { + return count(preg_split('/(?@. This can be sufficient for most + * people. Optional stricter mode can be utilised which restricts + * mailbox characters allowed to alphanumeric, full stop, hyphen + * and underscore. + * + * @param string $data Address to check + * @param boolean $strict Optional stricter mode + * @return mixed False if it fails, an indexed array + * username/domain if it matches + */ + function isValidInetAddress($data, $strict = false) + { + $regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i'; + if (preg_match($regex, trim($data), $matches)) { + return array($matches[1], $matches[2]); + } else { + return false; + } + } + +} diff --git a/core/lib/Mail/mail.php b/core/lib/Mail/mail.php new file mode 100644 index 00000000..a8b4b5db --- /dev/null +++ b/core/lib/Mail/mail.php @@ -0,0 +1,168 @@ + + * @copyright 2010 Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: mail.php 294747 2010-02-08 08:18:33Z clockwerx $ + * @link http://pear.php.net/package/Mail/ + */ + +/** + * internal PHP-mail() implementation of the PEAR Mail:: interface. + * @package Mail + * @version $Revision: 294747 $ + */ +class Mail_mail extends Mail { + + /** + * Any arguments to pass to the mail() function. + * @var string + */ + var $_params = ''; + + /** + * Constructor. + * + * Instantiates a new Mail_mail:: object based on the parameters + * passed in. + * + * @param array $params Extra arguments for the mail() function. + */ + function Mail_mail($params = null) + { + // The other mail implementations accept parameters as arrays. + // In the interest of being consistent, explode an array into + // a string of parameter arguments. + if (is_array($params)) { + $this->_params = join(' ', $params); + } else { + $this->_params = $params; + } + + /* Because the mail() function may pass headers as command + * line arguments, we can't guarantee the use of the standard + * "\r\n" separator. Instead, we use the system's native line + * separator. */ + if (defined('PHP_EOL')) { + $this->sep = PHP_EOL; + } else { + $this->sep = (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n"; + } + } + + /** + * Implements Mail_mail::send() function using php's built-in mail() + * command. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * + * @access public + */ + function send($recipients, $headers, $body) + { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + // If we're passed an array of recipients, implode it. + if (is_array($recipients)) { + $recipients = implode(', ', $recipients); + } + + // Get the Subject out of the headers array so that we can + // pass it as a seperate argument to mail(). + $subject = ''; + if (isset($headers['Subject'])) { + $subject = $headers['Subject']; + unset($headers['Subject']); + } + + // Also remove the To: header. The mail() function will add its own + // To: header based on the contents of $recipients. + unset($headers['To']); + + // Flatten the headers out. + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + return $headerElements; + } + list(, $text_headers) = $headerElements; + + // We only use mail()'s optional fifth parameter if the additional + // parameters have been provided and we're not running in safe mode. + if (empty($this->_params) || ini_get('safe_mode')) { + $result = mail($recipients, $subject, $body, $text_headers); + } else { + $result = mail($recipients, $subject, $body, $text_headers, + $this->_params); + } + + // If the mail() function returned failure, we need to create a + // PEAR_Error object and return it instead of the boolean result. + if ($result === false) { + $result = PEAR::raiseError('mail() returned failure'); + } + + return $result; + } + +} diff --git a/core/lib/Mail/mock.php b/core/lib/Mail/mock.php new file mode 100644 index 00000000..61570ba4 --- /dev/null +++ b/core/lib/Mail/mock.php @@ -0,0 +1,143 @@ + + * @copyright 2010 Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: mock.php 294747 2010-02-08 08:18:33Z clockwerx $ + * @link http://pear.php.net/package/Mail/ + */ + +/** + * Mock implementation of the PEAR Mail:: interface for testing. + * @access public + * @package Mail + * @version $Revision: 294747 $ + */ +class Mail_mock extends Mail { + + /** + * Array of messages that have been sent with the mock. + * + * @var array + * @access public + */ + var $sentMessages = array(); + + /** + * Callback before sending mail. + * + * @var callback + */ + var $_preSendCallback; + + /** + * Callback after sending mai. + * + * @var callback + */ + var $_postSendCallback; + + /** + * Constructor. + * + * Instantiates a new Mail_mock:: object based on the parameters + * passed in. It looks for the following parameters, both optional: + * preSendCallback Called before an email would be sent. + * postSendCallback Called after an email would have been sent. + * + * @param array Hash containing any parameters. + * @access public + */ + function Mail_mock($params) + { + if (isset($params['preSendCallback']) && + is_callable($params['preSendCallback'])) { + $this->_preSendCallback = $params['preSendCallback']; + } + + if (isset($params['postSendCallback']) && + is_callable($params['postSendCallback'])) { + $this->_postSendCallback = $params['postSendCallback']; + } + } + + /** + * Implements Mail_mock::send() function. Silently discards all + * mail. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + if ($this->_preSendCallback) { + call_user_func_array($this->_preSendCallback, + array(&$this, $recipients, $headers, $body)); + } + + $entry = array('recipients' => $recipients, 'headers' => $headers, 'body' => $body); + $this->sentMessages[] = $entry; + + if ($this->_postSendCallback) { + call_user_func_array($this->_postSendCallback, + array(&$this, $recipients, $headers, $body)); + } + + return true; + } + +} diff --git a/core/lib/Mail/null.php b/core/lib/Mail/null.php new file mode 100644 index 00000000..f8d58272 --- /dev/null +++ b/core/lib/Mail/null.php @@ -0,0 +1,84 @@ + + * @copyright 2010 Phil Kernick + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: null.php 294747 2010-02-08 08:18:33Z clockwerx $ + * @link http://pear.php.net/package/Mail/ + */ + +/** + * Null implementation of the PEAR Mail:: interface. + * @access public + * @package Mail + * @version $Revision: 294747 $ + */ +class Mail_null extends Mail { + + /** + * Implements Mail_null::send() function. Silently discards all + * mail. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + return true; + } + +} diff --git a/core/lib/Mail/sendmail.php b/core/lib/Mail/sendmail.php new file mode 100644 index 00000000..b056575e --- /dev/null +++ b/core/lib/Mail/sendmail.php @@ -0,0 +1,171 @@ + | +// +----------------------------------------------------------------------+ + +/** + * Sendmail implementation of the PEAR Mail:: interface. + * @access public + * @package Mail + * @version $Revision: 294744 $ + */ +class Mail_sendmail extends Mail { + + /** + * The location of the sendmail or sendmail wrapper binary on the + * filesystem. + * @var string + */ + var $sendmail_path = '/usr/sbin/sendmail'; + + /** + * Any extra command-line parameters to pass to the sendmail or + * sendmail wrapper binary. + * @var string + */ + var $sendmail_args = '-i'; + + /** + * Constructor. + * + * Instantiates a new Mail_sendmail:: object based on the parameters + * passed in. It looks for the following parameters: + * sendmail_path The location of the sendmail binary on the + * filesystem. Defaults to '/usr/sbin/sendmail'. + * + * sendmail_args Any extra parameters to pass to the sendmail + * or sendmail wrapper binary. + * + * If a parameter is present in the $params array, it replaces the + * default. + * + * @param array $params Hash containing any parameters different from the + * defaults. + * @access public + */ + function Mail_sendmail($params) + { + if (isset($params['sendmail_path'])) { + $this->sendmail_path = $params['sendmail_path']; + } + if (isset($params['sendmail_args'])) { + $this->sendmail_args = $params['sendmail_args']; + } + + /* + * Because we need to pass message headers to the sendmail program on + * the commandline, we can't guarantee the use of the standard "\r\n" + * separator. Instead, we use the system's native line separator. + */ + if (defined('PHP_EOL')) { + $this->sep = PHP_EOL; + } else { + $this->sep = (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n"; + } + } + + /** + * Implements Mail::send() function using the sendmail + * command-line binary. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + $recipients = $this->parseRecipients($recipients); + if (is_a($recipients, 'PEAR_Error')) { + return $recipients; + } + $recipients = implode(' ', array_map('escapeshellarg', $recipients)); + + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + return $headerElements; + } + list($from, $text_headers) = $headerElements; + + /* Since few MTAs are going to allow this header to be forged + * unless it's in the MAIL FROM: exchange, we'll use + * Return-Path instead of From: if it's set. */ + if (!empty($headers['Return-Path'])) { + $from = $headers['Return-Path']; + } + + if (!isset($from)) { + return PEAR::raiseError('No from address given.'); + } elseif (strpos($from, ' ') !== false || + strpos($from, ';') !== false || + strpos($from, '&') !== false || + strpos($from, '`') !== false) { + return PEAR::raiseError('From address specified with dangerous characters.'); + } + + $from = escapeshellarg($from); // Security bug #16200 + + $mail = @popen($this->sendmail_path . (!empty($this->sendmail_args) ? ' ' . $this->sendmail_args : '') . " -f$from -- $recipients", 'w'); + if (!$mail) { + return PEAR::raiseError('Failed to open sendmail [' . $this->sendmail_path . '] for execution.'); + } + + // Write the headers following by two newlines: one to end the headers + // section and a second to separate the headers block from the body. + fputs($mail, $text_headers . $this->sep . $this->sep); + + fputs($mail, $body); + $result = pclose($mail); + if (version_compare(phpversion(), '4.2.3') == -1) { + // With older php versions, we need to shift the pclose + // result to get the exit code. + $result = $result >> 8 & 0xFF; + } + + if ($result != 0) { + return PEAR::raiseError('sendmail returned error code ' . $result, + $result); + } + + return true; + } + +} diff --git a/core/lib/Mail/smtp.php b/core/lib/Mail/smtp.php new file mode 100644 index 00000000..52ea6020 --- /dev/null +++ b/core/lib/Mail/smtp.php @@ -0,0 +1,444 @@ + + * @author Chuck Hagenbuch + * @copyright 2010 Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: smtp.php 294747 2010-02-08 08:18:33Z clockwerx $ + * @link http://pear.php.net/package/Mail/ + */ + +/** Error: Failed to create a Net_SMTP object */ +define('PEAR_MAIL_SMTP_ERROR_CREATE', 10000); + +/** Error: Failed to connect to SMTP server */ +define('PEAR_MAIL_SMTP_ERROR_CONNECT', 10001); + +/** Error: SMTP authentication failure */ +define('PEAR_MAIL_SMTP_ERROR_AUTH', 10002); + +/** Error: No From: address has been provided */ +define('PEAR_MAIL_SMTP_ERROR_FROM', 10003); + +/** Error: Failed to set sender */ +define('PEAR_MAIL_SMTP_ERROR_SENDER', 10004); + +/** Error: Failed to add recipient */ +define('PEAR_MAIL_SMTP_ERROR_RECIPIENT', 10005); + +/** Error: Failed to send data */ +define('PEAR_MAIL_SMTP_ERROR_DATA', 10006); + +/** + * SMTP implementation of the PEAR Mail interface. Requires the Net_SMTP class. + * @access public + * @package Mail + * @version $Revision: 294747 $ + */ +class Mail_smtp extends Mail { + + /** + * SMTP connection object. + * + * @var object + * @access private + */ + var $_smtp = null; + + /** + * The list of service extension parameters to pass to the Net_SMTP + * mailFrom() command. + * @var array + */ + var $_extparams = array(); + + /** + * The SMTP host to connect to. + * @var string + */ + var $host = 'localhost'; + + /** + * The port the SMTP server is on. + * @var integer + */ + var $port = 25; + + /** + * Should SMTP authentication be used? + * + * This value may be set to true, false or the name of a specific + * authentication method. + * + * If the value is set to true, the Net_SMTP package will attempt to use + * the best authentication method advertised by the remote SMTP server. + * + * @var mixed + */ + var $auth = false; + + /** + * The username to use if the SMTP server requires authentication. + * @var string + */ + var $username = ''; + + /** + * The password to use if the SMTP server requires authentication. + * @var string + */ + var $password = ''; + + /** + * Hostname or domain that will be sent to the remote SMTP server in the + * HELO / EHLO message. + * + * @var string + */ + var $localhost = 'localhost'; + + /** + * SMTP connection timeout value. NULL indicates no timeout. + * + * @var integer + */ + var $timeout = null; + + /** + * Turn on Net_SMTP debugging? + * + * @var boolean $debug + */ + var $debug = false; + + /** + * Indicates whether or not the SMTP connection should persist over + * multiple calls to the send() method. + * + * @var boolean + */ + var $persist = false; + + /** + * Use SMTP command pipelining (specified in RFC 2920) if the SMTP server + * supports it. This speeds up delivery over high-latency connections. By + * default, use the default value supplied by Net_SMTP. + * @var bool + */ + var $pipelining; + + /** + * Constructor. + * + * Instantiates a new Mail_smtp:: object based on the parameters + * passed in. It looks for the following parameters: + * host The server to connect to. Defaults to localhost. + * port The port to connect to. Defaults to 25. + * auth SMTP authentication. Defaults to none. + * username The username to use for SMTP auth. No default. + * password The password to use for SMTP auth. No default. + * localhost The local hostname / domain. Defaults to localhost. + * timeout The SMTP connection timeout. Defaults to none. + * verp Whether to use VERP or not. Defaults to false. + * DEPRECATED as of 1.2.0 (use setMailParams()). + * debug Activate SMTP debug mode? Defaults to false. + * persist Should the SMTP connection persist? + * pipelining Use SMTP command pipelining + * + * If a parameter is present in the $params array, it replaces the + * default. + * + * @param array Hash containing any parameters different from the + * defaults. + * @access public + */ + function Mail_smtp($params) + { + if (isset($params['host'])) $this->host = $params['host']; + if (isset($params['port'])) $this->port = $params['port']; + if (isset($params['auth'])) $this->auth = $params['auth']; + if (isset($params['username'])) $this->username = $params['username']; + if (isset($params['password'])) $this->password = $params['password']; + if (isset($params['localhost'])) $this->localhost = $params['localhost']; + if (isset($params['timeout'])) $this->timeout = $params['timeout']; + if (isset($params['debug'])) $this->debug = (bool)$params['debug']; + if (isset($params['persist'])) $this->persist = (bool)$params['persist']; + if (isset($params['pipelining'])) $this->pipelining = (bool)$params['pipelining']; + + // Deprecated options + if (isset($params['verp'])) { + $this->addServiceExtensionParameter('XVERP', is_bool($params['verp']) ? null : $params['verp']); + } + + register_shutdown_function(array(&$this, '_Mail_smtp')); + } + + /** + * Destructor implementation to ensure that we disconnect from any + * potentially-alive persistent SMTP connections. + */ + function _Mail_smtp() + { + $this->disconnect(); + } + + /** + * Implements Mail::send() function using SMTP. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (e.g., 'Subject'), and the array value + * is the header value (e.g., 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * MIME parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + /* If we don't already have an SMTP object, create one. */ + $result = &$this->getSMTPObject(); + if (PEAR::isError($result)) { + return $result; + } + + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $this->_sanitizeHeaders($headers); + + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + $this->_smtp->rset(); + return $headerElements; + } + list($from, $textHeaders) = $headerElements; + + /* Since few MTAs are going to allow this header to be forged + * unless it's in the MAIL FROM: exchange, we'll use + * Return-Path instead of From: if it's set. */ + if (!empty($headers['Return-Path'])) { + $from = $headers['Return-Path']; + } + + if (!isset($from)) { + $this->_smtp->rset(); + return PEAR::raiseError('No From: address has been provided', + PEAR_MAIL_SMTP_ERROR_FROM); + } + + $params = null; + if (!empty($this->_extparams)) { + foreach ($this->_extparams as $key => $val) { + $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val); + } + } + if (PEAR::isError($res = $this->_smtp->mailFrom($from, ltrim($params)))) { + $error = $this->_error("Failed to set sender: $from", $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_SENDER); + } + + $recipients = $this->parseRecipients($recipients); + if (is_a($recipients, 'PEAR_Error')) { + $this->_smtp->rset(); + return $recipients; + } + + foreach ($recipients as $recipient) { + $res = $this->_smtp->rcptTo($recipient); + if (is_a($res, 'PEAR_Error')) { + $error = $this->_error("Failed to add recipient: $recipient", $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_RECIPIENT); + } + } + + /* Send the message's headers and the body as SMTP data. */ + $res = $this->_smtp->data($textHeaders . "\r\n\r\n" . $body); + list(,$args) = $this->_smtp->getResponse(); + + if (preg_match("/Ok: queued as (.*)/", $args, $queued)) { + $this->queued_as = $queued[1]; + } + + /* we need the greeting; from it we can extract the authorative name of the mail server we've really connected to. + * ideal if we're connecting to a round-robin of relay servers and need to track which exact one took the email */ + $this->greeting = $this->_smtp->getGreeting(); + + if (is_a($res, 'PEAR_Error')) { + $error = $this->_error('Failed to send data', $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_DATA); + } + + /* If persistent connections are disabled, destroy our SMTP object. */ + if ($this->persist === false) { + $this->disconnect(); + } + + return true; + } + + /** + * Connect to the SMTP server by instantiating a Net_SMTP object. + * + * @return mixed Returns a reference to the Net_SMTP object on success, or + * a PEAR_Error containing a descriptive error message on + * failure. + * + * @since 1.2.0 + * @access public + */ + function &getSMTPObject() + { + if (is_object($this->_smtp) !== false) { + return $this->_smtp; + } + + include_once 'Net/SMTP.php'; + $this->_smtp = &new Net_SMTP($this->host, + $this->port, + $this->localhost); + + /* If we still don't have an SMTP object at this point, fail. */ + if (is_object($this->_smtp) === false) { + return PEAR::raiseError('Failed to create a Net_SMTP object', + PEAR_MAIL_SMTP_ERROR_CREATE); + } + + /* Configure the SMTP connection. */ + if ($this->debug) { + $this->_smtp->setDebug(true); + } + + /* Attempt to connect to the configured SMTP server. */ + if (PEAR::isError($res = $this->_smtp->connect($this->timeout))) { + $error = $this->_error('Failed to connect to ' . + $this->host . ':' . $this->port, + $res); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_CONNECT); + } + + /* Attempt to authenticate if authentication has been enabled. */ + if ($this->auth) { + $method = is_string($this->auth) ? $this->auth : ''; + + if (PEAR::isError($res = $this->_smtp->auth($this->username, + $this->password, + $method))) { + $error = $this->_error("$method authentication failure", + $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_AUTH); + } + } + + return $this->_smtp; + } + + /** + * Add parameter associated with a SMTP service extension. + * + * @param string Extension keyword. + * @param string Any value the keyword needs. + * + * @since 1.2.0 + * @access public + */ + function addServiceExtensionParameter($keyword, $value = null) + { + $this->_extparams[$keyword] = $value; + } + + /** + * Disconnect and destroy the current SMTP connection. + * + * @return boolean True if the SMTP connection no longer exists. + * + * @since 1.1.9 + * @access public + */ + function disconnect() + { + /* If we have an SMTP object, disconnect and destroy it. */ + if (is_object($this->_smtp) && $this->_smtp->disconnect()) { + $this->_smtp = null; + } + + /* We are disconnected if we no longer have an SMTP object. */ + return ($this->_smtp === null); + } + + /** + * Build a standardized string describing the current SMTP error. + * + * @param string $text Custom string describing the error context. + * @param object $error Reference to the current PEAR_Error object. + * + * @return string A string describing the current SMTP error. + * + * @since 1.1.7 + * @access private + */ + function _error($text, &$error) + { + /* Split the SMTP response into a code and a response string. */ + list($code, $response) = $this->_smtp->getResponse(); + + /* Build our standardized error string. */ + return $text + . ' [SMTP: ' . $error->getMessage() + . " (code: $code, response: $response)]"; + } + +} diff --git a/core/lib/Mail/smtpmx.php b/core/lib/Mail/smtpmx.php new file mode 100644 index 00000000..f0b69408 --- /dev/null +++ b/core/lib/Mail/smtpmx.php @@ -0,0 +1,502 @@ + + * @copyright 2010 gERD Schaufelberger + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: smtpmx.php 294747 2010-02-08 08:18:33Z clockwerx $ + * @link http://pear.php.net/package/Mail/ + */ + +require_once 'Net/SMTP.php'; + +/** + * SMTP MX implementation of the PEAR Mail interface. Requires the Net_SMTP class. + * + * + * @access public + * @author gERD Schaufelberger + * @package Mail + * @version $Revision: 294747 $ + */ +class Mail_smtpmx extends Mail { + + /** + * SMTP connection object. + * + * @var object + * @access private + */ + var $_smtp = null; + + /** + * The port the SMTP server is on. + * @var integer + * @see getservicebyname() + */ + var $port = 25; + + /** + * Hostname or domain that will be sent to the remote SMTP server in the + * HELO / EHLO message. + * + * @var string + * @see posix_uname() + */ + var $mailname = 'localhost'; + + /** + * SMTP connection timeout value. NULL indicates no timeout. + * + * @var integer + */ + var $timeout = 10; + + /** + * use either PEAR:Net_DNS or getmxrr + * + * @var boolean + */ + var $withNetDns = true; + + /** + * PEAR:Net_DNS_Resolver + * + * @var object + */ + var $resolver; + + /** + * Whether to use VERP or not. If not a boolean, the string value + * will be used as the VERP separators. + * + * @var mixed boolean or string + */ + var $verp = false; + + /** + * Whether to use VRFY or not. + * + * @var boolean $vrfy + */ + var $vrfy = false; + + /** + * Switch to test mode - don't send emails for real + * + * @var boolean $debug + */ + var $test = false; + + /** + * Turn on Net_SMTP debugging? + * + * @var boolean $peardebug + */ + var $debug = false; + + /** + * internal error codes + * + * translate internal error identifier to PEAR-Error codes and human + * readable messages. + * + * @var boolean $debug + * @todo as I need unique error-codes to identify what exactly went wrond + * I did not use intergers as it should be. Instead I added a "namespace" + * for each code. This avoids conflicts with error codes from different + * classes. How can I use unique error codes and stay conform with PEAR? + */ + var $errorCode = array( + 'not_connected' => array( + 'code' => 1, + 'msg' => 'Could not connect to any mail server ({HOST}) at port {PORT} to send mail to {RCPT}.' + ), + 'failed_vrfy_rcpt' => array( + 'code' => 2, + 'msg' => 'Recipient "{RCPT}" could not be veryfied.' + ), + 'failed_set_from' => array( + 'code' => 3, + 'msg' => 'Failed to set sender: {FROM}.' + ), + 'failed_set_rcpt' => array( + 'code' => 4, + 'msg' => 'Failed to set recipient: {RCPT}.' + ), + 'failed_send_data' => array( + 'code' => 5, + 'msg' => 'Failed to send mail to: {RCPT}.' + ), + 'no_from' => array( + 'code' => 5, + 'msg' => 'No from address has be provided.' + ), + 'send_data' => array( + 'code' => 7, + 'msg' => 'Failed to create Net_SMTP object.' + ), + 'no_mx' => array( + 'code' => 8, + 'msg' => 'No MX-record for {RCPT} found.' + ), + 'no_resolver' => array( + 'code' => 9, + 'msg' => 'Could not start resolver! Install PEAR:Net_DNS or switch off "netdns"' + ), + 'failed_rset' => array( + 'code' => 10, + 'msg' => 'RSET command failed, SMTP-connection corrupt.' + ), + ); + + /** + * Constructor. + * + * Instantiates a new Mail_smtp:: object based on the parameters + * passed in. It looks for the following parameters: + * mailname The name of the local mail system (a valid hostname which matches the reverse lookup) + * port smtp-port - the default comes from getservicebyname() and should work fine + * timeout The SMTP connection timeout. Defaults to 30 seconds. + * vrfy Whether to use VRFY or not. Defaults to false. + * verp Whether to use VERP or not. Defaults to false. + * test Activate test mode? Defaults to false. + * debug Activate SMTP and Net_DNS debug mode? Defaults to false. + * netdns whether to use PEAR:Net_DNS or the PHP build in function getmxrr, default is true + * + * If a parameter is present in the $params array, it replaces the + * default. + * + * @access public + * @param array Hash containing any parameters different from the + * defaults. + * @see _Mail_smtpmx() + */ + function __construct($params) + { + if (isset($params['mailname'])) { + $this->mailname = $params['mailname']; + } else { + // try to find a valid mailname + if (function_exists('posix_uname')) { + $uname = posix_uname(); + $this->mailname = $uname['nodename']; + } + } + + // port number + if (isset($params['port'])) { + $this->_port = $params['port']; + } else { + $this->_port = getservbyname('smtp', 'tcp'); + } + + if (isset($params['timeout'])) $this->timeout = $params['timeout']; + if (isset($params['verp'])) $this->verp = $params['verp']; + if (isset($params['test'])) $this->test = $params['test']; + if (isset($params['peardebug'])) $this->test = $params['peardebug']; + if (isset($params['netdns'])) $this->withNetDns = $params['netdns']; + } + + /** + * Constructor wrapper for PHP4 + * + * @access public + * @param array Hash containing any parameters different from the defaults + * @see __construct() + */ + function Mail_smtpmx($params) + { + $this->__construct($params); + register_shutdown_function(array(&$this, '__destruct')); + } + + /** + * Destructor implementation to ensure that we disconnect from any + * potentially-alive persistent SMTP connections. + */ + function __destruct() + { + if (is_object($this->_smtp)) { + $this->_smtp->disconnect(); + $this->_smtp = null; + } + } + + /** + * Implements Mail::send() function using SMTP direct delivery + * + * @access public + * @param mixed $recipients in RFC822 style or array + * @param array $headers The array of headers to send with the mail. + * @param string $body The full text of the message body, + * @return mixed Returns true on success, or a PEAR_Error + */ + function send($recipients, $headers, $body) + { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + // Prepare headers + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + return $headerElements; + } + list($from, $textHeaders) = $headerElements; + + // use 'Return-Path' if possible + if (!empty($headers['Return-Path'])) { + $from = $headers['Return-Path']; + } + if (!isset($from)) { + return $this->_raiseError('no_from'); + } + + // Prepare recipients + $recipients = $this->parseRecipients($recipients); + if (is_a($recipients, 'PEAR_Error')) { + return $recipients; + } + + foreach ($recipients as $rcpt) { + list($user, $host) = explode('@', $rcpt); + + $mx = $this->_getMx($host); + if (is_a($mx, 'PEAR_Error')) { + return $mx; + } + + if (empty($mx)) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('no_mx', $info); + } + + $connected = false; + foreach ($mx as $mserver => $mpriority) { + $this->_smtp = new Net_SMTP($mserver, $this->port, $this->mailname); + + // configure the SMTP connection. + if ($this->debug) { + $this->_smtp->setDebug(true); + } + + // attempt to connect to the configured SMTP server. + $res = $this->_smtp->connect($this->timeout); + if (is_a($res, 'PEAR_Error')) { + $this->_smtp = null; + continue; + } + + // connection established + if ($res) { + $connected = true; + break; + } + } + + if (!$connected) { + $info = array( + 'host' => implode(', ', array_keys($mx)), + 'port' => $this->port, + 'rcpt' => $rcpt, + ); + return $this->_raiseError('not_connected', $info); + } + + // Verify recipient + if ($this->vrfy) { + $res = $this->_smtp->vrfy($rcpt); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_vrfy_rcpt', $info); + } + } + + // mail from: + $args['verp'] = $this->verp; + $res = $this->_smtp->mailFrom($from, $args); + if (is_a($res, 'PEAR_Error')) { + $info = array('from' => $from); + return $this->_raiseError('failed_set_from', $info); + } + + // rcpt to: + $res = $this->_smtp->rcptTo($rcpt); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_set_rcpt', $info); + } + + // Don't send anything in test mode + if ($this->test) { + $result = $this->_smtp->rset(); + $res = $this->_smtp->rset(); + if (is_a($res, 'PEAR_Error')) { + return $this->_raiseError('failed_rset'); + } + + $this->_smtp->disconnect(); + $this->_smtp = null; + return true; + } + + // Send data + $res = $this->_smtp->data("$textHeaders\r\n$body"); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_send_data', $info); + } + + $this->_smtp->disconnect(); + $this->_smtp = null; + } + + return true; + } + + /** + * Recieve mx rexords for a spciefied host + * + * The MX records + * + * @access private + * @param string $host mail host + * @return mixed sorted + */ + function _getMx($host) + { + $mx = array(); + + if ($this->withNetDns) { + $res = $this->_loadNetDns(); + if (is_a($res, 'PEAR_Error')) { + return $res; + } + + $response = $this->resolver->query($host, 'MX'); + if (!$response) { + return false; + } + + foreach ($response->answer as $rr) { + if ($rr->type == 'MX') { + $mx[$rr->exchange] = $rr->preference; + } + } + } else { + $mxHost = array(); + $mxWeight = array(); + + if (!getmxrr($host, $mxHost, $mxWeight)) { + return false; + } + for ($i = 0; $i < count($mxHost); ++$i) { + $mx[$mxHost[$i]] = $mxWeight[$i]; + } + } + + asort($mx); + return $mx; + } + + /** + * initialize PEAR:Net_DNS_Resolver + * + * @access private + * @return boolean true on success + */ + function _loadNetDns() + { + if (is_object($this->resolver)) { + return true; + } + + if (!include_once 'Net/DNS.php') { + return $this->_raiseError('no_resolver'); + } + + $this->resolver = new Net_DNS_Resolver(); + if ($this->debug) { + $this->resolver->test = 1; + } + + return true; + } + + /** + * raise standardized error + * + * include additional information in error message + * + * @access private + * @param string $id maps error ids to codes and message + * @param array $info optional information in associative array + * @see _errorCode + */ + function _raiseError($id, $info = array()) + { + $code = $this->errorCode[$id]['code']; + $msg = $this->errorCode[$id]['msg']; + + // include info to messages + if (!empty($info)) { + $search = array(); + $replace = array(); + + foreach ($info as $key => $value) { + array_push($search, '{' . strtoupper($key) . '}'); + array_push($replace, $value); + } + + $msg = str_replace($search, $replace, $msg); + } + + return PEAR::raiseError($msg, $code); + } + +} diff --git a/core/lib/composer/composer.json b/core/lib/composer/composer.json index 8785efb3..1e9b9d4e 100644 --- a/core/lib/composer/composer.json +++ b/core/lib/composer/composer.json @@ -7,7 +7,10 @@ "filp/whoops": "~2.1", "swiftmailer/swiftmailer": "^6.0", "pear/net_smtp": "^1.7", - "pear/mail": "^1.4" + "pear/mail": "^1.4", + "spomky-labs/base64url": "^1.0", + "cebe/markdown": "^1.2", + "neitanod/forceutf8": "^2.0" }, "require-dev": { "phpunit/phpunit": "~6" diff --git a/core/lib/composer/composer.lock b/core/lib/composer/composer.lock index 0c73456b..f2645e62 100644 --- a/core/lib/composer/composer.lock +++ b/core/lib/composer/composer.lock @@ -4,9 +4,68 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "3a99d8f1889b03e3d3d346d1c53e284a", - "content-hash": "0d37f31f02f0af3f426b668e57096b14", + "content-hash": "45cdd8adec569a3ef6dfed9c8b1fab41", "packages": [ + { + "name": "cebe/markdown", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/cebe/markdown.git", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "shasum": "" + }, + "require": { + "lib-pcre": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "cebe/indent": "*", + "facebook/xhprof": "*@dev", + "phpunit/phpunit": "4.1.*" + }, + "bin": [ + "bin/markdown" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "cebe\\markdown\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Creator" + } + ], + "description": "A super fast, highly extensible markdown parser for PHP", + "homepage": "https://github.com/cebe/markdown#readme", + "keywords": [ + "extensible", + "fast", + "gfm", + "markdown", + "markdown-extra" + ], + "time": "2018-03-26T11:24:36+00:00" + }, { "name": "consolidation/annotated-command", "version": "2.8.2", @@ -56,7 +115,7 @@ } ], "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2017-11-29 16:23:23" + "time": "2017-11-29T16:23:23+00:00" }, { "name": "consolidation/config", @@ -110,7 +169,7 @@ } ], "description": "Provide configuration services for a commandline tool.", - "time": "2017-12-22 17:28:19" + "time": "2017-12-22T17:28:19+00:00" }, { "name": "consolidation/log", @@ -158,7 +217,7 @@ } ], "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", - "time": "2017-11-29 01:44:16" + "time": "2017-11-29T01:44:16+00:00" }, { "name": "consolidation/output-formatters", @@ -207,7 +266,7 @@ } ], "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2017-11-29 15:25:38" + "time": "2017-11-29T15:25:38+00:00" }, { "name": "consolidation/robo", @@ -284,7 +343,7 @@ } ], "description": "Modern task runner", - "time": "2017-12-29 06:48:35" + "time": "2017-12-29T06:48:35+00:00" }, { "name": "container-interop/container-interop", @@ -315,7 +374,7 @@ ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "homepage": "https://github.com/container-interop/container-interop", - "time": "2017-02-14 19:40:03" + "time": "2017-02-14T19:40:03+00:00" }, { "name": "dflydev/dot-access-data", @@ -374,7 +433,7 @@ "dot", "notation" ], - "time": "2017-01-20 21:14:22" + "time": "2017-01-20T21:14:22+00:00" }, { "name": "doctrine/lexer", @@ -428,7 +487,7 @@ "lexer", "parser" ], - "time": "2014-09-09 13:34:57" + "time": "2014-09-09T13:34:57+00:00" }, { "name": "egulias/email-validator", @@ -485,7 +544,7 @@ "validation", "validator" ], - "time": "2017-11-15 23:40:40" + "time": "2017-11-15T23:40:40+00:00" }, { "name": "filp/whoops", @@ -546,7 +605,7 @@ "throwable", "whoops" ], - "time": "2017-11-23 18:22:44" + "time": "2017-11-23T18:22:44+00:00" }, { "name": "gettext/gettext", @@ -606,7 +665,7 @@ "po", "translation" ], - "time": "2016-06-15 18:14:14" + "time": "2016-06-15T18:14:14+00:00" }, { "name": "gettext/languages", @@ -667,7 +726,7 @@ "translations", "unicode" ], - "time": "2017-03-23 17:02:28" + "time": "2017-03-23T17:02:28+00:00" }, { "name": "grasmash/expander", @@ -714,7 +773,7 @@ } ], "description": "Expands internal property references in PHP arrays file.", - "time": "2017-12-21 22:14:55" + "time": "2017-12-21T22:14:55+00:00" }, { "name": "grasmash/yaml-expander", @@ -762,7 +821,7 @@ } ], "description": "Expands internal property references in a yaml file.", - "time": "2017-12-16 16:06:03" + "time": "2017-12-16T16:06:03+00:00" }, { "name": "league/container", @@ -827,7 +886,7 @@ "provider", "service" ], - "time": "2017-05-10 09:20:27" + "time": "2017-05-10T09:20:27+00:00" }, { "name": "monolog/monolog", @@ -900,7 +959,41 @@ "logging", "psr-3" ], - "time": "2015-03-09 09:58:04" + "time": "2015-03-09T09:58:04+00:00" + }, + { + "name": "neitanod/forceutf8", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/neitanod/forceutf8.git", + "reference": "47c883ab2739e7938a8bb0bfd1c29d48c88858de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/neitanod/forceutf8/zipball/47c883ab2739e7938a8bb0bfd1c29d48c88858de", + "reference": "47c883ab2739e7938a8bb0bfd1c29d48c88858de", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ForceUTF8\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "authors": [ + { + "name": "Sebastián Grignoli", + "email": "grignoli@gmail.com" + } + ], + "description": "PHP Class Encoding featuring popular Encoding::toUTF8() function --formerly known as forceUTF8()-- that fixes mixed encoded strings.", + "homepage": "https://github.com/neitanod/forceutf8", + "time": "2017-05-22T18:50:57+00:00" }, { "name": "pear/console_getopt", @@ -947,7 +1040,7 @@ } ], "description": "More info available on: http://pear.php.net/package/Console_Getopt", - "time": "2015-07-20 20:28:12" + "time": "2015-07-20T20:28:12+00:00" }, { "name": "pear/mail", @@ -1005,7 +1098,7 @@ ], "description": "Class that provides multiple interfaces for sending emails.", "homepage": "http://pear.php.net/package/Mail", - "time": "2017-04-11 17:27:29" + "time": "2017-04-11T17:27:29+00:00" }, { "name": "pear/net_smtp", @@ -1065,7 +1158,7 @@ "mail", "smtp" ], - "time": "2017-01-14 18:19:55" + "time": "2017-01-14T18:19:55+00:00" }, { "name": "pear/net_socket", @@ -1119,7 +1212,7 @@ } ], "description": "More info available on: http://pear.php.net/package/Net_Socket", - "time": "2017-04-06 15:16:38" + "time": "2017-04-06T15:16:38+00:00" }, { "name": "pear/pear-core-minimal", @@ -1163,7 +1256,7 @@ } ], "description": "Minimal set of PEAR core files to be used as composer dependency", - "time": "2017-02-28 16:46:11" + "time": "2017-02-28T16:46:11+00:00" }, { "name": "pear/pear_exception", @@ -1218,7 +1311,7 @@ "keywords": [ "exception" ], - "time": "2015-02-10 20:07:52" + "time": "2015-02-10T20:07:52+00:00" }, { "name": "psr/container", @@ -1267,7 +1360,7 @@ "container-interop", "psr" ], - "time": "2017-02-14 16:28:37" + "time": "2017-02-14T16:28:37+00:00" }, { "name": "psr/log", @@ -1314,7 +1407,59 @@ "psr", "psr-3" ], - "time": "2016-10-10 12:19:37" + "time": "2016-10-10T12:19:37+00:00" + }, + { + "name": "spomky-labs/base64url", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/base64url.git", + "reference": "ef6d5fb93894063d9cee996022259fd08d6646ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/ef6d5fb93894063d9cee996022259fd08d6646ea", + "reference": "ef6d5fb93894063d9cee996022259fd08d6646ea", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Base64Url\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/base64url/contributors" + } + ], + "description": "Base 64 URL Safe Encoding/decoding PHP Library", + "homepage": "https://github.com/Spomky-Labs/base64url", + "keywords": [ + "base64", + "rfc4648", + "safe", + "url" + ], + "time": "2016-01-21T19:50:30+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -1369,7 +1514,7 @@ "mail", "mailer" ], - "time": "2017-09-30 22:39:41" + "time": "2017-09-30T22:39:41+00:00" }, { "name": "symfony/console", @@ -1438,7 +1583,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-01-03 07:37:34" + "time": "2018-01-03T07:37:34+00:00" }, { "name": "symfony/debug", @@ -1494,7 +1639,7 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-01-03 17:14:19" + "time": "2018-01-03T17:14:19+00:00" }, { "name": "symfony/event-dispatcher", @@ -1557,7 +1702,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-01-03 07:37:34" + "time": "2018-01-03T07:37:34+00:00" }, { "name": "symfony/filesystem", @@ -1606,7 +1751,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-01-03 07:37:34" + "time": "2018-01-03T07:37:34+00:00" }, { "name": "symfony/finder", @@ -1655,7 +1800,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-01-03 07:37:34" + "time": "2018-01-03T07:37:34+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -1714,7 +1859,7 @@ "portable", "shim" ], - "time": "2017-10-11 12:05:26" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/process", @@ -1763,7 +1908,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-01-03 07:37:34" + "time": "2018-01-03T07:37:34+00:00" }, { "name": "symfony/yaml", @@ -1821,7 +1966,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-01-03 07:37:34" + "time": "2018-01-03T07:37:34+00:00" }, { "name": "twig/twig", @@ -1882,7 +2027,7 @@ "keywords": [ "templating" ], - "time": "2016-01-11 14:02:19" + "time": "2016-01-11T14:02:19+00:00" } ], "packages-dev": [ @@ -1938,7 +2083,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14 21:17:01" + "time": "2015-06-14T21:17:01+00:00" }, { "name": "myclabs/deep-copy", @@ -1983,7 +2128,7 @@ "object", "object graph" ], - "time": "2017-10-19 19:58:43" + "time": "2017-10-19T19:58:43+00:00" }, { "name": "phar-io/manifest", @@ -2038,7 +2183,7 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05 18:14:27" + "time": "2017-03-05T18:14:27+00:00" }, { "name": "phar-io/version", @@ -2085,7 +2230,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05 17:38:23" + "time": "2017-03-05T17:38:23+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -2139,7 +2284,7 @@ "reflection", "static analysis" ], - "time": "2017-09-11 18:02:19" + "time": "2017-09-11T18:02:19+00:00" }, { "name": "phpdocumentor/reflection-docblock", @@ -2190,7 +2335,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-27 17:38:31" + "time": "2017-11-27T17:38:31+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -2237,7 +2382,7 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14 14:27:02" + "time": "2017-07-14T14:27:02+00:00" }, { "name": "phpspec/prophecy", @@ -2300,7 +2445,7 @@ "spy", "stub" ], - "time": "2017-11-24 13:59:53" + "time": "2017-11-24T13:59:53+00:00" }, { "name": "phpunit/php-code-coverage", @@ -2363,7 +2508,7 @@ "testing", "xunit" ], - "time": "2017-12-06 09:29:45" + "time": "2017-12-06T09:29:45+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2410,7 +2555,7 @@ "filesystem", "iterator" ], - "time": "2017-11-27 13:52:08" + "time": "2017-11-27T13:52:08+00:00" }, { "name": "phpunit/php-text-template", @@ -2451,7 +2596,7 @@ "keywords": [ "template" ], - "time": "2015-06-21 13:50:34" + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", @@ -2500,7 +2645,7 @@ "keywords": [ "timer" ], - "time": "2017-02-26 11:10:40" + "time": "2017-02-26T11:10:40+00:00" }, { "name": "phpunit/php-token-stream", @@ -2549,7 +2694,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27 05:48:46" + "time": "2017-11-27T05:48:46+00:00" }, { "name": "phpunit/phpunit", @@ -2633,7 +2778,7 @@ "testing", "xunit" ], - "time": "2017-12-17 06:31:19" + "time": "2017-12-17T06:31:19+00:00" }, { "name": "phpunit/phpunit-mock-objects", @@ -2692,7 +2837,7 @@ "mock", "xunit" ], - "time": "2018-01-06 05:45:45" + "time": "2018-01-06T05:45:45+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -2737,7 +2882,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04 06:30:41" + "time": "2017-03-04T06:30:41+00:00" }, { "name": "sebastian/comparator", @@ -2801,7 +2946,7 @@ "compare", "equality" ], - "time": "2017-12-22 14:50:35" + "time": "2017-12-22T14:50:35+00:00" }, { "name": "sebastian/diff", @@ -2853,7 +2998,7 @@ "keywords": [ "diff" ], - "time": "2017-08-03 08:09:46" + "time": "2017-08-03T08:09:46+00:00" }, { "name": "sebastian/environment", @@ -2903,7 +3048,7 @@ "environment", "hhvm" ], - "time": "2017-07-01 08:51:00" + "time": "2017-07-01T08:51:00+00:00" }, { "name": "sebastian/exporter", @@ -2970,7 +3115,7 @@ "export", "exporter" ], - "time": "2017-04-03 13:19:02" + "time": "2017-04-03T13:19:02+00:00" }, { "name": "sebastian/global-state", @@ -3021,7 +3166,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27 15:39:26" + "time": "2017-04-27T15:39:26+00:00" }, { "name": "sebastian/object-enumerator", @@ -3068,7 +3213,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03 12:35:26" + "time": "2017-08-03T12:35:26+00:00" }, { "name": "sebastian/object-reflector", @@ -3113,7 +3258,7 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29 09:07:27" + "time": "2017-03-29T09:07:27+00:00" }, { "name": "sebastian/recursion-context", @@ -3166,7 +3311,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03 06:23:57" + "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", @@ -3208,7 +3353,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28 20:34:47" + "time": "2015-07-28T20:34:47+00:00" }, { "name": "sebastian/version", @@ -3251,7 +3396,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03 07:35:21" + "time": "2016-10-03T07:35:21+00:00" }, { "name": "theseer/tokenizer", @@ -3291,7 +3436,7 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07 12:08:54" + "time": "2017-04-07T12:08:54+00:00" }, { "name": "webmozart/assert", @@ -3341,7 +3486,7 @@ "check", "validate" ], - "time": "2016-11-23 20:04:58" + "time": "2016-11-23T20:04:58+00:00" } ], "aliases": [], diff --git a/core/lib/composer/vendor/autoload.php b/core/lib/composer/vendor/autoload.php index bc3afe3d..863746d9 100644 --- a/core/lib/composer/vendor/autoload.php +++ b/core/lib/composer/vendor/autoload.php @@ -2,6 +2,6 @@ // autoload.php @generated by Composer -require_once __DIR__ . '/composer' . '/autoload_real.php'; +require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInit6d4a28cd96a5bc5d5b97781c062572d9::getLoader(); diff --git a/core/lib/composer/vendor/bin/export-plural-rules b/core/lib/composer/vendor/bin/export-plural-rules deleted file mode 120000 index d727a051..00000000 --- a/core/lib/composer/vendor/bin/export-plural-rules +++ /dev/null @@ -1 +0,0 @@ -../gettext/languages/bin/export-plural-rules \ No newline at end of file diff --git a/core/lib/composer/vendor/bin/export-plural-rules b/core/lib/composer/vendor/bin/export-plural-rules new file mode 100755 index 00000000..e246599c --- /dev/null +++ b/core/lib/composer/vendor/bin/export-plural-rules @@ -0,0 +1,4 @@ +#!/usr/bin/env php + Enviro::$outputUSAscii)); + } else { + echo call_user_func(array(Exporter::getExporterClassName(Enviro::$outputFormat), 'toString'), $languages, array('us-ascii' => Enviro::$outputUSAscii)); + } +} catch (Exception $x) { + Enviro::echoErr($x->getMessage()."\n"); + Enviro::echoErr("Trace:\n"); + Enviro::echoErr($x->getTraceAsString()."\n"); + die(4); +} + +die(0); + +/** + * Helper class to handle command line options. + */ +class Enviro +{ + /** + * Shall the output contain only US-ASCII characters? + * @var bool + */ + public static $outputUSAscii; + /** + * The output format. + * @var string + */ + public static $outputFormat; + /** + * Output file name. + * @var string + */ + public static $outputFilename; + /** + * List of wanted language IDs; it not set: all languages will be returned. + * @var array|null + */ + public static $languages; + /** + * Reduce the language list to the minimum common denominator. + * @var bool + */ + public static $reduce; + /** + * Parse the command line options. + */ + public static function initialize() + { + global $argv; + self::$outputUSAscii = false; + self::$outputFormat = null; + self::$outputFilename = null; + self::$languages = null; + self::$reduce = null; + $exporters = Exporter::getExporters(); + if (isset($argv) && is_array($argv)) { + foreach ($argv as $argi => $arg) { + if ($argi === 0) { + continue; + } + if (is_string($arg)) { + $argLC = trim(strtolower($arg)); + switch ($argLC) { + case '--us-ascii': + self::$outputUSAscii = true; + break; + case '--reduce=yes': + self::$reduce = true; + break; + case '--reduce=no': + self::$reduce = false; + break; + default: + if (preg_match('/^--output=.+$/', $argLC)) { + if (isset(self::$outputFilename)) { + self::echoErr("The output file name has been specified more than once!\n"); + self::showSyntax(); + die(3); + } + list(, self::$outputFilename) = explode('=', $arg, 2); + self::$outputFilename = trim(self::$outputFilename); + } elseif (preg_match('/^--languages?=.+$/', $argLC)) { + list(, $s) = explode('=', $arg, 2); + $list = explode(',', $s); + if (is_array(self::$languages)) { + self::$languages = array_merge(self::$languages, $list); + } else { + self::$languages = $list; + } + } elseif (isset($exporters[$argLC])) { + if (isset(self::$outputFormat)) { + self::echoErr("The output format has been specified more than once!\n"); + self::showSyntax(); + die(3); + } + self::$outputFormat = $argLC; + } else { + self::echoErr("Unknown option: $arg\n"); + self::showSyntax(); + die(2); + } + break; + } + } + } + } + if (!isset(self::$outputFormat)) { + self::showSyntax(); + die(1); + } + if (isset(self::$languages)) { + self::$languages = array_values(array_unique(self::$languages)); + } + if (!isset(self::$reduce)) { + self::$reduce = isset(self::$languages) ? false : true; + } + } + + /** + * Write out the syntax. + */ + public static function showSyntax() + { + $exporters = array_keys(Exporter::getExporters(true)); + self::echoErr("Syntax: php ".basename(__FILE__)." [--us-ascii] [--languages=[,,...]] [--reduce=yes|no] [--output=] <".implode('|', $exporters).">\n"); + self::echoErr("Where:\n"); + self::echoErr("--us-ascii : if specified, the output will contain only US-ASCII characters.\n"); + self::echoErr("--languages: (or --language) export only the specified language codes.\n"); + self::echoErr(" Separate languages with commas; you can also use this argument\n"); + self::echoErr(" more than once; it's case insensitive and accepts both '_' and\n"); + self::echoErr(" '-' as locale chunks separator (eg we accept 'it_IT' as well as\n"); + self::echoErr(" 'it-it').\n"); + self::echoErr("--reduce : if set to yes the output won't contain languages with the same\n"); + self::echoErr(" base language and rules.\n For instance nl_BE ('Flemish') will be\n"); + self::echoErr(" omitted because it's the same as nl ('Dutch').\n"); + self::echoErr(" Defaults to 'no' --languages is specified, to 'yes' otherwise.\n"); + self::echoErr("--output : if specified, the output will be saved to . If not\n"); + self::echoErr(" specified we'll output to standard output.\n"); + self::echoErr("Output formats\n"); + $len = max(array_map('strlen', $exporters)); + foreach ($exporters as $exporter) { + self::echoErr(str_pad($exporter, $len).": ".Exporter::getExporterDescription($exporter)."\n"); + } + } + /** + * Print a string to stderr. + * @param string $str The string to be printed out. + */ + public static function echoErr($str) + { + $hStdErr = @fopen('php://stderr', 'a'); + if ($hStdErr === false) { + echo $str; + } else { + fwrite($hStdErr, $str); + fclose($hStdErr); + } + } + /** + * Reduce a language list to the minimum common denominator. + * @param Language[] $languages + * @return Language[] + */ + public static function reduce($languages) + { + for ($numChunks = 3; $numChunks >= 2; $numChunks--) { + $filtered = array(); + foreach ($languages as $language) { + $chunks = explode('_', $language->id); + $compatibleFound = false; + if (count($chunks) === $numChunks) { + $categoriesHash = serialize($language->categories); + $otherIds = array(); + $otherIds[] = $chunks[0]; + for ($k = 2; $k < $numChunks; $k++) { + $otherIds[] = $chunks[0].'_'.$chunks[$numChunks - 1]; + } + + foreach ($languages as $check) { + foreach ($otherIds as $otherId) { + if (($check->id === $otherId) && ($check->formula === $language->formula) && (serialize($check->categories) === $categoriesHash)) { + $compatibleFound = true; + break; + } + } + if ($compatibleFound === true) { + break; + } + } + } + if (!$compatibleFound) { + $filtered[] = $language; + } + } + $languages = $filtered; + } + + return $languages; + } +} diff --git a/core/lib/composer/vendor/bin/markdown b/core/lib/composer/vendor/bin/markdown new file mode 100755 index 00000000..f8893e05 --- /dev/null +++ b/core/lib/composer/vendor/bin/markdown @@ -0,0 +1,170 @@ +#!/usr/bin/env php + ['cebe\\markdown\\GithubMarkdown', __DIR__ . '/../GithubMarkdown.php'], + 'extra' => ['cebe\\markdown\\MarkdownExtra', __DIR__ . '/../MarkdownExtra.php'], +]; + +$full = false; +$src = []; +foreach($argv as $k => $arg) { + if ($k == 0) { + continue; + } + if ($arg[0] == '-') { + $arg = explode('=', $arg); + switch($arg[0]) { + case '--flavor': + if (isset($arg[1])) { + if (isset($flavors[$arg[1]])) { + require($flavors[$arg[1]][1]); + $flavor = $flavors[$arg[1]][0]; + } else { + error("Unknown flavor: " . $arg[1], "usage"); + } + } else { + error("Incomplete argument --flavor!", "usage"); + } + break; + case '--full': + $full = true; + break; + case '-h': + case '--help': + echo "PHP Markdown to HTML converter\n"; + echo "------------------------------\n\n"; + echo "by Carsten Brandt \n\n"; + usage(); + break; + default: + error("Unknown argument " . $arg[0], "usage"); + } + } else { + $src[] = $arg; + } +} + +if (empty($src)) { + $markdown = file_get_contents("php://stdin"); +} elseif (count($src) == 1) { + $file = reset($src); + if (!file_exists($file)) { + error("File does not exist:" . $file); + } + $markdown = file_get_contents($file); +} else { + error("Converting multiple files is not yet supported.", "usage"); +} + +/** @var cebe\markdown\Parser $md */ +$md = new $flavor(); +$markup = $md->parse($markdown); + +if ($full) { + echo << + + + + + + +$markup + + +HTML; +} else { + echo $markup; +} + +// functions + +/** + * Display usage information + */ +function usage() { + global $argv; + $cmd = $argv[0]; + echo <<] [--full] [file.md] + + --flavor specifies the markdown flavor to use. If omitted the original markdown by John Gruber [1] will be used. + Available flavors: + + gfm - Github flavored markdown [2] + extra - Markdown Extra [3] + + --full ouput a full HTML page with head and body. If not given, only the parsed markdown will be output. + + --help shows this usage information. + + If no file is specified input will be read from STDIN. + +Examples: + + Render a file with original markdown: + + $cmd README.md > README.html + + Render a file using gihtub flavored markdown: + + $cmd --flavor=gfm README.md > README.html + + Convert the original markdown description to html using STDIN: + + curl http://daringfireball.net/projects/markdown/syntax.text | $cmd > md.html + + +[1] http://daringfireball.net/projects/markdown/syntax +[2] https://help.github.com/articles/github-flavored-markdown +[3] http://michelf.ca/projects/php-markdown/extra/ + +EOF; + exit(1); +} + +/** + * Send custom error message to stderr + * @param $message string + * @param $callback mixed called before script exit + * @return void + */ +function error($message, $callback = null) { + $fe = fopen("php://stderr", "w"); + fwrite($fe, "Error: " . $message . "\n"); + + if (is_callable($callback)) { + call_user_func($callback); + } + + exit(1); +} diff --git a/core/lib/composer/vendor/bin/phpunit b/core/lib/composer/vendor/bin/phpunit deleted file mode 120000 index 2c489303..00000000 --- a/core/lib/composer/vendor/bin/phpunit +++ /dev/null @@ -1 +0,0 @@ -../phpunit/phpunit/phpunit \ No newline at end of file diff --git a/core/lib/composer/vendor/bin/phpunit b/core/lib/composer/vendor/bin/phpunit new file mode 100755 index 00000000..8271fa34 --- /dev/null +++ b/core/lib/composer/vendor/bin/phpunit @@ -0,0 +1,53 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (version_compare('7.0.0', PHP_VERSION, '>')) { + fwrite( + STDERR, + sprintf( + 'This version of PHPUnit is supported on PHP 7.0 and PHP 7.1.' . PHP_EOL . + 'You are using PHP %s (%s).' . PHP_EOL, + PHP_VERSION, + PHP_BINARY + ) + ); + + die(1); +} + +if (!ini_get('date.timezone')) { + ini_set('date.timezone', 'UTC'); +} + +foreach (array(__DIR__ . '/../../autoload.php', __DIR__ . '/../vendor/autoload.php', __DIR__ . '/vendor/autoload.php') as $file) { + if (file_exists($file)) { + define('PHPUNIT_COMPOSER_INSTALL', $file); + + break; + } +} + +unset($file); + +if (!defined('PHPUNIT_COMPOSER_INSTALL')) { + fwrite( + STDERR, + 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL . + ' composer install' . PHP_EOL . PHP_EOL . + 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL + ); + + die(1); +} + +require PHPUNIT_COMPOSER_INSTALL; + +PHPUnit\TextUI\Command::main(); diff --git a/core/lib/composer/vendor/bin/robo b/core/lib/composer/vendor/bin/robo deleted file mode 120000 index 701d42dd..00000000 --- a/core/lib/composer/vendor/bin/robo +++ /dev/null @@ -1 +0,0 @@ -../consolidation/robo/robo \ No newline at end of file diff --git a/core/lib/composer/vendor/bin/robo b/core/lib/composer/vendor/bin/robo new file mode 100755 index 00000000..2093bd11 --- /dev/null +++ b/core/lib/composer/vendor/bin/robo @@ -0,0 +1,22 @@ +#!/usr/bin/env php +setSelfUpdateRepository('consolidation/robo'); +$statusCode = $runner->execute($_SERVER['argv']); +exit($statusCode); diff --git a/core/lib/composer/vendor/cebe/markdown/.gitattributes b/core/lib/composer/vendor/cebe/markdown/.gitattributes new file mode 100644 index 00000000..57b46266 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/.gitattributes @@ -0,0 +1,6 @@ +* text=auto + +/.gitattributes +/.gitignore +/.scrutinizer.yml +/.travis.yml diff --git a/core/lib/composer/vendor/cebe/markdown/.gitignore b/core/lib/composer/vendor/cebe/markdown/.gitignore new file mode 100644 index 00000000..669d0be2 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/.gitignore @@ -0,0 +1,4 @@ +/.idea/ +composer.lock +/vendor +README.html diff --git a/core/lib/composer/vendor/cebe/markdown/.scrutinizer.yml b/core/lib/composer/vendor/cebe/markdown/.scrutinizer.yml new file mode 100644 index 00000000..74122b0f --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/.scrutinizer.yml @@ -0,0 +1,6 @@ +imports: + - php + +tools: + external_code_coverage: + timeout: 600 # Timeout in seconds. \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/.travis.yml b/core/lib/composer/vendor/cebe/markdown/.travis.yml new file mode 100644 index 00000000..8670037b --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/.travis.yml @@ -0,0 +1,42 @@ +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - nightly + - hhvm + +# faster builds on new travis setup not using sudo +sudo: false + +# travis does not support HHVM on other platforms, choosing trusty +dist: trusty + +# cache composer cache +cache: + directories: + - $HOME/.composer/cache + +# run build against hhvm but allow them to fail +# http://docs.travis-ci.com/user/build-configuration/#Rows-That-are-Allowed-To-Fail +matrix: + fast_finish: true + allow_failures: + - php: nightly + +install: + - composer self-update && composer --version + - composer install --prefer-dist + +script: + - vendor/bin/phpunit --verbose --coverage-clover=coverage.clover +# test against standard markdown spec +# - git clone https://github.com/jgm/stmd && cd stmd && perl runtests.pl spec.txt ../bin/markdown + +after_script: + - wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover coverage.clover diff --git a/core/lib/composer/vendor/cebe/markdown/CHANGELOG.md b/core/lib/composer/vendor/cebe/markdown/CHANGELOG.md new file mode 100644 index 00000000..742cbbf7 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/CHANGELOG.md @@ -0,0 +1,104 @@ +CHANGELOG +========= + +Version 1.2.1 on 26. Mar. 2018 +------------------------------ + +- Improved handling of inline HTML with URL and email tags. +- Improved handling of custom syntax with `[[`, references should not use `[` as the first character in the reference name. + +Version 1.2.0 on 14. Mar. 2018 +------------------------------ + +- #50 Do not render empty emphs. +- #69 Improve ABSY for tables, make column and row information directly available in absy (@NathanBaulch) +- #89 Lists should be separated by a HR (@bieleckim) +- #95 Added `TableTrait::composeTable($head, $body)`, for easier overriding of table layout (@maximal, @cebe) +- #111 Improve rendering of successive strongs (@wogsland) +- #132 Improve detection and rendering of fenced code blocks in lists. +- #134 Fix Emph and Strong to allow escaping `*` or `_` inside them. +- #135 GithubMarkdown was not parsing inline code when there are square brackets around it. +- #151 Fixed table rendering for lines begining with | for GFM (@GenaBitu) +- Improved table rendering, allow single column tables. + +Version 1.1.2 on 16. Jul 2017 +----------------------------- + +- #126 Fixed crash on empty lines that extend a lazy list +- #128 Fix table renderer which including default alignment (@tanakahisateru) +- #129 Use given encoded URL if decoded URL text looks insecure, e.g. uses broken UTF-8 (@tanakahisateru) +- Added a workaround for a [PHP bug](https://bugs.php.net/bug.php?id=45735) which exists in versions `<` 7.0, where `preg_match()` causes a segfault + on [catastropic backtracking][] in emph/strong parsing. + +[catastropic backtracking]: http://www.regular-expressions.info/catastrophic.html + +Version 1.1.1 on 14. Sep 2016 +----------------------------- + +- #112 Fixed parsing for custom self-closing HTML tags +- #113 improve extensibility by making `prepareMarkers()` protected and add `parseBlock()` method +- #114 better handling of continued inline HTML in paragraphs + +Version 1.1.0 on 06. Mar. 2015 +------------------------------ + +- improve compatibility with github flavored markdown +- #64 fixed some rendering issue with emph and strong +- #56 trailing and leading spaces in a link are now ignored +- fixed various issues with table rendering +- #98 Fix PHP fatal error when maximumNestingLevel was reached (@tanakahisateru) +- refactored nested and lazy list handling, improved overall list rendering consistency +- Lines containing "0" where skipped or considered empty in some cases (@tanakahisateru) +- #54 escape characters are now also considered inside of urls + +Version 1.0.1 on 25. Oct. 2014 +------------------------------ + +- Fixed the `bin/markdown` script to work with composer autoloader (c497bada0e15f61873ba6b2e29f4bb8b3ef2a489) +- #74 fixed a bug that caused a bunch of broken characters when non-ASCII input was given. Parser now handles UTF-8 input correctly. Other encodings are currently untested, UTF-8 is recommended. + +Version 1.0.0 on 12. Oct. 2014 +------------------------------ + +This is the first stable release of version 1.0 which is incompatible to the 0.9.x branch regarding the internal API which is used when extending the Markdown parser. The external API has no breaking changes. The rendered Markdown however has changed in some edge cases and some rendering issues have been fixed. + +The parser got a bit slower compared to earlier versions but is able to parse Markdown more accurately and uses an abstract syntax tree as the internal representation of the parsed text which allows extensions to work with the parsed Markdown in many ways including rendering as other formats than HTML. + +For more details about the changes see the [release message of 1.0.0-rc](https://github.com/cebe/markdown/releases/tag/1.0.0-rc). + +You can try it out on the website: + +The parser is now also regsitered on the [Babelmark 2 page](http://johnmacfarlane.net/babelmark2/?normalize=1&text=Hello+**World**!) by [John MacFarlane](http://johnmacfarlane.net/) which you can use to compare Markdown output of different parsers. + +Version 1.0.0-rc on 10. Oct. 2014 +--------------------------------- + +- #21 speed up inline parsing using [strpbrk](http://www.php.net/manual/de/function.strpbrk.php) about 20% speedup compared to parsing before. +- #24 CLI script now sends all error output to stderr instead of stdout +- #25 Added partial support for the Markdown Extra flavor +- #10 GithubMarkdown is now fully supported including tables +- #67 All Markdown classes are now composed out of php traits +- #67 The way to extend markdown has changed due to the introduction of an abstract syntax tree. See https://github.com/cebe/markdown/commit/dd2d0faa71b630e982d6651476872469b927db6d for how it changes or read the new README. +- Introduced an abstract syntax tree as an intermediate representation between parsing steps. + This not only fixes some issues with nested block elements but also allows manipulation of the markdown + before rendering. +- This version also fixes serveral rendering issues. + +Version 0.9.2 on 18. Feb. 2014 +------------------------------ + +- #27 Fixed some rendering problems with block elements not separated by newlines + +Version 0.9.1 on 18. Feb. 2014 +------------------------------ + +Fixed an issue with inline markers that begin with the same character e.g. `[` and `[[`. + +Version 0.9.0 on 18. Feb. 2014 +------------------------------ + +The initial release. + +- Complete implementation of the original Markdown spec +- GFM without tables +- a command line tool for markdown parsing diff --git a/core/lib/composer/vendor/cebe/markdown/CONTRIBUTING.md b/core/lib/composer/vendor/cebe/markdown/CONTRIBUTING.md new file mode 100644 index 00000000..986f153c --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/CONTRIBUTING.md @@ -0,0 +1,36 @@ +Contributing +============ + +First of all, **thank you** for contributing, **you are awesome**! :) + +If you have an idea or found a bug, please [open an issue](https://github.com/cebe/markdown/issues/new) on github. + +If you want to contribute code, there a few rules to follow: + +- I am following a code style that is basically [PSR-2](http://www.php-fig.org/psr/2/) but with TABS indentation (yes, I really do that ;) ). + I am not going to nit-pick on all the details about the code style but indentation is a must. The important part is that code is readable. + Methods should be documented using phpdoc style. + +- All code must be covered by tests so if you fix a bug or add a feature, please include a test case for it. See below on how that works. + +- If you add a feature it should be documented. + +- Also, while creating your Pull Request on GitHub, please write a description + which gives the context and/or explains why you are creating it. + +Thank you very much! + + +Running the tests +----------------- + +The Markdown parser classes are tested with [PHPUnit](https://phpunit.de/). For each test case there is a set of files in +the subfolders of the `/tests` folder. The result of the parser is tested with an input and an output file respectively +where the input file contains the Markdown and the output file contains the expected HTML. + +You can run the tests after initializing the lib with composer(`composer install`) with the following command: + + vendor/bin/phpunit + +To create a new test case, create a `.md` file a`.html` with the same base name in the subfolders of +the `/tests` directory. See existing files for examples. diff --git a/core/lib/composer/vendor/cebe/markdown/GithubMarkdown.php b/core/lib/composer/vendor/cebe/markdown/GithubMarkdown.php new file mode 100644 index 00000000..23c9d1ad --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/GithubMarkdown.php @@ -0,0 +1,114 @@ + + */ +class GithubMarkdown extends Markdown +{ + // include block element parsing using traits + use block\TableTrait; + use block\FencedCodeTrait; + + // include inline element parsing using traits + use inline\StrikeoutTrait; + use inline\UrlLinkTrait; + + /** + * @var boolean whether to interpret newlines as `
`-tags. + * This feature is useful for comments where newlines are often meant to be real new lines. + */ + public $enableNewlines = false; + + /** + * @inheritDoc + */ + protected $escapeCharacters = [ + // from Markdown + '\\', // backslash + '`', // backtick + '*', // asterisk + '_', // underscore + '{', '}', // curly braces + '[', ']', // square brackets + '(', ')', // parentheses + '#', // hash mark + '+', // plus sign + '-', // minus sign (hyphen) + '.', // dot + '!', // exclamation mark + '<', '>', + // added by GithubMarkdown + ':', // colon + '|', // pipe + ]; + + + + /** + * Consume lines for a paragraph + * + * Allow headlines, lists and code to break paragraphs + */ + protected function consumeParagraph($lines, $current) + { + // consume until newline + $content = []; + for ($i = $current, $count = count($lines); $i < $count; $i++) { + $line = $lines[$i]; + if ($line === '' + || ltrim($line) === '' + || !ctype_alpha($line[0]) && ( + $this->identifyQuote($line, $lines, $i) || + $this->identifyFencedCode($line, $lines, $i) || + $this->identifyUl($line, $lines, $i) || + $this->identifyOl($line, $lines, $i) || + $this->identifyHr($line, $lines, $i) + ) + || $this->identifyHeadline($line, $lines, $i)) + { + break; + } elseif ($this->identifyCode($line, $lines, $i)) { + // possible beginning of a code block + // but check for continued inline HTML + // e.g. some alt aligned with src attribute + if (preg_match('~<\w+([^>]+)$~s', implode("\n", $content))) { + $content[] = $line; + } else { + break; + } + } else { + $content[] = $line; + } + } + $block = [ + 'paragraph', + 'content' => $this->parseInline(implode("\n", $content)), + ]; + return [$block, --$i]; + } + + /** + * @inheritdocs + * + * Parses a newline indicated by two spaces on the end of a markdown line. + */ + protected function renderText($text) + { + if ($this->enableNewlines) { + $br = $this->html5 ? "
\n" : "
\n"; + return strtr($text[1], [" \n" => $br, "\n" => $br]); + } else { + return parent::renderText($text); + } + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/LICENSE b/core/lib/composer/vendor/cebe/markdown/LICENSE new file mode 100644 index 00000000..acc225d6 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Carsten Brandt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/Markdown.php b/core/lib/composer/vendor/cebe/markdown/Markdown.php new file mode 100644 index 00000000..32c9b0f4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/Markdown.php @@ -0,0 +1,128 @@ + + */ +class Markdown extends Parser +{ + // include block element parsing using traits + use block\CodeTrait; + use block\HeadlineTrait; + use block\HtmlTrait { + parseInlineHtml as private; + } + use block\ListTrait { + // Check Ul List before headline + identifyUl as protected identifyBUl; + consumeUl as protected consumeBUl; + } + use block\QuoteTrait; + use block\RuleTrait { + // Check Hr before checking lists + identifyHr as protected identifyAHr; + consumeHr as protected consumeAHr; + } + + // include inline element parsing using traits + use inline\CodeTrait; + use inline\EmphStrongTrait; + use inline\LinkTrait; + + /** + * @var boolean whether to format markup according to HTML5 spec. + * Defaults to `false` which means that markup is formatted as HTML4. + */ + public $html5 = false; + + /** + * @var array these are "escapeable" characters. When using one of these prefixed with a + * backslash, the character will be outputted without the backslash and is not interpreted + * as markdown. + */ + protected $escapeCharacters = [ + '\\', // backslash + '`', // backtick + '*', // asterisk + '_', // underscore + '{', '}', // curly braces + '[', ']', // square brackets + '(', ')', // parentheses + '#', // hash mark + '+', // plus sign + '-', // minus sign (hyphen) + '.', // dot + '!', // exclamation mark + '<', '>', + ]; + + + /** + * @inheritDoc + */ + protected function prepare() + { + // reset references + $this->references = []; + } + + /** + * Consume lines for a paragraph + * + * Allow headlines and code to break paragraphs + */ + protected function consumeParagraph($lines, $current) + { + // consume until newline + $content = []; + for ($i = $current, $count = count($lines); $i < $count; $i++) { + $line = $lines[$i]; + + // a list may break a paragraph when it is inside of a list + if (isset($this->context[1]) && $this->context[1] === 'list' && !ctype_alpha($line[0]) && ( + $this->identifyUl($line, $lines, $i) || $this->identifyOl($line, $lines, $i))) { + break; + } + + if ($line === '' || ltrim($line) === '' || $this->identifyHeadline($line, $lines, $i)) { + break; + } elseif ($line[0] === "\t" || $line[0] === " " && strncmp($line, ' ', 4) === 0) { + // possible beginning of a code block + // but check for continued inline HTML + // e.g. some alt aligned with src attribute + if (preg_match('~<\w+([^>]+)$~s', implode("\n", $content))) { + $content[] = $line; + } else { + break; + } + } else { + $content[] = $line; + } + } + $block = [ + 'paragraph', + 'content' => $this->parseInline(implode("\n", $content)), + ]; + return [$block, --$i]; + } + + + /** + * @inheritdocs + * + * Parses a newline indicated by two spaces on the end of a markdown line. + */ + protected function renderText($text) + { + return str_replace(" \n", $this->html5 ? "
\n" : "
\n", $text[1]); + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/MarkdownExtra.php b/core/lib/composer/vendor/cebe/markdown/MarkdownExtra.php new file mode 100644 index 00000000..eedcf778 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/MarkdownExtra.php @@ -0,0 +1,256 @@ + + * @license https://github.com/cebe/markdown/blob/master/LICENSE + * @link https://github.com/cebe/markdown#readme + */ +class MarkdownExtra extends Markdown +{ + // include block element parsing using traits + use block\TableTrait; + use block\FencedCodeTrait; + + // include inline element parsing using traits + // TODO + + /** + * @var bool whether special attributes on code blocks should be applied on the `
` element.
+	 * The default behavior is to put them on the `` element.
+	 */
+	public $codeAttributesOnPre = false;
+
+	/**
+	 * @inheritDoc
+	 */
+	protected $escapeCharacters = [
+		// from Markdown
+		'\\', // backslash
+		'`', // backtick
+		'*', // asterisk
+		'_', // underscore
+		'{', '}', // curly braces
+		'[', ']', // square brackets
+		'(', ')', // parentheses
+		'#', // hash mark
+		'+', // plus sign
+		'-', // minus sign (hyphen)
+		'.', // dot
+		'!', // exclamation mark
+		'<', '>',
+		// added by MarkdownExtra
+		':', // colon
+		'|', // pipe
+	];
+
+	private $_specialAttributesRegex = '\{(([#\.][A-z0-9-_]+\s*)+)\}';
+
+	// TODO allow HTML intended 3 spaces
+
+	// TODO add markdown inside HTML blocks
+
+	// TODO implement definition lists
+
+	// TODO implement footnotes
+
+	// TODO implement Abbreviations
+
+
+	// block parsing
+
+	protected function identifyReference($line)
+	{
+		return ($line[0] === ' ' || $line[0] === '[') && preg_match('/^ {0,3}\[[^\[](.*?)\]:\s*([^\s]+?)(?:\s+[\'"](.+?)[\'"])?\s*('.$this->_specialAttributesRegex.')?\s*$/', $line);
+	}
+
+	/**
+	 * Consume link references
+	 */
+	protected function consumeReference($lines, $current)
+	{
+		while (isset($lines[$current]) && preg_match('/^ {0,3}\[(.+?)\]:\s*(.+?)(?:\s+[\(\'"](.+?)[\)\'"])?\s*('.$this->_specialAttributesRegex.')?\s*$/', $lines[$current], $matches)) {
+			$label = strtolower($matches[1]);
+
+			$this->references[$label] = [
+				'url' => $this->replaceEscape($matches[2]),
+			];
+			if (isset($matches[3])) {
+				$this->references[$label]['title'] = $matches[3];
+			} else {
+				// title may be on the next line
+				if (isset($lines[$current + 1]) && preg_match('/^\s+[\(\'"](.+?)[\)\'"]\s*$/', $lines[$current + 1], $matches)) {
+					$this->references[$label]['title'] = $matches[1];
+					$current++;
+				}
+			}
+			if (isset($matches[5])) {
+				$this->references[$label]['attributes'] = $matches[5];
+			}
+			$current++;
+		}
+		return [false, --$current];
+	}
+
+	/**
+	 * Consume lines for a fenced code block
+	 */
+	protected function consumeFencedCode($lines, $current)
+	{
+		// consume until ```
+		$block = [
+			'code',
+		];
+		$line = trim($lines[$current]);
+		if (($pos = strrpos($line, '`')) === false) {
+			$pos = strrpos($line, '~');
+		}
+		$fence = substr($line, 0, $pos + 1);
+		$block['attributes'] = substr($line, $pos);
+		$content = [];
+		for($i = $current + 1, $count = count($lines); $i < $count; $i++) {
+			if (($pos = strpos($line = $lines[$i], $fence)) === false || $pos > 3) {
+				$content[] = $line;
+			} else {
+				break;
+			}
+		}
+		$block['content'] = implode("\n", $content);
+		return [$block, $i];
+	}
+
+	protected function renderCode($block)
+	{
+		$attributes = $this->renderAttributes($block);
+		return ($this->codeAttributesOnPre ? "" : "
")
+			. htmlspecialchars($block['content'] . "\n", ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8')
+			. "
\n"; + } + + /** + * Renders a headline + */ + protected function renderHeadline($block) + { + foreach($block['content'] as $i => $element) { + if ($element[0] === 'specialAttributes') { + unset($block['content'][$i]); + $block['attributes'] = $element[1]; + } + } + $tag = 'h' . $block['level']; + $attributes = $this->renderAttributes($block); + return "<$tag$attributes>" . rtrim($this->renderAbsy($block['content']), "# \t") . "\n"; + } + + protected function renderAttributes($block) + { + $html = []; + if (isset($block['attributes'])) { + $attributes = preg_split('/\s+/', $block['attributes'], -1, PREG_SPLIT_NO_EMPTY); + foreach($attributes as $attribute) { + if ($attribute[0] === '#') { + $html['id'] = substr($attribute, 1); + } else { + $html['class'][] = substr($attribute, 1); + } + } + } + $result = ''; + foreach($html as $attr => $value) { + if (is_array($value)) { + $value = trim(implode(' ', $value)); + } + if (!empty($value)) { + $result .= " $attr=\"$value\""; + } + } + return $result; + } + + + // inline parsing + + + /** + * @marker { + */ + protected function parseSpecialAttributes($text) + { + if (preg_match("~$this->_specialAttributesRegex~", $text, $matches)) { + return [['specialAttributes', $matches[1]], strlen($matches[0])]; + } + return [['text', '{'], 1]; + } + + protected function renderSpecialAttributes($block) + { + return '{' . $block[1] . '}'; + } + + protected function parseInline($text) + { + $elements = parent::parseInline($text); + // merge special attribute elements to links and images as they are not part of the final absy later + $relatedElement = null; + foreach($elements as $i => $element) { + if ($element[0] === 'link' || $element[0] === 'image') { + $relatedElement = $i; + } elseif ($element[0] === 'specialAttributes') { + if ($relatedElement !== null) { + $elements[$relatedElement]['attributes'] = $element[1]; + unset($elements[$i]); + } + $relatedElement = null; + } else { + $relatedElement = null; + } + } + return $elements; + } + + protected function renderLink($block) + { + if (isset($block['refkey'])) { + if (($ref = $this->lookupReference($block['refkey'])) !== false) { + $block = array_merge($block, $ref); + } else { + if (strncmp($block['orig'], '[', 1) === 0) { + return '[' . $this->renderAbsy($this->parseInline(substr($block['orig'], 1))); + } + return $block['orig']; + } + } + $attributes = $this->renderAttributes($block); + return '' . $this->renderAbsy($block['text']) . ''; + } + + protected function renderImage($block) + { + if (isset($block['refkey'])) { + if (($ref = $this->lookupReference($block['refkey'])) !== false) { + $block = array_merge($block, $ref); + } else { + if (strncmp($block['orig'], '![', 2) === 0) { + return '![' . $this->renderAbsy($this->parseInline(substr($block['orig'], 2))); + } + return $block['orig']; + } + } + $attributes = $this->renderAttributes($block); + return '' . htmlspecialchars($block['text'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE, 'UTF-8') . 'html5 ? '>' : ' />'); + } +} \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/Parser.php b/core/lib/composer/vendor/cebe/markdown/Parser.php new file mode 100644 index 00000000..9103582c --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/Parser.php @@ -0,0 +1,389 @@ + + */ +abstract class Parser +{ + /** + * @var integer the maximum nesting level for language elements. + */ + public $maximumNestingLevel = 32; + + /** + * @var array the current context the parser is in. + * TODO remove in favor of absy + */ + protected $context = []; + /** + * @var array these are "escapeable" characters. When using one of these prefixed with a + * backslash, the character will be outputted without the backslash and is not interpreted + * as markdown. + */ + protected $escapeCharacters = [ + '\\', // backslash + ]; + + private $_depth = 0; + + + /** + * Parses the given text considering the full language. + * + * This includes parsing block elements as well as inline elements. + * + * @param string $text the text to parse + * @return string parsed markup + */ + public function parse($text) + { + $this->prepare(); + + if (ltrim($text) === '') { + return ''; + } + + $text = str_replace(["\r\n", "\n\r", "\r"], "\n", $text); + + $this->prepareMarkers($text); + + $absy = $this->parseBlocks(explode("\n", $text)); + $markup = $this->renderAbsy($absy); + + $this->cleanup(); + return $markup; + } + + /** + * Parses a paragraph without block elements (block elements are ignored). + * + * @param string $text the text to parse + * @return string parsed markup + */ + public function parseParagraph($text) + { + $this->prepare(); + + if (ltrim($text) === '') { + return ''; + } + + $text = str_replace(["\r\n", "\n\r", "\r"], "\n", $text); + + $this->prepareMarkers($text); + + $absy = $this->parseInline($text); + $markup = $this->renderAbsy($absy); + + $this->cleanup(); + return $markup; + } + + /** + * This method will be called before `parse()` and `parseParagraph()`. + * You can override it to do some initialization work. + */ + protected function prepare() + { + } + + /** + * This method will be called after `parse()` and `parseParagraph()`. + * You can override it to do cleanup. + */ + protected function cleanup() + { + } + + + // block parsing + + private $_blockTypes; + + /** + * @return array a list of block element types available. + */ + protected function blockTypes() + { + if ($this->_blockTypes === null) { + // detect block types via "identify" functions + $reflection = new \ReflectionClass($this); + $this->_blockTypes = array_filter(array_map(function($method) { + $name = $method->getName(); + return strncmp($name, 'identify', 8) === 0 ? strtolower(substr($name, 8)) : false; + }, $reflection->getMethods(ReflectionMethod::IS_PROTECTED))); + + sort($this->_blockTypes); + } + return $this->_blockTypes; + } + + /** + * Given a set of lines and an index of a current line it uses the registed block types to + * detect the type of this line. + * @param array $lines + * @param integer $current + * @return string name of the block type in lower case + */ + protected function detectLineType($lines, $current) + { + $line = $lines[$current]; + $blockTypes = $this->blockTypes(); + foreach($blockTypes as $blockType) { + if ($this->{'identify' . $blockType}($line, $lines, $current)) { + return $blockType; + } + } + // consider the line a normal paragraph if no other block type matches + return 'paragraph'; + } + + /** + * Parse block elements by calling `detectLineType()` to identify them + * and call consume function afterwards. + */ + protected function parseBlocks($lines) + { + if ($this->_depth >= $this->maximumNestingLevel) { + // maximum depth is reached, do not parse input + return [['text', implode("\n", $lines)]]; + } + $this->_depth++; + + $blocks = []; + + // convert lines to blocks + for ($i = 0, $count = count($lines); $i < $count; $i++) { + $line = $lines[$i]; + if ($line !== '' && rtrim($line) !== '') { // skip empty lines + // identify a blocks beginning and parse the content + list($block, $i) = $this->parseBlock($lines, $i); + if ($block !== false) { + $blocks[] = $block; + } + } + } + + $this->_depth--; + + return $blocks; + } + + /** + * Parses the block at current line by identifying the block type and parsing the content + * @param $lines + * @param $current + * @return array Array of two elements, the first element contains the block, + * the second contains the next line index to be parsed. + */ + protected function parseBlock($lines, $current) + { + // identify block type for this line + $blockType = $this->detectLineType($lines, $current); + + // call consume method for the detected block type to consume further lines + return $this->{'consume' . $blockType}($lines, $current); + } + + protected function renderAbsy($blocks) + { + $output = ''; + foreach ($blocks as $block) { + array_unshift($this->context, $block[0]); + $output .= $this->{'render' . $block[0]}($block); + array_shift($this->context); + } + return $output; + } + + /** + * Consume lines for a paragraph + * + * @param $lines + * @param $current + * @return array + */ + protected function consumeParagraph($lines, $current) + { + // consume until newline + $content = []; + for ($i = $current, $count = count($lines); $i < $count; $i++) { + if (ltrim($lines[$i]) !== '') { + $content[] = $lines[$i]; + } else { + break; + } + } + $block = [ + 'paragraph', + 'content' => $this->parseInline(implode("\n", $content)), + ]; + return [$block, --$i]; + } + + /** + * Render a paragraph block + * + * @param $block + * @return string + */ + protected function renderParagraph($block) + { + return '

' . $this->renderAbsy($block['content']) . "

\n"; + } + + + // inline parsing + + + /** + * @var array the set of inline markers to use in different contexts. + */ + private $_inlineMarkers = []; + + /** + * Returns a map of inline markers to the corresponding parser methods. + * + * This array defines handler methods for inline markdown markers. + * When a marker is found in the text, the handler method is called with the text + * starting at the position of the marker. + * + * Note that markers starting with whitespace may slow down the parser, + * you may want to use [[renderText]] to deal with them. + * + * You may override this method to define a set of markers and parsing methods. + * The default implementation looks for protected methods starting with `parse` that + * also have an `@marker` annotation in PHPDoc. + * + * @return array a map of markers to parser methods + */ + protected function inlineMarkers() + { + $markers = []; + // detect "parse" functions + $reflection = new \ReflectionClass($this); + foreach($reflection->getMethods(ReflectionMethod::IS_PROTECTED) as $method) { + $methodName = $method->getName(); + if (strncmp($methodName, 'parse', 5) === 0) { + preg_match_all('/@marker ([^\s]+)/', $method->getDocComment(), $matches); + foreach($matches[1] as $match) { + $markers[$match] = $methodName; + } + } + } + return $markers; + } + + /** + * Prepare markers that are used in the text to parse + * + * Add all markers that are present in markdown. + * Check is done to avoid iterations in parseInline(), good for huge markdown files + * @param string $text + */ + protected function prepareMarkers($text) + { + $this->_inlineMarkers = []; + foreach ($this->inlineMarkers() as $marker => $method) { + if (strpos($text, $marker) !== false) { + $m = $marker[0]; + // put the longest marker first + if (isset($this->_inlineMarkers[$m])) { + reset($this->_inlineMarkers[$m]); + if (strlen($marker) > strlen(key($this->_inlineMarkers[$m]))) { + $this->_inlineMarkers[$m] = array_merge([$marker => $method], $this->_inlineMarkers[$m]); + continue; + } + } + $this->_inlineMarkers[$m][$marker] = $method; + } + } + } + + /** + * Parses inline elements of the language. + * + * @param string $text the inline text to parse. + * @return array + */ + protected function parseInline($text) + { + if ($this->_depth >= $this->maximumNestingLevel) { + // maximum depth is reached, do not parse input + return [['text', $text]]; + } + $this->_depth++; + + $markers = implode('', array_keys($this->_inlineMarkers)); + + $paragraph = []; + + while (!empty($markers) && ($found = strpbrk($text, $markers)) !== false) { + + $pos = strpos($text, $found); + + // add the text up to next marker to the paragraph + if ($pos !== 0) { + $paragraph[] = ['text', substr($text, 0, $pos)]; + } + $text = $found; + + $parsed = false; + foreach ($this->_inlineMarkers[$text[0]] as $marker => $method) { + if (strncmp($text, $marker, strlen($marker)) === 0) { + // parse the marker + array_unshift($this->context, $method); + list($output, $offset) = $this->$method($text); + array_shift($this->context); + + $paragraph[] = $output; + $text = substr($text, $offset); + $parsed = true; + break; + } + } + if (!$parsed) { + $paragraph[] = ['text', substr($text, 0, 1)]; + $text = substr($text, 1); + } + } + + $paragraph[] = ['text', $text]; + + $this->_depth--; + + return $paragraph; + } + + /** + * Parses escaped special characters. + * @marker \ + */ + protected function parseEscape($text) + { + if (isset($text[1]) && in_array($text[1], $this->escapeCharacters)) { + return [['text', $text[1]], 2]; + } + return [['text', $text[0]], 1]; + } + + /** + * This function renders plain text sections in the markdown text. + * It can be used to work on normal text sections for example to highlight keywords or + * do special escaping. + */ + protected function renderText($block) + { + return $block[1]; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/README.md b/core/lib/composer/vendor/cebe/markdown/README.md new file mode 100644 index 00000000..c4347b46 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/README.md @@ -0,0 +1,521 @@ +A super fast, highly extensible markdown parser for PHP +======================================================= + +[![Latest Stable Version](https://poser.pugx.org/cebe/markdown/v/stable.png)](https://packagist.org/packages/cebe/markdown) +[![Total Downloads](https://poser.pugx.org/cebe/markdown/downloads.png)](https://packagist.org/packages/cebe/markdown) +[![Build Status](https://travis-ci.org/cebe/markdown.svg?branch=master)](http://travis-ci.org/cebe/markdown) +[![Code Coverage](https://scrutinizer-ci.com/g/cebe/markdown/badges/coverage.png?s=db6af342d55bea649307ef311fbd536abb9bab76)](https://scrutinizer-ci.com/g/cebe/markdown/) +[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/cebe/markdown/badges/quality-score.png?s=17448ca4d140429fd687c58ff747baeb6568d528)](https://scrutinizer-ci.com/g/cebe/markdown/) + +What is this? +------------- + +A set of [PHP][] classes, each representing a [Markdown][] flavor, and a command line tool +for converting markdown files to HTML files. + +The implementation focus is to be **fast** (see [benchmark][]) and **extensible**. +Parsing Markdown to HTML is as simple as calling a single method (see [Usage](#usage)) providing a solid implementation +that gives most expected results even in non-trivial edge cases. + +Extending the Markdown language with new elements is as simple as adding a new method to the class that converts the +markdown text to the expected output in HTML. This is possible without dealing with complex and error prone regular expressions. +It is also possible to hook into the markdown structure and add elements or read meta information using the internal representation +of the Markdown text as an abstract syntax tree (see [Extending the language](#extend)). + +Currently the following markdown flavors are supported: + +- **Traditional Markdown** according to ([try it!](http://markdown.cebe.cc/try?flavor=default)). +- **Github flavored Markdown** according to ([try it!](http://markdown.cebe.cc/try?flavor=gfm)). +- **Markdown Extra** according to (currently not fully supported WIP see [#25][], [try it!](http://markdown.cebe.cc/try?flavor=extra)) +- Any mixed Markdown flavor you like because of its highly extensible structure (See documentation below). + +Future plans are to support: + +- Smarty Pants +- ... (Feel free to [suggest](https://github.com/cebe/markdown/issues/new) further additions!) + +[PHP]: http://php.net/ "PHP is a popular general-purpose scripting language that is especially suited to web development." +[Markdown]: http://en.wikipedia.org/wiki/Markdown "Markdown on Wikipedia" +[#25]: https://github.com/cebe/markdown/issues/25 "issue #25" +[benchmark]: https://github.com/kzykhys/Markbench#readme "kzykhys/Markbench on github" + +### Who is using it? + +- It powers the [API-docs and the definitive guide](http://www.yiiframework.com/doc-2.0/) for the [Yii Framework][] [2.0](https://github.com/yiisoft/yii2). + +[Yii Framework]: http://www.yiiframework.com/ "The Yii PHP Framework" + + +Installation +------------ + +[PHP 5.4 or higher](http://www.php.net/downloads.php) is required to use it. +It will also run on facebook's [hhvm](http://hhvm.com/). + +The library uses PHPDoc annotations to determine the markdown elements that should be parsed. +So in case you are using PHP `opcache`, make sure +[it does not strip comments](http://php.net/manual/en/opcache.configuration.php#ini.opcache.save-comments). + +Installation is recommended to be done via [composer][] by running: + + composer require cebe/markdown "~1.2.0" + +Alternatively you can add the following to the `require` section in your `composer.json` manually: + +```json +"cebe/markdown": "~1.2.0" +``` + +Run `composer update` afterwards. + +[composer]: https://getcomposer.org/ "The PHP package manager" + +> Note: If you have configured PHP with opcache you need to enable the +> [opcache.save_comments](http://php.net/manual/en/opcache.configuration.php#ini.opcache.save-comments) option because inline element parsing relies on PHPdoc annotations to find declared elements. + +Usage +----- + +### In your PHP project + +To parse your markdown you need only two lines of code. The first one is to choose the markdown flavor as +one of the following: + +- Traditional Markdown: `$parser = new \cebe\markdown\Markdown();` +- Github Flavored Markdown: `$parser = new \cebe\markdown\GithubMarkdown();` +- Markdown Extra: `$parser = new \cebe\markdown\MarkdownExtra();` + +The next step is to call the `parse()`-method for parsing the text using the full markdown language +or calling the `parseParagraph()`-method to parse only inline elements. + +Here are some examples: + +```php +// traditional markdown and parse full text +$parser = new \cebe\markdown\Markdown(); +echo $parser->parse($markdown); + +// use github markdown +$parser = new \cebe\markdown\GithubMarkdown(); +echo $parser->parse($markdown); + +// use markdown extra +$parser = new \cebe\markdown\MarkdownExtra(); +echo $parser->parse($markdown); + +// parse only inline elements (useful for one-line descriptions) +$parser = new \cebe\markdown\GithubMarkdown(); +echo $parser->parseParagraph($markdown); +``` + +You may optionally set one of the following options on the parser object: + +For all Markdown Flavors: + +- `$parser->html5 = true` to enable HTML5 output instead of HTML4. +- `$parser->keepListStartNumber = true` to enable keeping the numbers of ordered lists as specified in the markdown. + The default behavior is to always start from 1 and increment by one regardless of the number in markdown. + +For GithubMarkdown: + +- `$parser->enableNewlines = true` to convert all newlines to `
`-tags. By default only newlines with two preceding spaces are converted to `
`-tags. + +It is recommended to use UTF-8 encoding for the input strings. Other encodings may work, but are currently untested. + +### The command line script + +You can use it to render this readme: + + bin/markdown README.md > README.html + +Using github flavored markdown: + + bin/markdown --flavor=gfm README.md > README.html + +or convert the original markdown description to html using the unix pipe: + + curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown > md.html + +Here is the full Help output you will see when running `bin/markdown --help`: + + PHP Markdown to HTML converter + ------------------------------ + + by Carsten Brandt + + Usage: + bin/markdown [--flavor=] [--full] [file.md] + + --flavor specifies the markdown flavor to use. If omitted the original markdown by John Gruber [1] will be used. + Available flavors: + + gfm - Github flavored markdown [2] + extra - Markdown Extra [3] + + --full ouput a full HTML page with head and body. If not given, only the parsed markdown will be output. + + --help shows this usage information. + + If no file is specified input will be read from STDIN. + + Examples: + + Render a file with original markdown: + + bin/markdown README.md > README.html + + Render a file using gihtub flavored markdown: + + bin/markdown --flavor=gfm README.md > README.html + + Convert the original markdown description to html using STDIN: + + curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown > md.html + + + [1] http://daringfireball.net/projects/markdown/syntax + [2] https://help.github.com/articles/github-flavored-markdown + [3] http://michelf.ca/projects/php-markdown/extra/ + + +Extensions +---------- + +Here are some extensions to this library: + +- [Bogardo/markdown-codepen](https://github.com/Bogardo/markdown-codepen) - shortcode to embed codepens from http://codepen.io/ in markdown. +- [kartik-v/yii2-markdown](https://github.com/kartik-v/yii2-markdown) - Advanced Markdown editing and conversion utilities for Yii Framework 2.0. +- [cebe/markdown-latex](https://github.com/cebe/markdown-latex) - Convert Markdown to LaTeX and PDF +- [softark/creole](https://github.com/softark/creole) - A creole markup parser +- [hyn/frontmatter](https://github.com/hyn/frontmatter) - Frontmatter Metadata Support (JSON, TOML, YAML) +- ... [add yours!](https://github.com/cebe/markdown/edit/master/README.md#L186) + + +Extending the language +---------------------- + +Markdown consists of two types of language elements, I'll call them block and inline elements simlar to what you have in +HTML with `
` and ``. Block elements are normally spreads over several lines and are separated by blank lines. +The most basic block element is a paragraph (`

`). +Inline elements are elements that are added inside of block elements i.e. inside of text. + +This markdown parser allows you to extend the markdown language by changing existing elements behavior and also adding +new block and inline elements. You do this by extending from the parser class and adding/overriding class methods and +properties. For the different element types there are different ways to extend them as you will see in the following sections. + +### Adding block elements + +The markdown is parsed line by line to identify each non-empty line as one of the block element types. +To identify a line as the beginning of a block element it calls all protected class methods who's name begins with `identify`. +An identify function returns true if it has identified the block element it is responsible for or false if not. +In the following example we will implement support for [fenced code blocks][] which are part of the github flavored markdown. + +[fenced code blocks]: https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks + "Fenced code block feature of github flavored markdown" + +```php + [], + ]; + $line = rtrim($lines[$current]); + + // detect language and fence length (can be more than 3 backticks) + $fence = substr($line, 0, $pos = strrpos($line, '`') + 1); + $language = substr($line, $pos); + if (!empty($language)) { + $block['language'] = $language; + } + + // consume all lines until ``` + for($i = $current + 1, $count = count($lines); $i < $count; $i++) { + if (rtrim($line = $lines[$i]) !== $fence) { + $block['content'][] = $line; + } else { + // stop consuming when code block is over + break; + } + } + return [$block, $i]; + } + ``` + +2. **Rendering** the element. After all blocks have been consumed, they are being rendered using the + `render{elementName}()`-method where `elementName` refers to the name of the element in the abstract syntax tree: + + ```php + protected function renderFencedCode($block) + { + $class = isset($block['language']) ? ' class="language-' . $block['language'] . '"' : ''; + return "

" . htmlspecialchars(implode("\n", $block['content']) . "\n", ENT_NOQUOTES, 'UTF-8') . '
'; + } + ``` + + You may also add code highlighting here. In general it would also be possible to render ouput in a different language than + HTML for example LaTeX. + + +### Adding inline elements + +Adding inline elements is different from block elements as they are parsed using markers in the text. +An inline element is identified by a marker that marks the beginning of an inline element (e.g. `[` will mark a possible +beginning of a link or `` ` `` will mark inline code). + +Parsing methods for inline elements are also protected and identified by the prefix `parse`. Additionally a `@marker` annotation +in PHPDoc is needed to register the parse function for one or multiple markers. +The method will then be called when a marker is found in the text. As an argument it takes the text starting at the position of the marker. +The parser method will return an array containing the element of the abstract sytnax tree and an offset of text it has +parsed from the input markdown. All text up to this offset will be removed from the markdown before the next marker will be searched. + +As an example, we will add support for the [strikethrough][] feature of github flavored markdown: + +[strikethrough]: https://help.github.com/articles/github-flavored-markdown#strikethrough "Strikethrough feature of github flavored markdown" + +```php +parseInline($matches[1])], + // return the offset of the parsed text + strlen($matches[0]) + ]; + } + // in case we did not find a closing ~~ we just return the marker and skip 2 characters + return [['text', '~~'], 2]; + } + + // rendering is the same as for block elements, we turn the abstract syntax array into a string. + protected function renderStrike($element) + { + return '' . $this->renderAbsy($element[1]) . ''; + } +} +``` + +### Composing your own Markdown flavor + +This markdown library is composed of traits so it is very easy to create your own markdown flavor by adding and/or removing +the single feature traits. + +Designing your Markdown flavor consists of four steps: + +1. Select a base class +2. Select language feature traits +3. Define escapeable characters +4. Optionally add custom rendering behavior + +#### Select a base class + +If you want to extend from a flavor and only add features you can use one of the existing classes +(`Markdown`, `GithubMarkdown` or `MarkdownExtra`) as your flavors base class. + +If you want to define a subset of the markdown language, i.e. remove some of the features, you have to +extend your class from `Parser`. + +#### Select language feature traits + +The following shows the trait selection for traditional Markdown. + +```php +class MyMarkdown extends Parser +{ + // include block element parsing using traits + use block\CodeTrait; + use block\HeadlineTrait; + use block\HtmlTrait { + parseInlineHtml as private; + } + use block\ListTrait { + // Check Ul List before headline + identifyUl as protected identifyBUl; + consumeUl as protected consumeBUl; + } + use block\QuoteTrait; + use block\RuleTrait { + // Check Hr before checking lists + identifyHr as protected identifyAHr; + consumeHr as protected consumeAHr; + } + // include inline element parsing using traits + use inline\CodeTrait; + use inline\EmphStrongTrait; + use inline\LinkTrait; + + /** + * @var boolean whether to format markup according to HTML5 spec. + * Defaults to `false` which means that markup is formatted as HTML4. + */ + public $html5 = false; + + protected function prepare() + { + // reset references + $this->references = []; + } + + // ... +} +``` + +In general, just adding the trait with `use` is enough, however in some cases some fine tuning is desired +to get most expected parsing results. Elements are detected in alphabetical order of their identification +function. This means that if a line starting with `-` could be a list or a horizontal rule, the preference has to be set +by renaming the identification function. This is what is done with renaming `identifyHr` to `identifyAHr` +and `identifyBUl` to `identifyBUl`. The consume function always has to have the same name as the identification function +so this has to be renamed too. + +There is also a conflict for parsing of the `<` character. This could either be a link/email enclosed in `<` and `>` +or an inline HTML tag. In order to resolve this conflict when adding the `LinkTrait`, we need to hide the `parseInlineHtml` +method of the `HtmlTrait`. + +If you use any trait that uses the `$html5` property to adjust its output you also need to define this property. + +If you use the link trait it may be useful to implement `prepare()` as shown above to reset references before +parsing to ensure you get a reusable object. + +#### Define escapeable characters + +Depending on the language features you have chosen there is a different set of characters that can be escaped +using `\`. The following is the set of escapeable characters for traditional markdown, you can copy it to your class +as is. + +```php + /** + * @var array these are "escapeable" characters. When using one of these prefixed with a + * backslash, the character will be outputted without the backslash and is not interpreted + * as markdown. + */ + protected $escapeCharacters = [ + '\\', // backslash + '`', // backtick + '*', // asterisk + '_', // underscore + '{', '}', // curly braces + '[', ']', // square brackets + '(', ')', // parentheses + '#', // hash mark + '+', // plus sign + '-', // minus sign (hyphen) + '.', // dot + '!', // exclamation mark + '<', '>', + ]; +``` + +#### Add custom rendering behavior + +Optionally you may also want to adjust rendering behavior by overriding some methods. +You may refer to the `consumeParagraph()` method of the `Markdown` and `GithubMarkdown` classes for some inspiration +which define different rules for which elements are allowed to interrupt a paragraph. + + +Acknowledgements +---------------- + +I'd like to thank [@erusev][] for creating [Parsedown][] which heavily influenced this work and provided +the idea of the line based parsing approach. + +[@erusev]: https://github.com/erusev "Emanuil Rusev" +[Parsedown]: http://parsedown.org/ "The Parsedown PHP Markdown parser" + +FAQ +--- + +### Why another markdown parser? + +While reviewing PHP markdown parsers for choosing one to use bundled with the [Yii framework 2.0][] +I found that most of the implementations use regex to replace patterns instead +of doing real parsing. This way extending them with new language elements is quite hard +as you have to come up with a complex regex, that matches your addition but does not mess +with other elements. Such additions are very common as you see on github which supports referencing +issues, users and commits in the comments. +A [real parser][] should use context aware methods that walk trough the text and +parse the tokens as they find them. The only implentation that I have found that uses +this approach is [Parsedown][] which also shows that this implementation is [much faster][benchmark] +than the regex way. Parsedown however is an implementation that focuses on speed and implements +its own flavor (mainly github flavored markdown) in one class and at the time of this writing was +not easily extensible. + +Given the situation above I decided to start my own implementation using the parsing approach +from Parsedown and making it extensible creating a class for each markdown flavor that extend each +other in the way that also the markdown languages extend each other. +This allows you to choose between markdown language flavors and also provides a way to compose your +own flavor picking the best things from all. +I chose this approach as it is easier to implement and also more intuitive approach compared +to using callbacks to inject functionallity into the parser. + +[real parser]: http://en.wikipedia.org/wiki/Parsing#Types_of_parser + +[Parsedown]: http://parsedown.org/ "The Parsedown PHP Markdown parser" + +[Yii framework 2.0]: https://github.com/yiisoft/yii2 + +### Where do I report bugs or rendering issues? + +Just [open an issue][] on github, post your markdown code and describe the problem. You may also attach screenshots of the rendered HTML result to describe your problem. + +[open an issue]: https://github.com/cebe/markdown/issues/new + +### How can I contribute to this library? + +Check the [CONTRIBUTING.md](CONTRIBUTING.md) file for more info. + + +### Am I free to use this? + +This library is open source and licensed under the [MIT License][]. This means that you can do whatever you want +with it as long as you mention my name and include the [license file][license]. Check the [license][] for details. + +[MIT License]: http://opensource.org/licenses/MIT + +[license]: https://github.com/cebe/markdown/blob/master/LICENSE + +Contact +------- + +Feel free to contact me using [email](mailto:mail@cebe.cc) or [twitter](https://twitter.com/cebe_cc). diff --git a/core/lib/composer/vendor/cebe/markdown/bin/markdown b/core/lib/composer/vendor/cebe/markdown/bin/markdown new file mode 100755 index 00000000..f8893e05 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/bin/markdown @@ -0,0 +1,170 @@ +#!/usr/bin/env php + ['cebe\\markdown\\GithubMarkdown', __DIR__ . '/../GithubMarkdown.php'], + 'extra' => ['cebe\\markdown\\MarkdownExtra', __DIR__ . '/../MarkdownExtra.php'], +]; + +$full = false; +$src = []; +foreach($argv as $k => $arg) { + if ($k == 0) { + continue; + } + if ($arg[0] == '-') { + $arg = explode('=', $arg); + switch($arg[0]) { + case '--flavor': + if (isset($arg[1])) { + if (isset($flavors[$arg[1]])) { + require($flavors[$arg[1]][1]); + $flavor = $flavors[$arg[1]][0]; + } else { + error("Unknown flavor: " . $arg[1], "usage"); + } + } else { + error("Incomplete argument --flavor!", "usage"); + } + break; + case '--full': + $full = true; + break; + case '-h': + case '--help': + echo "PHP Markdown to HTML converter\n"; + echo "------------------------------\n\n"; + echo "by Carsten Brandt \n\n"; + usage(); + break; + default: + error("Unknown argument " . $arg[0], "usage"); + } + } else { + $src[] = $arg; + } +} + +if (empty($src)) { + $markdown = file_get_contents("php://stdin"); +} elseif (count($src) == 1) { + $file = reset($src); + if (!file_exists($file)) { + error("File does not exist:" . $file); + } + $markdown = file_get_contents($file); +} else { + error("Converting multiple files is not yet supported.", "usage"); +} + +/** @var cebe\markdown\Parser $md */ +$md = new $flavor(); +$markup = $md->parse($markdown); + +if ($full) { + echo << + + + + + + +$markup + + +HTML; +} else { + echo $markup; +} + +// functions + +/** + * Display usage information + */ +function usage() { + global $argv; + $cmd = $argv[0]; + echo <<] [--full] [file.md] + + --flavor specifies the markdown flavor to use. If omitted the original markdown by John Gruber [1] will be used. + Available flavors: + + gfm - Github flavored markdown [2] + extra - Markdown Extra [3] + + --full ouput a full HTML page with head and body. If not given, only the parsed markdown will be output. + + --help shows this usage information. + + If no file is specified input will be read from STDIN. + +Examples: + + Render a file with original markdown: + + $cmd README.md > README.html + + Render a file using gihtub flavored markdown: + + $cmd --flavor=gfm README.md > README.html + + Convert the original markdown description to html using STDIN: + + curl http://daringfireball.net/projects/markdown/syntax.text | $cmd > md.html + + +[1] http://daringfireball.net/projects/markdown/syntax +[2] https://help.github.com/articles/github-flavored-markdown +[3] http://michelf.ca/projects/php-markdown/extra/ + +EOF; + exit(1); +} + +/** + * Send custom error message to stderr + * @param $message string + * @param $callback mixed called before script exit + * @return void + */ +function error($message, $callback = null) { + $fe = fopen("php://stderr", "w"); + fwrite($fe, "Error: " . $message . "\n"); + + if (is_callable($callback)) { + call_user_func($callback); + } + + exit(1); +} diff --git a/core/lib/composer/vendor/cebe/markdown/block/CodeTrait.php b/core/lib/composer/vendor/cebe/markdown/block/CodeTrait.php new file mode 100644 index 00000000..2457ece4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/block/CodeTrait.php @@ -0,0 +1,66 @@ += 4 or one tab is code + return ($l = $line[0]) === ' ' && $line[1] === ' ' && $line[2] === ' ' && $line[3] === ' ' || $l === "\t"; + } + + /** + * Consume lines for a code block element + */ + protected function consumeCode($lines, $current) + { + // consume until newline + + $content = []; + for ($i = $current, $count = count($lines); $i < $count; $i++) { + $line = $lines[$i]; + + // a line is considered to belong to this code block as long as it is intended by 4 spaces or a tab + if (isset($line[0]) && ($line[0] === "\t" || strncmp($line, ' ', 4) === 0)) { + $line = $line[0] === "\t" ? substr($line, 1) : substr($line, 4); + $content[] = $line; + // but also if it is empty and the next line is intended by 4 spaces or a tab + } elseif (($line === '' || rtrim($line) === '') && isset($lines[$i + 1][0]) && + ($lines[$i + 1][0] === "\t" || strncmp($lines[$i + 1], ' ', 4) === 0)) { + if ($line !== '') { + $line = $line[0] === "\t" ? substr($line, 1) : substr($line, 4); + } + $content[] = $line; + } else { + break; + } + } + + $block = [ + 'code', + 'content' => implode("\n", $content), + ]; + return [$block, --$i]; + } + + /** + * Renders a code block + */ + protected function renderCode($block) + { + $class = isset($block['language']) ? ' class="language-' . $block['language'] . '"' : ''; + return "
" . htmlspecialchars($block['content'] . "\n", ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8') . "
\n"; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/block/FencedCodeTrait.php b/core/lib/composer/vendor/cebe/markdown/block/FencedCodeTrait.php new file mode 100644 index 00000000..60efbc9b --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/block/FencedCodeTrait.php @@ -0,0 +1,58 @@ + 3) { + $content[] = $line; + } else { + break; + } + } + $block = [ + 'code', + 'content' => implode("\n", $content), + ]; + if (!empty($language)) { + $block['language'] = $language; + } + return [$block, $i]; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/block/HeadlineTrait.php b/core/lib/composer/vendor/cebe/markdown/block/HeadlineTrait.php new file mode 100644 index 00000000..efa7c5b5 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/block/HeadlineTrait.php @@ -0,0 +1,70 @@ + $this->parseInline(trim($lines[$current], "# \t")), + 'level' => $level, + ]; + return [$block, $current]; + } else { + // underlined headline + $block = [ + 'headline', + 'content' => $this->parseInline($lines[$current]), + 'level' => $lines[$current + 1][0] === '=' ? 1 : 2, + ]; + return [$block, $current + 1]; + } + } + + /** + * Renders a headline + */ + protected function renderHeadline($block) + { + $tag = 'h' . $block['level']; + return "<$tag>" . $this->renderAbsy($block['content']) . "\n"; + } + + abstract protected function parseInline($text); + abstract protected function renderAbsy($absy); +} diff --git a/core/lib/composer/vendor/cebe/markdown/block/HtmlTrait.php b/core/lib/composer/vendor/cebe/markdown/block/HtmlTrait.php new file mode 100644 index 00000000..2f15135e --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/block/HtmlTrait.php @@ -0,0 +1,168 @@ +'); + $spacePos = strpos($lines[$current], ' '); + if ($gtPos === false && $spacePos === false) { + return false; // no html tag + } elseif ($spacePos === false) { + $tag = rtrim(substr($line, 1, $gtPos - 1), '/'); + } else { + $tag = rtrim(substr($line, 1, min($gtPos, $spacePos) - 1), '/'); + } + + if (!ctype_alnum($tag) || in_array(strtolower($tag), $this->inlineHtmlElements)) { + return false; // no html tag or inline html tag + } + return true; + } + + /** + * Consume lines for an HTML block + */ + protected function consumeHtml($lines, $current) + { + $content = []; + if (strncmp($lines[$current], '') !== false) { + break; + } + } + } else { + $tag = rtrim(substr($lines[$current], 1, min(strpos($lines[$current], '>'), strpos($lines[$current] . ' ', ' ')) - 1), '/'); + $level = 0; + if (in_array($tag, $this->selfClosingHtmlElements)) { + $level--; + } + for ($i = $current, $count = count($lines); $i < $count; $i++) { + $line = $lines[$i]; + $content[] = $line; + $level += substr_count($line, "<$tag") - substr_count($line, "") - substr_count($line, "/>"); + if ($level <= 0) { + break; + } + } + } + $block = [ + 'html', + 'content' => implode("\n", $content), + ]; + return [$block, $i]; + } + + /** + * Renders an HTML block + */ + protected function renderHtml($block) + { + return $block['content'] . "\n"; + } + + /** + * Parses an & or a html entity definition. + * @marker & + */ + protected function parseEntity($text) + { + // html entities e.g. © © © + if (preg_match('/^&#?[\w\d]+;/', $text, $matches)) { + return [['inlineHtml', $matches[0]], strlen($matches[0])]; + } else { + return [['text', '&'], 1]; + } + } + + /** + * renders a html entity. + */ + protected function renderInlineHtml($block) + { + return $block[1]; + } + + /** + * Parses inline HTML. + * @marker < + */ + protected function parseInlineHtml($text) + { + if (strpos($text, '>') !== false) { + if (preg_match('~^~s', $text, $matches)) { + // HTML tags + return [['inlineHtml', $matches[0]], strlen($matches[0])]; + } elseif (preg_match('~^~s', $text, $matches)) { + // HTML comments + return [['inlineHtml', $matches[0]], strlen($matches[0])]; + } + } + return [['text', '<'], 1]; + } + + /** + * Escapes `>` characters. + * @marker > + */ + protected function parseGt($text) + { + return [['text', '>'], 1]; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/block/ListTrait.php b/core/lib/composer/vendor/cebe/markdown/block/ListTrait.php new file mode 100644 index 00000000..7e53a766 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/block/ListTrait.php @@ -0,0 +1,202 @@ +) starts with 1. + */ + public $keepListStartNumber = false; + + /** + * identify a line as the beginning of an ordered list. + */ + protected function identifyOl($line) + { + return (($l = $line[0]) > '0' && $l <= '9' || $l === ' ') && preg_match('/^ {0,3}\d+\.[ \t]/', $line); + } + + /** + * identify a line as the beginning of an unordered list. + */ + protected function identifyUl($line) + { + $l = $line[0]; + return ($l === '-' || $l === '+' || $l === '*') && (isset($line[1]) && (($l1 = $line[1]) === ' ' || $l1 === "\t")) || + ($l === ' ' && preg_match('/^ {0,3}[\-\+\*][ \t]/', $line)); + } + + /** + * Consume lines for an ordered list + */ + protected function consumeOl($lines, $current) + { + // consume until newline + + $block = [ + 'list', + 'list' => 'ol', + 'attr' => [], + 'items' => [], + ]; + return $this->consumeList($lines, $current, $block, 'ol'); + } + + /** + * Consume lines for an unordered list + */ + protected function consumeUl($lines, $current) + { + // consume until newline + + $block = [ + 'list', + 'list' => 'ul', + 'items' => [], + ]; + return $this->consumeList($lines, $current, $block, 'ul'); + } + + private function consumeList($lines, $current, $block, $type) + { + $item = 0; + $indent = ''; + $len = 0; + $lastLineEmpty = false; + // track the indentation of list markers, if indented more than previous element + // a list marker is considered to be long to a lower level + $leadSpace = 3; + $marker = $type === 'ul' ? ltrim($lines[$current])[0] : ''; + for ($i = $current, $count = count($lines); $i < $count; $i++) { + $line = $lines[$i]; + // match list marker on the beginning of the line + $pattern = ($type === 'ol') ? '/^( {0,'.$leadSpace.'})(\d+)\.[ \t]+/' : '/^( {0,'.$leadSpace.'})\\'.$marker.'[ \t]+/'; + if (preg_match($pattern, $line, $matches)) { + if (($len = substr_count($matches[0], "\t")) > 0) { + $indent = str_repeat("\t", $len); + $line = substr($line, strlen($matches[0])); + } else { + $len = strlen($matches[0]); + $indent = str_repeat(' ', $len); + $line = substr($line, $len); + } + if ($i === $current) { + $leadSpace = strlen($matches[1]) + 1; + } + + if ($type === 'ol' && $this->keepListStartNumber) { + // attr `start` for ol + if (!isset($block['attr']['start']) && isset($matches[2])) { + $block['attr']['start'] = $matches[2]; + } + } + + $block['items'][++$item][] = $line; + $block['lazyItems'][$item] = $lastLineEmpty; + $lastLineEmpty = false; + } elseif (ltrim($line) === '') { + // line is empty, may be a lazy list + $lastLineEmpty = true; + + // two empty lines will end the list + if (!isset($lines[$i + 1][0])) { + break; + + // next item is the continuation of this list -> lazy list + } elseif (preg_match($pattern, $lines[$i + 1])) { + $block['items'][$item][] = $line; + $block['lazyItems'][$item] = true; + + // next item is indented as much as this list -> lazy list if it is not a reference + } elseif (strncmp($lines[$i + 1], $indent, $len) === 0 || !empty($lines[$i + 1]) && $lines[$i + 1][0] == "\t") { + $block['items'][$item][] = $line; + $nextLine = $lines[$i + 1][0] === "\t" ? substr($lines[$i + 1], 1) : substr($lines[$i + 1], $len); + $block['lazyItems'][$item] = empty($nextLine) || !method_exists($this, 'identifyReference') || !$this->identifyReference($nextLine); + + // everything else ends the list + } else { + break; + } + } else { + if ($line[0] === "\t") { + $line = substr($line, 1); + } elseif (strncmp($line, $indent, $len) === 0) { + $line = substr($line, $len); + } + $block['items'][$item][] = $line; + $lastLineEmpty = false; + } + + // if next line is
, end the list + if (!empty($lines[$i + 1]) && method_exists($this, 'identifyHr') && $this->identifyHr($lines[$i + 1])) { + break; + } + } + + foreach($block['items'] as $itemId => $itemLines) { + $content = []; + if (!$block['lazyItems'][$itemId]) { + $firstPar = []; + while (!empty($itemLines) && rtrim($itemLines[0]) !== '' && $this->detectLineType($itemLines, 0) === 'paragraph') { + $firstPar[] = array_shift($itemLines); + } + $content = $this->parseInline(implode("\n", $firstPar)); + } + if (!empty($itemLines)) { + $content = array_merge($content, $this->parseBlocks($itemLines)); + } + $block['items'][$itemId] = $content; + } + + return [$block, $i]; + } + + /** + * Renders a list + */ + protected function renderList($block) + { + $type = $block['list']; + + if (!empty($block['attr'])) { + $output = "<$type " . $this->generateHtmlAttributes($block['attr']) . ">\n"; + } else { + $output = "<$type>\n"; + } + + foreach ($block['items'] as $item => $itemLines) { + $output .= '
  • ' . $this->renderAbsy($itemLines). "
  • \n"; + } + return $output . "\n"; + } + + + /** + * Return html attributes string from [attrName => attrValue] list + * @param array $attributes the attribute name-value pairs. + * @return string + */ + private function generateHtmlAttributes($attributes) + { + foreach ($attributes as $name => $value) { + $attributes[$name] = "$name=\"$value\""; + } + return implode(' ', $attributes); + } + + abstract protected function parseBlocks($lines); + abstract protected function parseInline($text); + abstract protected function renderAbsy($absy); + abstract protected function detectLineType($lines, $current); +} diff --git a/core/lib/composer/vendor/cebe/markdown/block/QuoteTrait.php b/core/lib/composer/vendor/cebe/markdown/block/QuoteTrait.php new file mode 100644 index 00000000..4040ddf8 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/block/QuoteTrait.php @@ -0,0 +1,63 @@ +' && (!isset($line[1]) || ($l1 = $line[1]) === ' ' || $l1 === "\t"); + } + + /** + * Consume lines for a blockquote element + */ + protected function consumeQuote($lines, $current) + { + // consume until newline + $content = []; + for ($i = $current, $count = count($lines); $i < $count; $i++) { + $line = $lines[$i]; + if (ltrim($line) !== '') { + if ($line[0] == '>' && !isset($line[1])) { + $line = ''; + } elseif (strncmp($line, '> ', 2) === 0) { + $line = substr($line, 2); + } + $content[] = $line; + } else { + break; + } + } + + $block = [ + 'quote', + 'content' => $this->parseBlocks($content), + 'simple' => true, + ]; + return [$block, $i]; + } + + + /** + * Renders a blockquote + */ + protected function renderQuote($block) + { + return '
    ' . $this->renderAbsy($block['content']) . "
    \n"; + } + + abstract protected function parseBlocks($lines); + abstract protected function renderAbsy($absy); +} diff --git a/core/lib/composer/vendor/cebe/markdown/block/RuleTrait.php b/core/lib/composer/vendor/cebe/markdown/block/RuleTrait.php new file mode 100644 index 00000000..26f4b700 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/block/RuleTrait.php @@ -0,0 +1,40 @@ +html5 ? "
    \n" : "
    \n"; + } + +} \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/block/TableTrait.php b/core/lib/composer/vendor/cebe/markdown/block/TableTrait.php new file mode 100644 index 00000000..9ca82670 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/block/TableTrait.php @@ -0,0 +1,156 @@ + [], + 'rows' => [], + ]; + for ($i = $current, $count = count($lines); $i < $count; $i++) { + $line = trim($lines[$i]); + + // extract alignment from second line + if ($i == $current+1) { + $cols = explode('|', trim($line, ' |')); + foreach($cols as $col) { + $col = trim($col); + if (empty($col)) { + $block['cols'][] = ''; + continue; + } + $l = ($col[0] === ':'); + $r = (substr($col, -1, 1) === ':'); + if ($l && $r) { + $block['cols'][] = 'center'; + } elseif ($l) { + $block['cols'][] = 'left'; + } elseif ($r) { + $block['cols'][] = 'right'; + } else { + $block['cols'][] = ''; + } + } + + continue; + } + if ($line === '' || substr($lines[$i], 0, 4) === ' ') { + break; + } + if ($line[0] === '|') { + $line = substr($line, 1); + } + if (substr($line, -1, 1) === '|' && (substr($line, -2, 2) !== '\\|' || substr($line, -3, 3) === '\\\\|')) { + $line = substr($line, 0, -1); + } + + array_unshift($this->context, 'table'); + $row = $this->parseInline($line); + array_shift($this->context); + + $r = count($block['rows']); + $c = 0; + $block['rows'][] = []; + foreach ($row as $absy) { + if (!isset($block['rows'][$r][$c])) { + $block['rows'][$r][] = []; + } + if ($absy[0] === 'tableBoundary') { + $c++; + } else { + $block['rows'][$r][$c][] = $absy; + } + } + } + + return [$block, --$i]; + } + + /** + * render a table block + */ + protected function renderTable($block) + { + $head = ''; + $body = ''; + $cols = $block['cols']; + $first = true; + foreach($block['rows'] as $row) { + $cellTag = $first ? 'th' : 'td'; + $tds = ''; + foreach ($row as $c => $cell) { + $align = empty($cols[$c]) ? '' : ' align="' . $cols[$c] . '"'; + $tds .= "<$cellTag$align>" . trim($this->renderAbsy($cell)) . ""; + } + if ($first) { + $head .= "$tds\n"; + } else { + $body .= "$tds\n"; + } + $first = false; + } + return $this->composeTable($head, $body); + } + + /** + * This method composes a table from parsed body and head HTML. + * + * You may override this method to customize the table rendering, for example by + * adding a `class` to the table tag: + * + * ```php + * return "\n\n$head\n\n$body\n
    \n" + * ``` + * + * @param string $head table head HTML. + * @param string $body table body HTML. + * @return string the complete table HTML. + * @since 1.2.0 + */ + protected function composeTable($head, $body) + { + return "\n\n$head\n\n$body\n
    \n"; + } + + /** + * @marker | + */ + protected function parseTd($markdown) + { + if (isset($this->context[1]) && $this->context[1] === 'table') { + return [['tableBoundary'], isset($markdown[1]) && $markdown[1] === ' ' ? 2 : 1]; + } + return [['text', $markdown[0]], 1]; + } + + abstract protected function parseInline($text); + abstract protected function renderAbsy($absy); +} diff --git a/core/lib/composer/vendor/cebe/markdown/composer.json b/core/lib/composer/vendor/cebe/markdown/composer.json new file mode 100644 index 00000000..6a3160e5 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/composer.json @@ -0,0 +1,42 @@ +{ + "name": "cebe/markdown", + "description": "A super fast, highly extensible markdown parser for PHP", + "keywords": ["markdown", "gfm", "markdown-extra", "fast", "extensible"], + "homepage": "https://github.com/cebe/markdown#readme", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Creator" + } + ], + "support": { + "issues": "https://github.com/cebe/markdown/issues", + "source": "https://github.com/cebe/markdown" + }, + "require": { + "php": ">=5.4.0", + "lib-pcre": "*" + }, + "require-dev": { + "phpunit/phpunit": "4.1.*", + "facebook/xhprof": "*@dev", + "cebe/indent": "*" + }, + "autoload": { + "psr-4": { + "cebe\\markdown\\": "" + } + }, + "bin": [ + "bin/markdown" + ], + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/inline/CodeTrait.php b/core/lib/composer/vendor/cebe/markdown/inline/CodeTrait.php new file mode 100644 index 00000000..63eb3ef4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/inline/CodeTrait.php @@ -0,0 +1,45 @@ +' . htmlspecialchars($block[1], ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8') . ''; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/inline/EmphStrongTrait.php b/core/lib/composer/vendor/cebe/markdown/inline/EmphStrongTrait.php new file mode 100644 index 00000000..ca919294 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/inline/EmphStrongTrait.php @@ -0,0 +1,87 @@ +\\\\[*]|[^*]|[*][^*]*[*])+?)[*]{2}/s', $text, $matches) || + $marker === '_' && preg_match('/^__((?>\\\\_|[^_]|_[^_]*_)+?)__/us', $text, $matches)) { + + return [ + [ + 'strong', + $this->parseInline($matches[1]), + ], + strlen($matches[0]) + ]; + } + } else { // emph + // work around a PHP bug that crashes with a segfault on too much regex backtrack + // check whether the end marker exists in the text + // https://github.com/erusev/parsedown/issues/443 + // https://bugs.php.net/bug.php?id=45735 + if (strpos($text, $marker, 1) === false) { + return [['text', $text[0]], 1]; + } + + if ($marker === '*' && preg_match('/^[*]((?>\\\\[*]|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*][^*])/s', $text, $matches) || + $marker === '_' && preg_match('/^_((?>\\\\_|[^_]|__[^_]*__)+?)_(?!_[^_])\b/us', $text, $matches)) { + // if only a single whitespace or nothing is contained in an emphasis, do not consider it valid + if ($matches[1] === '' || $matches[1] === ' ') { + return [['text', $text[0]], 1]; + } + return [ + [ + 'emph', + $this->parseInline($matches[1]), + ], + strlen($matches[0]) + ]; + } + } + return [['text', $text[0]], 1]; + } + + protected function renderStrong($block) + { + return '' . $this->renderAbsy($block[1]) . ''; + } + + protected function renderEmph($block) + { + return '' . $this->renderAbsy($block[1]) . ''; + } + + abstract protected function parseInline($text); + abstract protected function renderAbsy($blocks); +} diff --git a/core/lib/composer/vendor/cebe/markdown/inline/LinkTrait.php b/core/lib/composer/vendor/cebe/markdown/inline/LinkTrait.php new file mode 100644 index 00000000..bb6c45f4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/inline/LinkTrait.php @@ -0,0 +1,287 @@ +references = []; + * } + * ``` + */ +trait LinkTrait +{ + /** + * @var array a list of defined references in this document. + */ + protected $references = []; + + /** + * Remove backslash from escaped characters + * @param $text + * @return string + */ + protected function replaceEscape($text) + { + $strtr = []; + foreach($this->escapeCharacters as $char) { + $strtr["\\$char"] = $char; + } + return strtr($text, $strtr); + } + + /** + * Parses a link indicated by `[`. + * @marker [ + */ + protected function parseLink($markdown) + { + if (!in_array('parseLink', array_slice($this->context, 1)) && ($parts = $this->parseLinkOrImage($markdown)) !== false) { + list($text, $url, $title, $offset, $key) = $parts; + return [ + [ + 'link', + 'text' => $this->parseInline($text), + 'url' => $url, + 'title' => $title, + 'refkey' => $key, + 'orig' => substr($markdown, 0, $offset), + ], + $offset + ]; + } else { + // remove all starting [ markers to avoid next one to be parsed as link + $result = '['; + $i = 1; + while (isset($markdown[$i]) && $markdown[$i] === '[') { + $result .= '['; + $i++; + } + return [['text', $result], $i]; + } + } + + /** + * Parses an image indicated by `![`. + * @marker ![ + */ + protected function parseImage($markdown) + { + if (($parts = $this->parseLinkOrImage(substr($markdown, 1))) !== false) { + list($text, $url, $title, $offset, $key) = $parts; + + return [ + [ + 'image', + 'text' => $text, + 'url' => $url, + 'title' => $title, + 'refkey' => $key, + 'orig' => substr($markdown, 0, $offset + 1), + ], + $offset + 1 + ]; + } else { + // remove all starting [ markers to avoid next one to be parsed as link + $result = '!'; + $i = 1; + while (isset($markdown[$i]) && $markdown[$i] === '[') { + $result .= '['; + $i++; + } + return [['text', $result], $i]; + } + } + + protected function parseLinkOrImage($markdown) + { + if (strpos($markdown, ']') !== false && preg_match('/\[((?>[^\]\[]+|(?R))*)\]/', $markdown, $textMatches)) { // TODO improve bracket regex + $text = $textMatches[1]; + $offset = strlen($textMatches[0]); + $markdown = substr($markdown, $offset); + + $pattern = <<[^\s()]+)|(?R))*\) + | # else match a link with title + ^\(\s*(((?>[^\s()]+)|(?R))*)(\s+"(.*?)")?\s*\) + )/x +REGEXP; + if (preg_match($pattern, $markdown, $refMatches)) { + // inline link + return [ + $text, + isset($refMatches[2]) ? $this->replaceEscape($refMatches[2]) : '', // url + empty($refMatches[5]) ? null: $refMatches[5], // title + $offset + strlen($refMatches[0]), // offset + null, // reference key + ]; + } elseif (preg_match('/^([ \n]?\[(.*?)\])?/s', $markdown, $refMatches)) { + // reference style link + if (empty($refMatches[2])) { + $key = strtolower($text); + } else { + $key = strtolower($refMatches[2]); + } + return [ + $text, + null, // url + null, // title + $offset + strlen($refMatches[0]), // offset + $key, + ]; + } + } + return false; + } + + /** + * Parses inline HTML. + * @marker < + */ + protected function parseLt($text) + { + if (strpos($text, '>') !== false) { + if (!in_array('parseLink', $this->context)) { // do not allow links in links + if (preg_match('/^<([^\s>]*?@[^\s]*?\.\w+?)>/', $text, $matches)) { + // email address + return [ + ['email', $this->replaceEscape($matches[1])], + strlen($matches[0]) + ]; + } elseif (preg_match('/^<([a-z]{3,}:\/\/[^\s]+?)>/', $text, $matches)) { + // URL + return [ + ['url', $this->replaceEscape($matches[1])], + strlen($matches[0]) + ]; + } + } + // try inline HTML if it was neither a URL nor email if HtmlTrait is included. + if (method_exists($this, 'parseInlineHtml')) { + return $this->parseInlineHtml($text); + } + } + return [['text', '<'], 1]; + } + + protected function renderEmail($block) + { + $email = htmlspecialchars($block[1], ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8'); + return "$email"; + } + + protected function renderUrl($block) + { + $url = htmlspecialchars($block[1], ENT_COMPAT | ENT_HTML401, 'UTF-8'); + $decodedUrl = urldecode($block[1]); + $secureUrlText = preg_match('//u', $decodedUrl) ? $decodedUrl : $block[1]; + $text = htmlspecialchars($secureUrlText, ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8'); + return "$text"; + } + + protected function lookupReference($key) + { + $normalizedKey = preg_replace('/\s+/', ' ', $key); + if (isset($this->references[$key]) || isset($this->references[$key = $normalizedKey])) { + return $this->references[$key]; + } + return false; + } + + protected function renderLink($block) + { + if (isset($block['refkey'])) { + if (($ref = $this->lookupReference($block['refkey'])) !== false) { + $block = array_merge($block, $ref); + } else { + if (strncmp($block['orig'], '[', 1) === 0) { + return '[' . $this->renderAbsy($this->parseInline(substr($block['orig'], 1))); + } + return $block['orig']; + } + } + return '' . $this->renderAbsy($block['text']) . ''; + } + + protected function renderImage($block) + { + if (isset($block['refkey'])) { + if (($ref = $this->lookupReference($block['refkey'])) !== false) { + $block = array_merge($block, $ref); + } else { + if (strncmp($block['orig'], '![', 2) === 0) { + return '![' . $this->renderAbsy($this->parseInline(substr($block['orig'], 2))); + } + return $block['orig']; + } + } + return '' . htmlspecialchars($block['text'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE, 'UTF-8') . 'html5 ? '>' : ' />'); + } + + // references + + protected function identifyReference($line) + { + return isset($line[0]) && ($line[0] === ' ' || $line[0] === '[') && preg_match('/^ {0,3}\[[^\[](.*?)\]:\s*([^\s]+?)(?:\s+[\'"](.+?)[\'"])?\s*$/', $line); + } + + /** + * Consume link references + */ + protected function consumeReference($lines, $current) + { + while (isset($lines[$current]) && preg_match('/^ {0,3}\[(.+?)\]:\s*(.+?)(?:\s+[\(\'"](.+?)[\)\'"])?\s*$/', $lines[$current], $matches)) { + $label = strtolower($matches[1]); + + $this->references[$label] = [ + 'url' => $this->replaceEscape($matches[2]), + ]; + if (isset($matches[3])) { + $this->references[$label]['title'] = $matches[3]; + } else { + // title may be on the next line + if (isset($lines[$current + 1]) && preg_match('/^\s+[\(\'"](.+?)[\)\'"]\s*$/', $lines[$current + 1], $matches)) { + $this->references[$label]['title'] = $matches[1]; + $current++; + } + } + $current++; + } + return [false, --$current]; + } + + abstract protected function parseInline($text); + abstract protected function renderAbsy($blocks); +} diff --git a/core/lib/composer/vendor/cebe/markdown/inline/StrikeoutTrait.php b/core/lib/composer/vendor/cebe/markdown/inline/StrikeoutTrait.php new file mode 100644 index 00000000..0e1d21a4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/inline/StrikeoutTrait.php @@ -0,0 +1,40 @@ +parseInline($matches[1]) + ], + strlen($matches[0]) + ]; + } + return [['text', $markdown[0] . $markdown[1]], 2]; + } + + protected function renderStrike($block) + { + return '' . $this->renderAbsy($block[1]) . ''; + } + + abstract protected function parseInline($text); + abstract protected function renderAbsy($blocks); +} diff --git a/core/lib/composer/vendor/cebe/markdown/inline/UrlLinkTrait.php b/core/lib/composer/vendor/cebe/markdown/inline/UrlLinkTrait.php new file mode 100644 index 00000000..90bc794d --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/inline/UrlLinkTrait.php @@ -0,0 +1,50 @@ +[^\s()]+)|(?R))*\) + | # else match a link with title + ^(https?|ftp):\/\/(([^\s<>()]+)|(?R))+(?context) && preg_match($pattern, $markdown, $matches)) { + return [ + ['autoUrl', $matches[0]], + strlen($matches[0]) + ]; + } + return [['text', substr($markdown, 0, 4)], 4]; + } + + protected function renderAutoUrl($block) + { + $href = htmlspecialchars($block[1], ENT_COMPAT | ENT_HTML401, 'UTF-8'); + $decodedUrl = urldecode($block[1]); + $secureUrlText = preg_match('//u', $decodedUrl) ? $decodedUrl : $block[1]; + $text = htmlspecialchars($secureUrlText, ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8'); + return "$text"; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/phpunit.xml.dist b/core/lib/composer/vendor/cebe/markdown/phpunit.xml.dist new file mode 100644 index 00000000..8d41c255 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/phpunit.xml.dist @@ -0,0 +1,27 @@ + + + + + ./tests/ParserTest.php + + ./tests/MarkdownTest.php + ./tests/MarkdownOLStartNumTest.php + + ./tests/GithubMarkdownTest.php + + ./tests/MarkdownExtraTest.php + + + + + ./vendor + ./tests + + + + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/BaseMarkdownTest.php b/core/lib/composer/vendor/cebe/markdown/tests/BaseMarkdownTest.php new file mode 100644 index 00000000..780e12ef --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/BaseMarkdownTest.php @@ -0,0 +1,115 @@ + + */ +abstract class BaseMarkdownTest extends \PHPUnit_Framework_TestCase +{ + protected $outputFileExtension = '.html'; + + abstract public function getDataPaths(); + + /** + * @return Parser + */ + abstract public function createMarkdown(); + + /** + * @dataProvider dataFiles + */ + public function testParse($path, $file) + { + list($markdown, $html) = $this->getTestData($path, $file); + // Different OS line endings should not affect test + $html = str_replace(["\r\n", "\n\r", "\r"], "\n", $html); + + $m = $this->createMarkdown(); + $this->assertEquals($html, $m->parse($markdown)); + } + + public function testUtf8() + { + $this->assertSame("

    абвгдеёжзийклмнопрÑтуфхцчшщъыьÑÑŽÑ

    \n", $this->createMarkdown()->parse('абвгдеёжзийклмнопрÑтуфхцчшщъыьÑÑŽÑ')); + $this->assertSame("

    there is a charater, é…

    \n", $this->createMarkdown()->parse('there is a charater, é…')); + $this->assertSame("

    Arabic Latter \"Ù… (M)\"

    \n", $this->createMarkdown()->parse('Arabic Latter "Ù… (M)"')); + $this->assertSame("

    電腦

    \n", $this->createMarkdown()->parse('電腦')); + + $this->assertSame('абвгдеёжзийклмнопрÑтуфхцчшщъыьÑÑŽÑ', $this->createMarkdown()->parseParagraph('абвгдеёжзийклмнопрÑтуфхцчшщъыьÑÑŽÑ')); + $this->assertSame('there is a charater, é…', $this->createMarkdown()->parseParagraph('there is a charater, é…')); + $this->assertSame('Arabic Latter "Ù… (M)"', $this->createMarkdown()->parseParagraph('Arabic Latter "Ù… (M)"')); + $this->assertSame('電腦', $this->createMarkdown()->parseParagraph('電腦')); + } + + public function testInvalidUtf8() + { + $m = $this->createMarkdown(); + $this->assertEquals("

    �

    \n", $m->parse("`\x80`")); + $this->assertEquals('�', $m->parseParagraph("`\x80`")); + } + + public function pregData() + { + // http://en.wikipedia.org/wiki/Newline#Representations + return [ + ["a\r\nb", "a\nb"], + ["a\n\rb", "a\nb"], // Acorn BBC and RISC OS spooled text output :) + ["a\nb", "a\nb"], + ["a\rb", "a\nb"], + + ["a\n\nb", "a\n\nb", "a

    \n

    b"], + ["a\r\rb", "a\n\nb", "a

    \n

    b"], + ["a\n\r\n\rb", "a\n\nb", "a

    \n

    b"], // Acorn BBC and RISC OS spooled text output :) + ["a\r\n\r\nb", "a\n\nb", "a

    \n

    b"], + ]; + } + + /** + * @dataProvider pregData + */ + public function testPregReplaceR($input, $exptected, $pexpect = null) + { + $this->assertSame($exptected, $this->createMarkdown()->parseParagraph($input)); + $this->assertSame($pexpect === null ? "

    $exptected

    \n" : "

    $pexpect

    \n", $this->createMarkdown()->parse($input)); + } + + public function getTestData($path, $file) + { + return [ + file_get_contents($this->getDataPaths()[$path] . '/' . $file . '.md'), + file_get_contents($this->getDataPaths()[$path] . '/' . $file . $this->outputFileExtension), + ]; + } + + public function dataFiles() + { + $files = []; + foreach ($this->getDataPaths() as $name => $src) { + $handle = opendir($src); + if ($handle === false) { + throw new \Exception('Unable to open directory: ' . $src); + } + while (($file = readdir($handle)) !== false) { + if ($file === '.' || $file === '..') { + continue; + } + + if (substr($file, -3, 3) === '.md' && file_exists($src . '/' . substr($file, 0, -3) . $this->outputFileExtension)) { + $files[] = [$name, substr($file, 0, -3)]; + } + } + closedir($handle); + } + return $files; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/tests/GithubMarkdownTest.php b/core/lib/composer/vendor/cebe/markdown/tests/GithubMarkdownTest.php new file mode 100644 index 00000000..6134fca8 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/GithubMarkdownTest.php @@ -0,0 +1,80 @@ + + * @group github + */ +class GithubMarkdownTest extends BaseMarkdownTest +{ + public function createMarkdown() + { + return new GithubMarkdown(); + } + + public function getDataPaths() + { + return [ + 'markdown-data' => __DIR__ . '/markdown-data', + 'github-data' => __DIR__ . '/github-data', + ]; + } + + public function testNewlines() + { + $markdown = $this->createMarkdown(); + $this->assertEquals("This is text
    \nnewline\nnewline.", $markdown->parseParagraph("This is text \nnewline\nnewline.")); + $markdown->enableNewlines = true; + $this->assertEquals("This is text
    \nnewline
    \nnewline.", $markdown->parseParagraph("This is text \nnewline\nnewline.")); + + $this->assertEquals("

    This is text

    \n

    newline
    \nnewline.

    \n", $markdown->parse("This is text\n\nnewline\nnewline.")); + } + + public function dataFiles() + { + $files = parent::dataFiles(); + foreach($files as $i => $f) { + // skip files that are different in github MD + if ($f[0] === 'markdown-data' && ( + $f[1] === 'list-marker-in-paragraph' || + $f[1] === 'dense-block-markers' + )) { + unset($files[$i]); + } + } + return $files; + } + + public function testKeepZeroAlive() + { + $parser = $this->createMarkdown(); + + $this->assertEquals("0", $parser->parseParagraph("0")); + $this->assertEquals("

    0

    \n", $parser->parse("0")); + } + + public function testAutoLinkLabelingWithEncodedUrl() + { + $parser = $this->createMarkdown(); + + $utfText = "\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a"; + $utfNaturalUrl = "http://example.com/" . $utfText; + $utfEncodedUrl = "http://example.com/" . urlencode($utfText); + $eucEncodedUrl = "http://example.com/" . urlencode(mb_convert_encoding($utfText, 'EUC-JP', 'UTF-8')); + + $this->assertStringEndsWith(">{$utfNaturalUrl}", $parser->parseParagraph($utfNaturalUrl), "Natural UTF-8 URL needs no conversion."); + $this->assertStringEndsWith(">{$utfNaturalUrl}", $parser->parseParagraph($utfEncodedUrl), "Encoded UTF-8 URL will be converted to readable format."); + $this->assertStringEndsWith(">{$eucEncodedUrl}", $parser->parseParagraph($eucEncodedUrl), "Non UTF-8 URL should never be converted."); + // See: \cebe\markdown\inline\UrlLinkTrait::renderAutoUrl + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/tests/MarkdownExtraTest.php b/core/lib/composer/vendor/cebe/markdown/tests/MarkdownExtraTest.php new file mode 100644 index 00000000..40fe9f10 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/MarkdownExtraTest.php @@ -0,0 +1,24 @@ + + * @group extra + */ +class MarkdownExtraTest extends BaseMarkdownTest +{ + public function createMarkdown() + { + return new MarkdownExtra(); + } + + public function getDataPaths() + { + return [ + 'markdown-data' => __DIR__ . '/markdown-data', + 'extra-data' => __DIR__ . '/extra-data', + ]; + } +} \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/MarkdownOLStartNumTest.php b/core/lib/composer/vendor/cebe/markdown/tests/MarkdownOLStartNumTest.php new file mode 100644 index 00000000..01788e39 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/MarkdownOLStartNumTest.php @@ -0,0 +1,32 @@ + + * @group default + */ +class MarkdownOLStartNumTest extends BaseMarkdownTest +{ + public function createMarkdown() + { + $markdown = new Markdown(); + $markdown->keepListStartNumber = true; + return $markdown; + } + + public function getDataPaths() + { + return [ + 'markdown-data' => __DIR__ . '/markdown-ol-start-num-data', + ]; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/tests/MarkdownTest.php b/core/lib/composer/vendor/cebe/markdown/tests/MarkdownTest.php new file mode 100644 index 00000000..97b8e521 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/MarkdownTest.php @@ -0,0 +1,60 @@ + + * @group default + */ +class MarkdownTest extends BaseMarkdownTest +{ + public function createMarkdown() + { + return new Markdown(); + } + + public function getDataPaths() + { + return [ + 'markdown-data' => __DIR__ . '/markdown-data', + ]; + } + + public function testEdgeCases() + { + $this->assertEquals("

    &

    \n", $this->createMarkdown()->parse('&')); + $this->assertEquals("

    <

    \n", $this->createMarkdown()->parse('<')); + } + + public function testKeepZeroAlive() + { + $parser = $this->createMarkdown(); + + $this->assertEquals("0", $parser->parseParagraph("0")); + $this->assertEquals("

    0

    \n", $parser->parse("0")); + } + + public function testAutoLinkLabelingWithEncodedUrl() + { + $parser = $this->createMarkdown(); + + $utfText = "\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a"; + $utfNaturalUrl = "http://example.com/" . $utfText; + $utfEncodedUrl = "http://example.com/" . urlencode($utfText); + $eucEncodedUrl = "http://example.com/" . urlencode(mb_convert_encoding($utfText, 'EUC-JP', 'UTF-8')); + + $this->assertStringEndsWith(">{$utfNaturalUrl}", $parser->parseParagraph("<{$utfNaturalUrl}>"), "Natural UTF-8 URL needs no conversion."); + $this->assertStringEndsWith(">{$utfNaturalUrl}", $parser->parseParagraph("<{$utfEncodedUrl}>"), "Encoded UTF-8 URL will be converted to readable format."); + $this->assertStringEndsWith(">{$eucEncodedUrl}", $parser->parseParagraph("<{$eucEncodedUrl}>"), "Non UTF-8 URL should never be converted."); + // See: \cebe\markdown\inline\LinkTrait::renderUrl + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/tests/ParserTest.php b/core/lib/composer/vendor/cebe/markdown/tests/ParserTest.php new file mode 100644 index 00000000..11418e09 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/ParserTest.php @@ -0,0 +1,94 @@ + + * @group default + */ +class ParserTest extends \PHPUnit_Framework_TestCase +{ + public function testMarkerOrder() + { + $parser = new TestParser(); + $parser->markers = [ + '[' => 'parseMarkerA', + '[[' => 'parseMarkerB', + ]; + + $this->assertEquals("

    Result is A

    \n", $parser->parse('Result is [abc]')); + $this->assertEquals("

    Result is B

    \n", $parser->parse('Result is [[abc]]')); + $this->assertEquals('Result is A', $parser->parseParagraph('Result is [abc]')); + $this->assertEquals('Result is B', $parser->parseParagraph('Result is [[abc]]')); + + $parser = new TestParser(); + $parser->markers = [ + '[[' => 'parseMarkerB', + '[' => 'parseMarkerA', + ]; + + $this->assertEquals("

    Result is A

    \n", $parser->parse('Result is [abc]')); + $this->assertEquals("

    Result is B

    \n", $parser->parse('Result is [[abc]]')); + $this->assertEquals('Result is A', $parser->parseParagraph('Result is [abc]')); + $this->assertEquals('Result is B', $parser->parseParagraph('Result is [[abc]]')); + } + + public function testMaxNestingLevel() + { + $parser = new TestParser(); + $parser->markers = [ + '[' => 'parseMarkerC', + ]; + + $parser->maximumNestingLevel = 3; + $this->assertEquals("(C-a(C-b(C-c)))", $parser->parseParagraph('[a[b[c]]]')); + $parser->maximumNestingLevel = 2; + $this->assertEquals("(C-a(C-b[c]))", $parser->parseParagraph('[a[b[c]]]')); + $parser->maximumNestingLevel = 1; + $this->assertEquals("(C-a[b[c]])", $parser->parseParagraph('[a[b[c]]]')); + } + + public function testKeepZeroAlive() + { + $parser = new TestParser(); + + $this->assertEquals("0", $parser->parseParagraph("0")); + $this->assertEquals("

    0

    \n", $parser->parse("0")); + } +} + +class TestParser extends Parser +{ + public $markers = []; + + protected function inlineMarkers() + { + return $this->markers; + } + + protected function parseMarkerA($text) + { + return [['text', 'A'], strrpos($text, ']') + 1]; + } + + protected function parseMarkerB($text) + { + return [['text', 'B'], strrpos($text, ']') + 1]; + } + + protected function parseMarkerC($text) + { + $terminatingMarkerPos = strrpos($text, ']'); + $inside = $this->parseInline(substr($text, 1, $terminatingMarkerPos - 1)); + return [['text', '(C-' . $this->renderAbsy($inside) . ')'], $terminatingMarkerPos + 1]; + } +} diff --git a/core/lib/composer/vendor/cebe/markdown/tests/bootstrap.php b/core/lib/composer/vendor/cebe/markdown/tests/bootstrap.php new file mode 100644 index 00000000..b7e49f91 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/bootstrap.php @@ -0,0 +1,5 @@ + +
  • foo

    +
    ```
    +bar
    +
    +blah
    +
    +foo
    +```
    +
    +
  • + +
    +
      +
    1. foo

      +
         bar
      +
      +   blah
      +
      +   foo
      +
      +
    2. +
    +
    +
      +
    1. foo

      +
        bar
      +
      +  blah
      +
      +  foo
      +
      +
    2. +
    +
    +
      +
    1. foo

      +
       bar
      +
      + blah
      +
      + foo
      +
      +
    2. +
    +
    +
      +
    1. foo

      +
      bar
      +
      +blah
      +
      +foo
      +
      +
    2. +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +    ```
    +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/code_in_lists.md b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/code_in_lists.md new file mode 100644 index 00000000..cc3a4ca3 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/code_in_lists.md @@ -0,0 +1,94 @@ +1. foo + + ``` + bar + + blah + + foo + ``` + +---- + +1. foo + + ``` + bar + + blah + + foo + ``` + +---- + +1. foo + + ``` + bar + + blah + + foo + ``` + +---- + +1. foo + + ``` + bar + + blah + + foo + ``` + +---- + +1. foo + + ``` + bar + + blah + + foo + ``` + + + ``` +foo + +bar +``` + + ``` +foo + +bar +``` + + ``` +foo + +bar +``` + + ``` +foo + +bar + ``` + + ``` +foo + +bar + ``` + + ``` +foo + +bar + ``` diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/fenced-code.html b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/fenced-code.html new file mode 100644 index 00000000..578e7214 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/fenced-code.html @@ -0,0 +1,17 @@ +
    
    +fenced code block
    +
    +
    +
    
    +fenced with tildes
    +
    +
    +
    long fence
    +
    +```
    +code about code
    +```
    +
    +
    +
    fenced code block
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/fenced-code.md b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/fenced-code.md new file mode 100644 index 00000000..871f7886 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/fenced-code.md @@ -0,0 +1,24 @@ +``` + +fenced code block + +``` + +~~~ + +fenced with tildes + +~~~ + +`````````` +long fence + +``` +code about code +``` + +`````````` + +``` .html #test +fenced code block +``` diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/non-tables.html b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/non-tables.html new file mode 100644 index 00000000..0d0724f3 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/non-tables.html @@ -0,0 +1,8 @@ +

    Non-tables

    +

    This line contains two pipes but is not a table. [[yii\widgets\DetailView|DetailView]] widget displays the details of a single data [[yii\widgets\DetailView::$model|model]].

    +

    the line above contains a space.

    +

    looks | like | head +-:

    +

    looks | like | head +-: +a

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/non-tables.md b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/non-tables.md new file mode 100644 index 00000000..4fb9cde5 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/non-tables.md @@ -0,0 +1,13 @@ +Non-tables +---------- + +This line contains two pipes but is not a table. [[yii\widgets\DetailView|DetailView]] widget displays the details of a single data [[yii\widgets\DetailView::$model|model]]. + +the line above contains a space. + +looks | like | head +-: + +looks | like | head +-: +a diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/special-attributes.html b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/special-attributes.html new file mode 100644 index 00000000..55de8087 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/special-attributes.html @@ -0,0 +1,12 @@ +

    Header 1

    +

    Header 2

    +

    The Site

    +

    The Site

    +

    link +img

    +

    link or linkref +img

    +

    this is just normal text {.main .shine #the-site}

    +

    some { brackets

    +

    some } brackets

    +

    some { } brackets

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/special-attributes.md b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/special-attributes.md new file mode 100644 index 00000000..0796d346 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/special-attributes.md @@ -0,0 +1,25 @@ +Header 1 {#header1} +======== + +## Header 2 ## {#header2} + +## The Site ## {.main} + +## The Site ## {.main .shine #the-site} + +[link](url){#id1 .class} +![img](url){#id2 .class} + + +[link][linkref] or [linkref] +![img][linkref] + +[linkref]: http://url.de/ "optional title" {#id .class} + +this is just normal text {.main .shine #the-site} + +some { brackets + +some } brackets + +some { } brackets \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/tables.html b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/tables.html new file mode 100644 index 00000000..52fb8456 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/tables.html @@ -0,0 +1,219 @@ +

    Tables

    + + + + + + + + +
    First HeaderSecond Header
    Content CellContent Cell
    Content CellContent Cell
    + + + + + + + + +
    First HeaderSecond Header
    Content CellContent Cell
    Content CellContent Cell
    + + + + + + + + +
    NameDescription
    HelpDisplay the help window.
    CloseCloses a window
    + + + + + + + + +
    NameDescription
    HelpDisplay the help window.
    CloseCloses a window
    + + + + + + + + + +
    Default-AlignLeft-AlignedCenter AlignedRight Aligned
    1col 3 issome wordy text$1600
    2col 2 iscentered$12
    3zebra stripesare neat$1
    + + + + + + + + +
    SimpleTable
    12
    34
    + + + + + + + + + + +
    SimpleTable
    12
    34
    34 |
    34 \
    +

    Check https://github.com/erusev/parsedown/issues/184 for the following:

    + + + + + + + + + + + +
    FooBarState
    Code | PipeBrokenBlank
    Escaped Code \| PipeBrokenBlank
    Escaped | PipeBrokenBlank
    Escaped \PipeBrokenBlank
    Escaped \PipeBrokenBlank
    + + + + + + + + + +
    SimpleTable
    34
    34
    5
    + + + + + + + + +
    MixedTable
    12
    34
    + + + + + + + + +
    MixedTable
    12
    34
    + + + + + + + + +
    MixedTable
    12
    34
    +

    some text

    + + + + + + + + + +
    single col
    1
    2
    3
    + + + + + + + + + + + +
    TableWithEmptyCells
    ab
    ab
    ab
    ab
    + + + + + + + +
    + + + + + + + +
    + + + + + + + +
    TableIndentation
    AB
    + + + + + + + +
    TableIndentation
    AB
    + + + + + + + +
    TableIndentation
    AB
    +
    | Table | Indentation |
    +
    +

    | ----- | ---- | + | A | B |

    + + + + + + +
    TableIndentation
    +
    | A     | B    |
    +
    + + + + + + + + + +
    ItemValue
    Computer$1600
    Phone$12
    Pipe$1
    + + + + + + + +
    abc
    123
    + + + + + + + +
    abcd
    1234
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/tables.md b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/tables.md new file mode 100644 index 00000000..5c3df505 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/tables.md @@ -0,0 +1,130 @@ +Tables +------ + +First Header | Second Header +------------- | ------------- +Content Cell | Content Cell +Content Cell | Content Cell + +| First Header | Second Header | +| ------------- | ------------- | +| Content Cell | Content Cell | +| Content Cell | Content Cell | + +| Name | Description | +| ------------- | ----------- | +| Help | Display the help window.| +| Close | Closes a window | + +| Name | Description | +| ------------- | ----------- | +| Help | **Display the** help window.| +| Close | _Closes_ a window | + +| Default-Align | Left-Aligned | Center Aligned | Right Aligned | +| ------------- | :------------ |:---------------:| -----:| +| 1 | col 3 is | some wordy text | $1600 | +| 2 | col 2 is | centered | $12 | +| 3 | zebra stripes | are neat | $1 | + + +Simple | Table +------ | ----- +1 | 2 +3 | 4 + +| Simple | Table | +| ------ | ----- | +| 1 | 2 | +| 3 | 4 | +| 3 | 4 \| +| 3 | 4 \\| + +Check https://github.com/erusev/parsedown/issues/184 for the following: + +Foo | Bar | State +------ | ------ | ----- +`Code | Pipe` | Broken | Blank +`Escaped Code \| Pipe` | Broken | Blank +Escaped \| Pipe | Broken | Blank +Escaped \\| Pipe | Broken | Blank +Escaped \\ | Pipe | Broken | Blank + +| Simple | Table | +| :----- | ----- | +| 3 | 4 | +3 | 4 +5 + +Mixed | Table +------ | ----- +| 1 | 2 +3 | 4 + +| Mixed | Table +------ | ----- +| 1 | 2 +3 | 4 + + Mixed | Table +|------ | ----- | + 1 | 2 +| 3 | 4 | + +some text + +| single col | +| -- | -- | +| 1 | +2 +3 + +| Table | With | Empty | Cells | +| ----- | ---- | ----- | ----- | +| | | | | +| a | | b | | +| | a | | b | +| a | | | b | +| | a | b | | + + | +-- | -- + | + +| | | +| - | - | +| | | + + | Table | Indentation | + | ----- | ---- | + | A | B | + + | Table | Indentation | + | ----- | ---- | + | A | B | + + | Table | Indentation | + | ----- | ---- | + | A | B | + + | Table | Indentation | + | ----- | ---- | + | A | B | + +| Table | Indentation | + | :----- | ---- | + | A | B | + +| Item | Value | +| --------- | -----:| +| Computer | $1600 | +| Phone | $12 | +| Pipe | $1 | + +| a | b | c | +|:-:|:-:|:-:| +| 1 | 2 | 3 | + +| a | b | c | d | +|:--|:-:|:--|:-:| +| 1 | 2 | 3 | 4 | \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/test_precedence.html b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/test_precedence.html new file mode 100644 index 00000000..e452a929 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/test_precedence.html @@ -0,0 +1,8 @@ +

    Not a headline but a code block:

    +
    ---
    +
    +

    Not a headline but two HR:

    +
    +
    +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/extra-data/test_precedence.md b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/test_precedence.md new file mode 100644 index 00000000..66b49425 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/extra-data/test_precedence.md @@ -0,0 +1,14 @@ +Not a headline but a code block: + +``` +--- +``` + +Not a headline but two HR: + +*** +--- + +--- +*** + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/code_in_lists.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/code_in_lists.html new file mode 100644 index 00000000..3787bded --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/code_in_lists.html @@ -0,0 +1,82 @@ +
      +
    1. foo

      +
      ```
      +bar
      +
      +blah
      +
      +foo
      +```
      +
      +
    2. +
    +
    +
      +
    1. foo

      +
         bar
      +
      +   blah
      +
      +   foo
      +
      +
    2. +
    +
    +
      +
    1. foo

      +
        bar
      +
      +  blah
      +
      +  foo
      +
      +
    2. +
    +
    +
      +
    1. foo

      +
       bar
      +
      + blah
      +
      + foo
      +
      +
    2. +
    +
    +
      +
    1. foo

      +
      bar
      +
      +blah
      +
      +foo
      +
      +
    2. +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +
    +
    foo
    +
    +bar
    +    ```
    +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/code_in_lists.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/code_in_lists.md new file mode 100644 index 00000000..cc3a4ca3 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/code_in_lists.md @@ -0,0 +1,94 @@ +1. foo + + ``` + bar + + blah + + foo + ``` + +---- + +1. foo + + ``` + bar + + blah + + foo + ``` + +---- + +1. foo + + ``` + bar + + blah + + foo + ``` + +---- + +1. foo + + ``` + bar + + blah + + foo + ``` + +---- + +1. foo + + ``` + bar + + blah + + foo + ``` + + + ``` +foo + +bar +``` + + ``` +foo + +bar +``` + + ``` +foo + +bar +``` + + ``` +foo + +bar + ``` + + ``` +foo + +bar + ``` + + ``` +foo + +bar + ``` diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/del.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/del.html new file mode 100644 index 00000000..efacb5c4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/del.html @@ -0,0 +1,5 @@ +

    this is striked out after

    +

    striked out

    +

    a line with ~~ in it ...

    +

    ~~

    +

    ~

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/del.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/del.md new file mode 100644 index 00000000..8a3c701a --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/del.md @@ -0,0 +1,9 @@ +this is ~~striked out~~ after + +~~striked out~~ + +a line with ~~ in it ... + +~~ + +~ \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers.html new file mode 100644 index 00000000..daac5ed4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers.html @@ -0,0 +1,52 @@ +

    this is to test dense blocks (no newlines between them)

    +
    +

    what is Markdown?

    +

    see Wikipedia

    +

    a h2

    +

    paragraph

    +

    this is a paragraph, not a headline or list +next line

    +
      +
    • whoo
    • +
    +

    par

    +
    code
    +code
    +
    +

    par

    +

    Tasks list

    +
      +
    • list items
    • +
    +

    headline1

    +

    quote +quote

    +
    +

    headline2

    +
    +

    h1

    +

    h2

    +
    +

    h3

    +
      +
    1. ol1
    2. +
    3. ol2
    4. +
    +

    h4

    +
      +
    • listA
    • +
    • listB
    • +
    +
    h5
    +
    h6
    +
    +
    +

    changelog 1

    +
      +
    • 17-Feb-2013 re-design
    • +
    +
    +

    changelog 2

    +
      +
    • 17-Feb-2013 re-design
    • +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers.md new file mode 100644 index 00000000..ea365b86 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers.md @@ -0,0 +1,56 @@ +# this is to test dense blocks (no newlines between them) + +---- +## what is Markdown? +see [Wikipedia][] + +a h2 +---- +paragraph + +this is a paragraph, not a headline or list +next line +- whoo + +par + code + code +par + +### Tasks list +- list items + +headline1 +--------- +> quote +> quote + +[Wikipedia]: http://en.wikipedia.org/wiki/Markdown +headline2 +--------- + +---- +# h1 +## h2 +--- +### h3 +1. ol1 +2. ol2 + +#### h4 +- listA +- listB + +##### h5 +###### h6 +-------- + +---- + +## changelog 1 + +* 17-Feb-2013 re-design + +---- +## changelog 2 +* 17-Feb-2013 re-design \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers2.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers2.html new file mode 100644 index 00000000..c7db5024 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers2.html @@ -0,0 +1,23 @@ +

    Now we need to set:

    +
    'session' => [
    +    'cookieParams' => [
    +        'path' => '/path1/',
    +    ]
    +],
    +
    +

    and

    +
    'session' => [
    +    'cookieParams' => [
    +        'path' => '/path2/',
    +    ]
    +],
    +
    +

    In the following starts a Blockquote:

    +

    this is a blockquote

    +
    +

    par

    +
    +

    par

    +

    This is some text

    +

    Headline1

    +

    more text

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers2.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers2.md new file mode 100644 index 00000000..de990fcd --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/dense-block-markers2.md @@ -0,0 +1,27 @@ +Now we need to set: +```php +'session' => [ + 'cookieParams' => [ + 'path' => '/path1/', + ] +], +``` +and +```php +'session' => [ + 'cookieParams' => [ + 'path' => '/path2/', + ] +], +``` + +In the following starts a Blockquote: +> this is a blockquote + +par +*** +par + +This is some text +# Headline1 +more text \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-basics.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-basics.html new file mode 100644 index 00000000..5a4d7d3d --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-basics.html @@ -0,0 +1,19 @@ +

    GitHub Flavored Markdown

    +

    Multiple underscores in words

    +

    do_this_and_do_that_and_another_thing

    +

    URL autolinking

    +

    http://example.com

    +

    Strikethrough

    +

    Mistaken text.

    +

    Fenced code blocks

    +
    function test() {
    +  console.log("notice the blank line before this function?");
    +}
    +
    +

    Syntax highlighting

    +
    require 'redcarpet'
    +markdown = Redcarpet.new("Hello World!")
    +puts markdown.to_html
    +
    +
    this is also code
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-basics.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-basics.md new file mode 100644 index 00000000..ddb97d55 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-basics.md @@ -0,0 +1,40 @@ +GitHub Flavored Markdown +======================== + +Multiple underscores in words +----------------------------- + +do_this_and_do_that_and_another_thing + +URL autolinking +--------------- + +http://example.com + +Strikethrough +------------- + +~~Mistaken text.~~ + +Fenced code blocks +------------------ + +``` +function test() { + console.log("notice the blank line before this function?"); +} +``` + +Syntax highlighting +------------------- + +```ruby +require 'redcarpet' +markdown = Redcarpet.new("Hello World!") +puts markdown.to_html +``` + +~~~ +this is also code +~~~ + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-code-in-numbered-list.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-code-in-numbered-list.html new file mode 100644 index 00000000..cc149575 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-code-in-numbered-list.html @@ -0,0 +1,12 @@ +
      +
    1. Item one.
    2. +
    3. Item two with some code:

      +
      code one
      +
      +
    4. +
    5. Item three with code:

      +
      code two
      +
      +
    6. +
    +

    Paragraph.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-code-in-numbered-list.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-code-in-numbered-list.md new file mode 100644 index 00000000..880ff473 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-code-in-numbered-list.md @@ -0,0 +1,14 @@ +1. Item one. +2. Item two with some code: + + ``` + code one + ``` + +3. Item three with code: + + ``` + code two + ``` + +Paragraph. \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-sample.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-sample.html new file mode 100644 index 00000000..b2e3962d --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-sample.html @@ -0,0 +1,117 @@ +

    GitHub Flavored Markdown

    +

    View the source of this content.

    +

    Let's get the whole "linebreak" thing out of the way. The next paragraph contains two phrases separated by a single newline character:

    +

    Roses are red +Violets are blue

    +

    The next paragraph has the same phrases, but now they are separated by two spaces and a newline character:

    +

    Roses are red
    +Violets are blue

    +

    Oh, and one thing I cannot stand is the mangling of words with multiple underscores in them like perform_complicated_task or do_this_and_do_that_and_another_thing.

    +

    A bit of the GitHub spice

    +

    In addition to the changes in the previous section, certain references are auto-linked:

    +
      +
    • SHA: be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2
    • +
    • User@SHA ref: mojombo@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2
    • +
    • User/Project@SHA: mojombo/god@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2
    • +
    • #Num: #1
    • +
    • User/#Num: mojombo#1
    • +
    • User/Project#Num: mojombo/god#1
    • +
    +

    These are dangerous goodies though, and we need to make sure email addresses don't get mangled:

    +

    My email addy is tom@github.com.

    +

    Math is hard, let's go shopping

    +

    In first grade I learned that 5 > 3 and 2 < 7. Maybe some arrows. 1 -> 2 -> 3. 9 <- 8 <- 7.

    +

    Triangles man! a^2 + b^2 = c^2

    +

    We all like making lists

    +

    The above header should be an H2 tag. Now, for a list of fruits:

    +
      +
    • Red Apples
    • +
    • Purple Grapes
    • +
    • Green Kiwifruits
    • +
    +

    Let's get crazy:

    +
      +
    1. This is a list item with two paragraphs. Lorem ipsum dolor +sit amet, consectetuer adipiscing elit. Aliquam hendrerit +mi posuere lectus.

      +

      Vestibulum enim wisi, viverra nec, fringilla in, laoreet +vitae, risus. Donec sit amet nisl. Aliquam semper ipsum +sit amet velit.

      +
    2. +
    3. Suspendisse id sem consectetuer libero luctus adipiscing.

      +
    4. +
    +

    What about some code in a list? That's insane, right?

    +
      +
    1. In Ruby you can map like this:

      +
       ['a', 'b'].map { |x| x.uppercase }
      +
      +
    2. +
    3. In Rails, you can do a shortcut:

      +
       ['a', 'b'].map(&:uppercase)
      +
      +
    4. +
    +

    Some people seem to like definition lists

    +
    +
    Lower cost
    +
    The new version of this product costs significantly less than the previous one!
    +
    Easier to use
    +
    We've changed the product so that it's much easier to use!
    +
    +

    I am a robot

    +

    Maybe you want to print robot to the console 1000 times. Why not?

    +
    def robot_invasion
    +  puts("robot " * 1000)
    +end
    +
    +

    You see, that was formatted as code because it's been indented by four spaces.

    +

    How about we throw some angle braces and ampersands in there?

    +
    <div class="footer">
    +    &copy; 2004 Foo Corporation
    +</div>
    +
    +

    Set in stone

    +

    Preformatted blocks are useful for ASCII art:

    +
    +             ,-. 
    +    ,     ,-.   ,-. 
    +   / \   (   )-(   ) 
    +   \ |  ,.>-(   )-< 
    +    \|,' (   )-(   ) 
    +     Y ___`-'   `-' 
    +     |/__/   `-' 
    +     | 
    +     | 
    +     |    -hrr- 
    +  ___|_____________ 
    +
    +

    Playing the blame game

    +

    If you need to blame someone, the best way to do so is by quoting them:

    +

    I, at any rate, am convinced that He does not throw dice.

    +
    +

    Or perhaps someone a little less eloquent:

    +

    I wish you'd have given me this written question ahead of time so I +could plan for it... I'm sure something will pop into my head here in +the midst of this press conference, with all the pressure of trying to +come up with answer, but it hadn't yet...

    +

    I don't want to sound like +I have made no mistakes. I'm confident I have. I just haven't - you +just put me under the spot here, and maybe I'm not as quick on my feet +as I should be in coming up with one.

    +
    +

    Table for two

    + + + + + + + + + + +
    IDNameRank
    1Tom Preston-WernerAwesome
    2Albert EinsteinNearly as awesome
    +

    Crazy linking action

    +

    I get 10 times more traffic from Google than from +Yahoo or MSN.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-sample.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-sample.md new file mode 100644 index 00000000..dd2a804a --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/github-sample.md @@ -0,0 +1,159 @@ +GitHub Flavored Markdown +================================ + +*View the [source of this content](http://github.github.com/github-flavored-markdown/sample_content.html).* + +Let's get the whole "linebreak" thing out of the way. The next paragraph contains two phrases separated by a single newline character: + +Roses are red +Violets are blue + +The next paragraph has the same phrases, but now they are separated by two spaces and a newline character: + +Roses are red +Violets are blue + +Oh, and one thing I cannot stand is the mangling of words with multiple underscores in them like perform_complicated_task or do_this_and_do_that_and_another_thing. + +A bit of the GitHub spice +------------------------- + +In addition to the changes in the previous section, certain references are auto-linked: + +* SHA: be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 +* User@SHA ref: mojombo@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 +* User/Project@SHA: mojombo/god@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 +* \#Num: #1 +* User/#Num: mojombo#1 +* User/Project#Num: mojombo/god#1 + +These are dangerous goodies though, and we need to make sure email addresses don't get mangled: + +My email addy is tom@github.com. + +Math is hard, let's go shopping +------------------------------- + +In first grade I learned that 5 > 3 and 2 < 7. Maybe some arrows. 1 -> 2 -> 3. 9 <- 8 <- 7. + +Triangles man! a^2 + b^2 = c^2 + +We all like making lists +------------------------ + +The above header should be an H2 tag. Now, for a list of fruits: + +* Red Apples +* Purple Grapes +* Green Kiwifruits + +Let's get crazy: + +1. This is a list item with two paragraphs. Lorem ipsum dolor + sit amet, consectetuer adipiscing elit. Aliquam hendrerit + mi posuere lectus. + + Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. Donec sit amet nisl. Aliquam semper ipsum + sit amet velit. + +2. Suspendisse id sem consectetuer libero luctus adipiscing. + +What about some code **in** a list? That's insane, right? + +1. In Ruby you can map like this: + + ['a', 'b'].map { |x| x.uppercase } + +2. In Rails, you can do a shortcut: + + ['a', 'b'].map(&:uppercase) + +Some people seem to like definition lists + +
    +
    Lower cost
    +
    The new version of this product costs significantly less than the previous one!
    +
    Easier to use
    +
    We've changed the product so that it's much easier to use!
    +
    + +I am a robot +------------ + +Maybe you want to print `robot` to the console 1000 times. Why not? + + def robot_invasion + puts("robot " * 1000) + end + +You see, that was formatted as code because it's been indented by four spaces. + +How about we throw some angle braces and ampersands in there? + + + +Set in stone +------------ + +Preformatted blocks are useful for ASCII art: + +
    +             ,-. 
    +    ,     ,-.   ,-. 
    +   / \   (   )-(   ) 
    +   \ |  ,.>-(   )-< 
    +    \|,' (   )-(   ) 
    +     Y ___`-'   `-' 
    +     |/__/   `-' 
    +     | 
    +     | 
    +     |    -hrr- 
    +  ___|_____________ 
    +
    + +Playing the blame game +---------------------- + +If you need to blame someone, the best way to do so is by quoting them: + +> I, at any rate, am convinced that He does not throw dice. + +Or perhaps someone a little less eloquent: + +> I wish you'd have given me this written question ahead of time so I +> could plan for it... I'm sure something will pop into my head here in +> the midst of this press conference, with all the pressure of trying to +> come up with answer, but it hadn't yet... +> +> I don't want to sound like +> I have made no mistakes. I'm confident I have. I just haven't - you +> just put me under the spot here, and maybe I'm not as quick on my feet +> as I should be in coming up with one. + +Table for two +------------- + + + + + + + + + + + +
    IDNameRank
    1Tom Preston-WernerAwesome
    2Albert EinsteinNearly as awesome
    + +Crazy linking action +-------------------- + +I get 10 times more traffic from [Google] [1] than from +[Yahoo] [2] or [MSN] [3]. + + [1]: http://google.com/ "Google" + [2]: http://search.yahoo.com/ "Yahoo Search" + [3]: http://search.msn.com/ "MSN Search" diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-33.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-33.html new file mode 100644 index 00000000..37ca8f41 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-33.html @@ -0,0 +1,5 @@ +
    hey, check [this].
    +
    +[this]: https://github.com/cebe/markdown
    +
    +

    is a vaild reference.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-33.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-33.md new file mode 100644 index 00000000..1f639db6 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-33.md @@ -0,0 +1,6 @@ +``` +hey, check [this]. + +[this]: https://github.com/cebe/markdown +``` +is a vaild reference. \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-38.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-38.html new file mode 100644 index 00000000..ef7f3e5b --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-38.html @@ -0,0 +1,21 @@ +

    some text +`` +// some code +\``

    +
    +

    some text

    +
    // some code
    +
    +
    +

    some text

    +
    // some code
    +
    +
    +

    some text

    +
    // some code
    +
    +
    +

    some text

    +
    +
    // some code
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-38.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-38.md new file mode 100644 index 00000000..c7400683 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-38.md @@ -0,0 +1,26 @@ +> some text +\``` +// some code +\``` + +> some text +``` +// some code +``` + +> some text +> ``` +// some code +``` + +> some text +> +> ``` +// some code +``` + +> some text + +``` +// some code +``` diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-50.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-50.html new file mode 100644 index 00000000..c8ba3910 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-50.html @@ -0,0 +1,9 @@ +

    table of cronjobs should not result in empty ems:

    + + + + + + + +
    cron
    * * * * *
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-50.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-50.md new file mode 100644 index 00000000..b5a176db --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/issue-50.md @@ -0,0 +1,5 @@ +table of cronjobs should not result in empty ems: + +| cron | +| ------- | +| * * * * * | diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/lists.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/lists.html new file mode 100644 index 00000000..d296dd5b --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/lists.html @@ -0,0 +1,16 @@ +

    Text before list:

    +
      +
    • item 1,
    • +
    • item 2,
    • +
    • item 3.
    • +
    +

    Text after list.

    +
      +
    • test
    • +
    • test
        +
      • test
      • +
      • test
      • +
      +
    • +
    • test
    • +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/lists.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/lists.md new file mode 100644 index 00000000..eb7b62a6 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/lists.md @@ -0,0 +1,12 @@ +Text before list: + * item 1, + * item 2, + * item 3. + +Text after list. + +- test +- test + - test + - test +- test diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/non-tables.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/non-tables.html new file mode 100644 index 00000000..0d0724f3 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/non-tables.html @@ -0,0 +1,8 @@ +

    Non-tables

    +

    This line contains two pipes but is not a table. [[yii\widgets\DetailView|DetailView]] widget displays the details of a single data [[yii\widgets\DetailView::$model|model]].

    +

    the line above contains a space.

    +

    looks | like | head +-:

    +

    looks | like | head +-: +a

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/non-tables.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/non-tables.md new file mode 100644 index 00000000..4fb9cde5 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/non-tables.md @@ -0,0 +1,13 @@ +Non-tables +---------- + +This line contains two pipes but is not a table. [[yii\widgets\DetailView|DetailView]] widget displays the details of a single data [[yii\widgets\DetailView::$model|model]]. + +the line above contains a space. + +looks | like | head +-: + +looks | like | head +-: +a diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/tables.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/tables.html new file mode 100644 index 00000000..40c38136 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/tables.html @@ -0,0 +1,203 @@ +

    Tables

    + + + + + + + + +
    First HeaderSecond Header
    Content CellContent Cell
    Content CellContent Cell
    + + + + + + + + +
    First HeaderSecond Header
    Content CellContent Cell
    Content CellContent Cell
    + + + + + + + + +
    NameDescription
    HelpDisplay the help window.
    CloseCloses a window
    + + + + + + + + +
    NameDescription
    HelpDisplay the help window.
    CloseCloses a window
    + + + + + + + + + +
    Default-AlignLeft-AlignedCenter AlignedRight Aligned
    1col 3 issome wordy text$1600
    2col 2 iscentered$12
    3zebra stripesare neat$1
    + + + + + + + + +
    SimpleTable
    12
    34
    + + + + + + + + + + +
    SimpleTable
    12
    34
    34 |
    34 \
    +

    Check https://github.com/erusev/parsedown/issues/184 for the following:

    + + + + + + + + + + + +
    FooBarState
    Code | PipeBrokenBlank
    Escaped Code \| PipeBrokenBlank
    Escaped | PipeBrokenBlank
    Escaped \PipeBrokenBlank
    Escaped \PipeBrokenBlank
    + + + + + + + + + +
    SimpleTable
    34
    34
    5
    + + + + + + + + +
    MixedTable
    12
    34
    + + + + + + + + +
    MixedTable
    12
    34
    + + + + + + + + +
    MixedTable
    12
    34
    +

    some text

    + + + + + + + + + +
    single col
    1
    2
    3
    + + + + + + + + + + + +
    TableWithEmptyCells
    ab
    ab
    ab
    ab
    + + + + + + + +
    + + + + + + + +
    + + + + + + + +
    TableIndentation
    AB
    + + + + + + + +
    TableIndentation
    AB
    + + + + + + + +
    TableIndentation
    AB
    +
    | Table | Indentation |
    +
    +

    | ----- | ---- | + | A | B |

    + + + + + + +
    TableIndentation
    +
    | A     | B    |
    +
    + + + + + + + + + +
    ItemValue
    Computer$1600
    Phone$12
    Pipe$1
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/tables.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/tables.md new file mode 100644 index 00000000..8b479285 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/tables.md @@ -0,0 +1,122 @@ +Tables +------ + +First Header | Second Header +------------- | ------------- +Content Cell | Content Cell +Content Cell | Content Cell + +| First Header | Second Header | +| ------------- | ------------- | +| Content Cell | Content Cell | +| Content Cell | Content Cell | + +| Name | Description | +| ------------- | ----------- | +| Help | Display the help window.| +| Close | Closes a window | + +| Name | Description | +| ------------- | ----------- | +| Help | **Display the** help window.| +| Close | _Closes_ a window | + +| Default-Align | Left-Aligned | Center Aligned | Right Aligned | +| ------------- | :------------ |:---------------:| -----:| +| 1 | col 3 is | some wordy text | $1600 | +| 2 | col 2 is | centered | $12 | +| 3 | zebra stripes | are neat | $1 | + + +Simple | Table +------ | ----- +1 | 2 +3 | 4 + +| Simple | Table | +| ------ | ----- | +| 1 | 2 | +| 3 | 4 | +| 3 | 4 \| +| 3 | 4 \\| + +Check https://github.com/erusev/parsedown/issues/184 for the following: + +Foo | Bar | State +------ | ------ | ----- +`Code | Pipe` | Broken | Blank +`Escaped Code \| Pipe` | Broken | Blank +Escaped \| Pipe | Broken | Blank +Escaped \\| Pipe | Broken | Blank +Escaped \\ | Pipe | Broken | Blank + +| Simple | Table | +| :----- | ----- | +| 3 | 4 | +3 | 4 +5 + +Mixed | Table +------ | ----- +| 1 | 2 +3 | 4 + +| Mixed | Table +------ | ----- +| 1 | 2 +3 | 4 + + Mixed | Table +|------ | ----- | + 1 | 2 +| 3 | 4 | + +some text + +| single col | +| -- | -- | +| 1 | +2 +3 + +| Table | With | Empty | Cells | +| ----- | ---- | ----- | ----- | +| | | | | +| a | | b | | +| | a | | b | +| a | | | b | +| | a | b | | + + | +-- | -- + | + +| | | +| - | - | +| | | + + | Table | Indentation | + | ----- | ---- | + | A | B | + + | Table | Indentation | + | ----- | ---- | + | A | B | + + | Table | Indentation | + | ----- | ---- | + | A | B | + + | Table | Indentation | + | ----- | ---- | + | A | B | + +| Table | Indentation | + | :----- | ---- | + | A | B | + +| Item | Value | +| --------- | -----:| +| Computer | $1600 | +| Phone | $12 | +| Pipe | $1 | diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/test_precedence.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/test_precedence.html new file mode 100644 index 00000000..e452a929 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/test_precedence.html @@ -0,0 +1,8 @@ +

    Not a headline but a code block:

    +
    ---
    +
    +

    Not a headline but two HR:

    +
    +
    +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/test_precedence.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/test_precedence.md new file mode 100644 index 00000000..66b49425 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/test_precedence.md @@ -0,0 +1,14 @@ +Not a headline but a code block: + +``` +--- +``` + +Not a headline but two HR: + +*** +--- + +--- +*** + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/url.html b/core/lib/composer/vendor/cebe/markdown/tests/github-data/url.html new file mode 100644 index 00000000..4d802d7a --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/url.html @@ -0,0 +1,17 @@ +

    here is the url: http://www.cebe.cc/

    +

    here is the url: http://www.cebe.cc

    +

    here is the url: http://www.cebe.cc/ and some text

    +

    using http is cool and http:// is the beginning of an url.

    +

    link should be url decoded: http://en.wikipedia.org/wiki/Mase_(disambiguation)

    +

    link in the end of the sentence: See this http://example.com/.

    +

    this one is in parenthesis (http://example.com/).

    +

    this one is in parenthesis (http://example.com:80/?id=1,2,3).

    +

    ... (see http://en.wikipedia.org/wiki/Port_(computer_networking)).

    +

    ... (see https://en.wikipedia.org/wiki/Port_(computer_networking)_more).

    +

    ... (see https://en.wikipedia.org/wiki/Port_(computer_networking)_more). ... (see http://en.wikipedia.org/wiki/Port_(computer_networking)).

    +

    ... (see https://en.wikipedia.org/wiki/Port_(computer_networking)_more)....(http://en.wikipedia.org/wiki/Port_(computer_networking)).

    +

    ... (see http://en.wikipedia.org/wiki/Port)

    +

    ... (see http://en.wikipedia.org/wiki/Port).

    +

    http://www.cebe.cc, http://www.cebe.net, and so on

    +

    link to http://www.google.com/

    +

    contact me at http://cebe.cc/contact.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/github-data/url.md b/core/lib/composer/vendor/cebe/markdown/tests/github-data/url.md new file mode 100644 index 00000000..b45396be --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/github-data/url.md @@ -0,0 +1,33 @@ +here is the url: http://www.cebe.cc/ + +here is the url: http://www.cebe.cc + +here is the url: http://www.cebe.cc/ and some text + +using http is cool and http:// is the beginning of an url. + +link should be url decoded: http://en.wikipedia.org/wiki/Mase_%28disambiguation%29 + +link in the end of the sentence: See this http://example.com/. + +this one is in parenthesis (http://example.com/). + +this one is in parenthesis (http://example.com:80/?id=1,2,3). + +... (see http://en.wikipedia.org/wiki/Port_(computer_networking)). + +... (see https://en.wikipedia.org/wiki/Port_(computer_networking)_more). + +... (see https://en.wikipedia.org/wiki/Port_(computer_networking)_more). ... (see http://en.wikipedia.org/wiki/Port_(computer_networking)). + +... (see https://en.wikipedia.org/wiki/Port_(computer_networking)_more)....(http://en.wikipedia.org/wiki/Port_(computer_networking)). + +... (see http://en.wikipedia.org/wiki/Port) + +... (see http://en.wikipedia.org/wiki/Port). + +http://www.cebe.cc, http://www.cebe.net, and so on + +[link to http://www.google.com/](http://www.google.com/) + +contact me at http://cebe.cc/contact. diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/README b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/README new file mode 100644 index 00000000..f899a74e --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/README @@ -0,0 +1 @@ +All tests prefixed with `md1_` are taken from http://daringfireball.net/projects/downloads/MarkdownTest_1.0.zip \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote-nested.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote-nested.html new file mode 100644 index 00000000..4bf4289c --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote-nested.html @@ -0,0 +1,11 @@ +

    This is a header.

    +
      +
    1. This is the first list item.
    2. +
    3. This is the second list item.
    4. +
    +

    Here's some example code:

    +
    return shell_exec("echo $input | $markdown_script");
    +
    +

    quote here

    +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote-nested.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote-nested.md new file mode 100644 index 00000000..a20b01e8 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote-nested.md @@ -0,0 +1,10 @@ +> ## This is a header. +> +> 1. This is the first list item. +> 2. This is the second list item. +> +> Here's some example code: +> +> return shell_exec("echo $input | $markdown_script"); +> +> > quote here \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote.html new file mode 100644 index 00000000..ea8fcf8a --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote.html @@ -0,0 +1,9 @@ +

    test test +test

    +
    +

    test +test +test

    +
    +

    test

    +

    >this is not a quote

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote.md new file mode 100644 index 00000000..83217736 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/blockquote.md @@ -0,0 +1,10 @@ +> test test +> test + +> test +test +test + +test + +>this is not a quote \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/code.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/code.html new file mode 100644 index 00000000..4f06e82c --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/code.html @@ -0,0 +1,17 @@ +

    this is inline code

    +

    this is `inline code`

    +

    this is inline code

    +

    this is inline ` code

    +

    this is inline `` code

    +
    code block
    +
    +code block
    +
    +

    this is code too: co +ooo +de

    +

    A code block enclosed in brackets: [somecode].

    +

    A code block enclosed in brackets: [ somecode ].

    +

    A code block enclosed in a link: somecode.

    +

    A code block enclosed in image brackets: ![somecode].

    +

    A code block enclosed in image brackets: ![ somecode ].

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/code.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/code.md new file mode 100644 index 00000000..1e84faeb --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/code.md @@ -0,0 +1,27 @@ +this is `inline code` + +this is ``inline code`` + +this is `` inline code `` + +this is `` inline ` code `` + +this is ``` inline `` code ``` + + code block + + code block + +this is code too: ` co +ooo +de ` + +A code block enclosed in brackets: [`somecode`]. + +A code block enclosed in brackets: [ `somecode` ]. + +A code block enclosed in a link: [`somecode`](./url.md). + +A code block enclosed in image brackets: ![`somecode`]. + +A code block enclosed in image brackets: ![ `somecode` ]. diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dense-block-markers.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dense-block-markers.html new file mode 100644 index 00000000..964949ca --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dense-block-markers.html @@ -0,0 +1,50 @@ +

    this is to test dense blocks (no newlines between them)

    +
    +

    what is Markdown?

    +

    see Wikipedia

    +

    a h2

    +

    paragraph

    +

    this is a paragraph, not a headline or list +next line +- whoo

    +

    par

    +
    code
    +code
    +
    +

    par

    +

    Tasks list

    +
      +
    • list items
    • +
    +

    headline1

    +

    quote +quote

    +
    +

    headline2

    +
    +

    h1

    +

    h2

    +
    +

    h3

    +
      +
    1. ol1
    2. +
    3. ol2
    4. +
    +

    h4

    +
      +
    • listA
    • +
    • listB
    • +
    +
    h5
    +
    h6
    +
    +
    +

    changelog 1

    +
      +
    • 17-Feb-2013 re-design
    • +
    +
    +

    changelog 2

    +
      +
    • 17-Feb-2013 re-design
    • +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dense-block-markers.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dense-block-markers.md new file mode 100644 index 00000000..ea365b86 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dense-block-markers.md @@ -0,0 +1,56 @@ +# this is to test dense blocks (no newlines between them) + +---- +## what is Markdown? +see [Wikipedia][] + +a h2 +---- +paragraph + +this is a paragraph, not a headline or list +next line +- whoo + +par + code + code +par + +### Tasks list +- list items + +headline1 +--------- +> quote +> quote + +[Wikipedia]: http://en.wikipedia.org/wiki/Markdown +headline2 +--------- + +---- +# h1 +## h2 +--- +### h3 +1. ol1 +2. ol2 + +#### h4 +- listA +- listB + +##### h5 +###### h6 +-------- + +---- + +## changelog 1 + +* 17-Feb-2013 re-design + +---- +## changelog 2 +* 17-Feb-2013 re-design \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos.html new file mode 100644 index 00000000..991bb2ca --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos.html @@ -0,0 +1,2549 @@ +

    example* +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos.md new file mode 100644 index 00000000..0bff4811 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos.md @@ -0,0 +1,2549 @@ +example* +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos2.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos2.html new file mode 100644 index 00000000..5d2651e4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos2.html @@ -0,0 +1,2549 @@ +

    example** +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos2.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos2.md new file mode 100644 index 00000000..a96055c0 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/dos2.md @@ -0,0 +1,2549 @@ +example** +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example +example \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/emphasis.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/emphasis.html new file mode 100644 index 00000000..4f6316cf --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/emphasis.html @@ -0,0 +1,34 @@ +

    this is strong and this is strong.

    +

    this is em and this is em.

    +

    code code

    +

    codecodecode

    +

    Hey this is +italic

    +

    Hey this is +bold

    +

    strong textemphasized text

    +

    emphasized textstrong text

    +

    strong textemphasized text

    +

    emphasized textstrong text

    +

    strong textemphasized text

    +

    emphasized textstrong text

    +

    simple_word_with_underscores

    +

    this is text, this is emph simple_word_with_underscores text again.

    +

    highlight something inside of a word. abc.

    +

    a a*b

    +

    a a_b

    +

    a a*b

    +

    a a_b

    +

    a this is strong

    +

    a this is strong

    +

    a this is strong

    +

    a * ABC

    +

    a AB

    +

    a A____B

    +

    a AB

    +

    a A****B

    +

    5 * 4 = 20

    +

    **

    +

    aha * * haha

    +

    em_text strong__text_

    +

    em*text strong**text*

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/emphasis.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/emphasis.md new file mode 100644 index 00000000..71ab5070 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/emphasis.md @@ -0,0 +1,65 @@ +this is __strong__ and this is **strong**. + +this is _em_ and this is *em*. + +_`code`_ __`code`__ + +*`code`**`code`**`code`* + +Hey *this is +italic* + +Hey **this is +bold** + +**strong text***emphasized text* + +*emphasized text***strong text** + +**strong text**_emphasized text_ + +*emphasized text*__strong text__ + +__strong text__*emphasized text* + +_emphasized text_**strong text** + +simple_word_with_underscores + +this is text, _this is emph_ simple_word_with_underscores text again. + +highlight something in**side** of a word. a**b**c. + +a ** a\*b ** + +a __ a\_b __ + +a * a\*b * + +a _ a\_b _ + +a **this *is* strong** + +a *this **is** strong* + +a ***this is strong*** + +a **\* ABC** + +a **A****B** + +a **A____B** + +a __A____B__ + +a __A****B__ + +5 * 4 = 20 + +** + +aha * * haha + +_em\_text_ __strong\_\_text\___ + +*em\*text* **strong\*\*text\*** diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/empty-line.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/empty-line.html new file mode 100644 index 00000000..6bebbf49 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/empty-line.html @@ -0,0 +1,8 @@ +

    0

    +

    0 +Lorem ipsum dolor

    +

    Lorem ipsum dolor +0

    +
    code
    +
    +

    0

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/empty-line.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/empty-line.md new file mode 100644 index 00000000..8d3a11a8 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/empty-line.md @@ -0,0 +1,11 @@ +0 + +0 +Lorem ipsum dolor + +Lorem ipsum dolor +0 + + code +0 + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/endless_loop_bug.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/endless_loop_bug.html new file mode 100644 index 00000000..4460837a --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/endless_loop_bug.html @@ -0,0 +1,9 @@ +

    Creating an Action

    +

    For the "Hello" task, you will create a say action that reads +a message parameter from the request and displays that message back to the user. If the request +does not provide a message parameter, the action will display the default "Hello" message.

    +

    Info: Actions are the objects that end users can directly refer to for + execution. Actions are grouped by controllers. The execution result of + an action is the response that an end user will receive.

    +
    +

    Actions must be declared in ...

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/endless_loop_bug.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/endless_loop_bug.md new file mode 100644 index 00000000..acd289fa --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/endless_loop_bug.md @@ -0,0 +1,12 @@ +Creating an Action +------------------ + +For the "Hello" task, you will create a `say` [action](structure-controllers.md#creating-actions) that reads +a `message` parameter from the request and displays that message back to the user. If the request +does not provide a `message` parameter, the action will display the default "Hello" message. + +> Info: [Actions](structure-controllers.md#creating-actions) are the objects that end users can directly refer to for + execution. Actions are grouped by [controllers](structure-controllers.md). The execution result of + an action is the response that an end user will receive. + +Actions must be declared in ... diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/escape-in-link.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/escape-in-link.html new file mode 100644 index 00000000..d6c40bab --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/escape-in-link.html @@ -0,0 +1,3 @@ +

    nice video. Nice-vide\o star *

    +

    nice video. Nice-vide\o star *

    +

    video and http://www.youtube.com/video-on\e and m\a-il@cebe.cc

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/escape-in-link.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/escape-in-link.md new file mode 100644 index 00000000..c9b5aa2d --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/escape-in-link.md @@ -0,0 +1,7 @@ +nice [video](http://www.youtube.com/video\-on\e). Nice\-vide\o star \* + +nice ![video](http://www.youtube.com/video\-on\e). Nice\-vide\o star \* + +[video]: http://www.youtube.com/video\-on\e + +[video] and and diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/headline.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/headline.html new file mode 100644 index 00000000..998b2acd --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/headline.html @@ -0,0 +1,21 @@ +

    a h1 heading

    +

    par1

    +

    a h2 heading

    +

    par2

    +

    a h4 heading

    +

    par3

    +

    another h1

    +

    par4

    +

    another h2

    +

    par5

    +

    a h4 heading

    +

    a h4 heading

    +
    h6
    +
    h7
    +

    +

    head

    +

    hallo +hallo

    +

    test

    +

    test

    +

    #1 has been fixed

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/headline.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/headline.md new file mode 100644 index 00000000..f0bd8a5d --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/headline.md @@ -0,0 +1,41 @@ +# a h1 heading + +par1 + +## a h2 heading + +par2 + +#### a h4 heading + +par3 + +another h1 +========== + +par4 + +another h2 +---------- + +par5 + +#### a h4 heading #### + +#### a h4 heading ######## + +###### h6 + +####### h7 + + +head +---- + +hallo +hallo +test +==== +test + +#1 has been fixed diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/hr.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/hr.html new file mode 100644 index 00000000..a1dcf598 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/hr.html @@ -0,0 +1,15 @@ +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    **

    +

    --

    +

    ––

    +

    *

    +

    -

    +

    –

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/hr.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/hr.md new file mode 100644 index 00000000..4f9ea2dc --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/hr.md @@ -0,0 +1,29 @@ +- - - + +--- + +------ + +_ _ _ + +___ + +_____________ + +********* + +* * * + +*** + +** + +-- + +–– + +* + +- + +– \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/html-block.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/html-block.html new file mode 100644 index 00000000..738b51bd --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/html-block.html @@ -0,0 +1,42 @@ +

    paragraph 1 is here

    + + + + + + + + + +
    ab
    cd
    +

    more markdown here

    +

    < this is not an html tag

    +

    <thisisnotanhtmltag

    +

    but this is:

    +

    some alt aligned with src attribute

    +

    some inline md

    +

    some inline md

    +

    self-closing on block level:

    +

    this is a paragraph

    +
    +

    something bold.

    + +

    h1

    + +

    h2

    +

    p some alt aligned with src attribute + something

    +

    p some alt aligned with src attribute

    +
    something
    +
    +

    p is < than 5

    +
    this is code
    +
    +

    this paragraph contains a +newline

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/html-block.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/html-block.md new file mode 100644 index 00000000..ac8c9ae2 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/html-block.md @@ -0,0 +1,59 @@ +paragraph 1 is here + + + + + + + + + + +
    ab
    cd
    + +more markdown here + +< this is not an html tag + + + +some inline **md** + +some inline **md** + +self-closing on block level: + +

    this is a paragraph

    +
    + +something **bold**. + + + +# h1 + + + +## h2 + +p some alt aligned with src attribute + something + +p some alt aligned with src attribute + something + +p is < than 5 + this is code + +this paragraph contains a +newline diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/images.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/images.html new file mode 100644 index 00000000..e7c76793 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/images.html @@ -0,0 +1,14 @@ +

    Total Downloads +Build Status

    +

    Here is an image tag: Total Downloads.

    +

    Images inside of links: +Total Downloads + +Build Status +Build Status

    +

    This is not an image: ![[ :-)

    +

    This is not an image: ![[ :-)]]

    +

    Alt text

    +

    Alt text

    +

    Alt text

    +

    Alt text

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/images.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/images.md new file mode 100644 index 00000000..cf933671 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/images.md @@ -0,0 +1,22 @@ +![Total Downloads](https://poser.pugx.org/cebe/markdown/downloads.png) +![Build Status](https://secure.travis-ci.org/cebe/markdown.png "test1") + +Here is an image tag: ![Total Downloads](https://poser.pugx.org/cebe/markdown/downloads.png). + +Images inside of links: +[![Total Downloads](https://poser.pugx.org/cebe/markdown/downloads.png)](https://packagist.org/packages/cebe/markdown) + +[![Build Status](https://secure.travis-ci.org/cebe/markdown.png "test2")](http://travis-ci.org/cebe/markdown) +[![Build Status](https://secure.travis-ci.org/cebe/markdown.png "test3")](http://travis-ci.org/cebe/markdown "test4") + +This is not an image: ![[ :-) + +This is not an image: ![[ :-)]] + +![Alt text](/path/to/img.jpg) + +![Alt text]( /path/to/img.jpg) + +![Alt text]( /path/to/img.jpg ) + +![Alt text](/path/to/img.jpg ) \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/inline-html.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/inline-html.html new file mode 100644 index 00000000..9038bf35 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/inline-html.html @@ -0,0 +1,11 @@ +

    this is inline html trailing

    +

    © AT&T

    +

    this is deleted this is not +new text on new line

    +

    this is deleted this is not +new text on new line

    +

    this line ends with <

    +

    this line ends with &

    +

    contact me at mail@cebe.cc.

    +

    contact me at mail@cebe.cc.

    +

    contact me at http://cebe.cc/contact.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/inline-html.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/inline-html.md new file mode 100644 index 00000000..41d976ed --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/inline-html.md @@ -0,0 +1,19 @@ +this is inline **html** trailing + +© AT&T + +this is deleted this is not +new text on new line + +this is deleted this is not +new text on new line + +this line ends with < + +this line ends with & + +contact me at mail@cebe.cc. + +contact me at . + +contact me at . diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/lazy-list.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/lazy-list.html new file mode 100644 index 00000000..e732edab --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/lazy-list.html @@ -0,0 +1,43 @@ +
      +
    • Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, +viverra nec, fringilla in, laoreet vitae, risus.
    • +
    • Donec sit amet nisl. Aliquam semper ipsum sit amet velit. +Suspendisse id sem consectetuer libero luctus adipiscing.
    • +
    +
      +
    • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

      +
    • +
    • Donec sit amet nisl. Aliquam semper ipsum sit amet velit.

      +
    • +
    +
      +
    1. Item one.
    2. +
    3. Item two with some code:
      code one
      +
      +
    4. +
    +
      +
    1. Item one.

      +
    2. +
    3. Paragraph 1

      +

      Paragraph 2

      +
    4. +
    5. Item three with code:

      +
      code two
      +
      +
    6. +
    +

    Paragraph.

    +
      +
    • line1 +line2

      +

      line1 +line2

      +

      line1 +line2 +line3 +line4

      +
    • +
    +

    line 5

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/lazy-list.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/lazy-list.md new file mode 100644 index 00000000..3cf9e4d7 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/lazy-list.md @@ -0,0 +1,40 @@ +* Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, +viverra nec, fringilla in, laoreet vitae, risus. +* Donec sit amet nisl. Aliquam semper ipsum sit amet velit. +Suspendisse id sem consectetuer libero luctus adipiscing. + + +* Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + +* Donec sit amet nisl. Aliquam semper ipsum sit amet velit. + +1. Item one. +2. Item two with some code: + code one + + +1. Item one. + +2. Paragraph 1 + + Paragraph 2 + +3. Item three with code: + + code two + +Paragraph. + +- line1 +line2 + + line1 +line2 + + line1 +line2 +line3 +line4 + +line 5 \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/links.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/links.html new file mode 100644 index 00000000..9b293c38 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/links.html @@ -0,0 +1,14 @@ +

    Go search on http://google.com!

    +

    link should be url decoded: http://en.wikipedia.org/wiki/Mase_(disambiguation)

    +

    Brackets in url and backslashes in links:

    +

    About port info on wiki: port

    +

    About port info on wiki: port

    +

    I'm an inline-style link

    +

    I'm an inline-style link with title +and another one in the same paragraph: +I'm an inline-style link with title

    +

    I'm a relative reference to a repository file

    +

    Or leave it empty and use the link text itself

    +

    A link [in a link](http://example.com)

    +

    About port info on wiki: port

    +

    About port info on wiki: port

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/links.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/links.md new file mode 100644 index 00000000..326bbb2a --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/links.md @@ -0,0 +1,25 @@ +Go search on ! + +link should be url decoded: + +Brackets in url and backslashes in links: + +About port info on wiki: [port](http://en.wikipedia.org/wiki/Port_(computer_networking)) + +About port info on wiki: [port](http://en.wikipedia.org/wiki/Port_(computer_networking) "port wiki") + +[I'm an inline-style link](https://www.google.com) + +[I'm an inline-style link with title](https://www.google.com "Google's Homepage") +and another one in the same paragraph: +[I'm an inline-style link with title](https://www.google.com "Google's Homepage") + +[I'm a relative reference to a repository file](../blob/(master)/LICENSE) + +Or leave it empty and use the [link text itself]() + +A [link [in a link](http://example.com)](http://example.com) + +About port info on wiki: [port]( http://en.wikipedia.org/wiki/Port_(computer_networking) ) + +About port info on wiki: [port]( http://en.wikipedia.org/wiki/Port_(computer_networking) "port wiki" ) diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-marker-in-paragraph.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-marker-in-paragraph.html new file mode 100644 index 00000000..92d12197 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-marker-in-paragraph.html @@ -0,0 +1,7 @@ +

    In Markdown 1.0.0 and earlier. Version +8. This line turns into a list item. +Because a hard-wrapped line in the +middle of a paragraph looked like a +list item.

    +

    Here's one with a bullet. +* criminey

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-marker-in-paragraph.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-marker-in-paragraph.md new file mode 100644 index 00000000..54c49572 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-marker-in-paragraph.md @@ -0,0 +1,8 @@ +In Markdown 1.0.0 and earlier. Version +8. This line turns into a list item. +Because a hard-wrapped line in the +middle of a paragraph looked like a +list item. + +Here's one with a bullet. +* criminey \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-separated-by-hr.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-separated-by-hr.html new file mode 100644 index 00000000..a212c0e8 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-separated-by-hr.html @@ -0,0 +1,7 @@ +
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-separated-by-hr.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-separated-by-hr.md new file mode 100644 index 00000000..7bc6d467 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list-separated-by-hr.md @@ -0,0 +1,3 @@ +- foo +*** +- bar \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list.html new file mode 100644 index 00000000..ac7c863c --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list.html @@ -0,0 +1,59 @@ +
      +
    • item1
    • +
    • +
    • item2
    • +
    • item3
    • +
    +
    +
      +
    • item1
    • +
    • item2
    • +
    • item3
    • +
    +
    +
      +
    • item1
    • +
    • item2
    • +
    • item3
    • +
    +
    +
      +
    1. item1
    2. +
    3. item2
    4. +
    5. item3
    6. +
    +
    +
      +
    1. item1
    2. +
    3. item2
    4. +
    5. item3
    6. +
    +
    +
      +
    1. item1
    2. +
    3. item2
    4. +
    5. item3
    6. +
    +
    +
      +
    1. item1
    2. +
    3. item2
    4. +
    5. item3
    6. +
    +
    +
      +
    • more indented line
    • +
    • different indent +-not a list item
    • +
    +
    +
      +
    • one item
    • +
    +
    +
      +
    • List...

      +
    • +
    +

    Ensure the above will not throw Exception

    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list.md new file mode 100644 index 00000000..a8f0ba92 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list.md @@ -0,0 +1,60 @@ +- item1 +- +- item2 +- item3 + +--- + +* item1 +* item2 +* item3 + +--- + ++ item1 ++ item2 ++ item3 + +--- + +1. item1 +2. item2 +4. item3 + +--- + +4. item1 +12. item2 +125. item3 + +--- + +4. item1 +12. item2 +125. item3 + +--- + + 4. item1 + 12. item2 +125. item3 + +--- + +- more indented line +- different indent +-not a list item + +--- + +- one item + +--- + +- List... + + + +Ensure the above will not throw Exception + +--- \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_and_reference.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_and_reference.html new file mode 100644 index 00000000..62f40210 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_and_reference.html @@ -0,0 +1,9 @@ +

    link ref1

    +
      +
    • item 1 ref2
    • +
    • item 2
    • +
    +
      +
    • item 1 ref2
    • +
    • item 2
    • +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_and_reference.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_and_reference.md new file mode 100644 index 00000000..e19617b9 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_and_reference.md @@ -0,0 +1,13 @@ +link [ref1] + +- item 1 [ref2] +- item 2 + + [ref1]: http://example.com/a +[ref2]: http://example.com/b + + +- item 1 [ref2] +- item 2 + + [ref3]: http://example.com/a diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_items_with_undefined_ref.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_items_with_undefined_ref.html new file mode 100644 index 00000000..6cd231fc --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_items_with_undefined_ref.html @@ -0,0 +1,14 @@ +
      +
    • [[\yii\caching\ApcCache]]: uses PHP APC extension. This option can be +considered as the fastest one when dealing with cache for a centralized thick application (e.g. one +server, no dedicated load balancers, etc.).

      +
    • +
    • [[\yii\caching\DbCache]]: uses a database table to store cached data. By default, it will create and use a +SQLite3 database under the runtime directory. You can explicitly specify a database for +it to use by setting its db property.

      +
    • +
    +
      +
    • [[yii\caching\Cache::get()|get()]]: 指定ã•れãŸã‚­ãƒ¼ã‚’用ã„ã¦ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’å–å¾—ã—ã¾ã™ã€‚データãŒè¦‹ã¤ã‹ã‚‰ãªã„ã‹ã€ã‚‚ã—ãã¯æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚ŒãŸã‚Šç„¡åйã«ãªã£ãŸã‚Šã—ã¦ã„ã‚‹å ´åˆã¯ false ã‚’è¿”ã—ã¾ã™ã€‚
    • +
    • [[yii\caching\Cache::set()|set()]]: キーã«ã‚ˆã£ã¦è­˜åˆ¥ã•ã‚Œã‚‹ãƒ‡ãƒ¼ã‚¿ã‚’ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã«æ ¼ç´ã—ã¾ã™ã€‚
    • +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_items_with_undefined_ref.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_items_with_undefined_ref.md new file mode 100644 index 00000000..5ae7e828 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/list_items_with_undefined_ref.md @@ -0,0 +1,11 @@ +* [[\yii\caching\ApcCache]]: uses PHP [APC](http://php.net/manual/en/book.apc.php) extension. This option can be + considered as the fastest one when dealing with cache for a centralized thick application (e.g. one + server, no dedicated load balancers, etc.). + +* [[\yii\caching\DbCache]]: uses a database table to store cached data. By default, it will create and use a + [SQLite3](http://sqlite.org/) database under the runtime directory. You can explicitly specify a database for + it to use by setting its `db` property. + + +* [[yii\caching\Cache::get()|get()]]: 指定ã•れãŸã‚­ãƒ¼ã‚’用ã„ã¦ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’å–å¾—ã—ã¾ã™ã€‚データãŒè¦‹ã¤ã‹ã‚‰ãªã„ã‹ã€ã‚‚ã—ãã¯æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚ŒãŸã‚Šç„¡åйã«ãªã£ãŸã‚Šã—ã¦ã„ã‚‹å ´åˆã¯ false ã‚’è¿”ã—ã¾ã™ã€‚ +* [[yii\caching\Cache::set()|set()]]: キーã«ã‚ˆã£ã¦è­˜åˆ¥ã•ã‚Œã‚‹ãƒ‡ãƒ¼ã‚¿ã‚’ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã«æ ¼ç´ã—ã¾ã™ã€‚ diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_amps_and_angle_encoding.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_amps_and_angle_encoding.html new file mode 100644 index 00000000..959591fc --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_amps_and_angle_encoding.html @@ -0,0 +1,8 @@ +

    AT&T has an ampersand in their name.

    +

    AT&T is another way to write it.

    +

    This & that.

    +

    4 < 5.

    +

    6 > 5.

    +

    Here's a link with an ampersand in the URL.

    +

    Here's a link with an amersand in the link text: AT&T.

    +

    Here's an inline link.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_amps_and_angle_encoding.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_amps_and_angle_encoding.md new file mode 100644 index 00000000..55601f26 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_amps_and_angle_encoding.md @@ -0,0 +1,19 @@ +AT&T has an ampersand in their name. + +AT&T is another way to write it. + +This & that. + +4 < 5. + +6 > 5. + +Here's a [link] [1] with an ampersand in the URL. + +Here's a link with an amersand in the link text: [AT&T] [2]. + +Here's an inline [link](/script?foo=1&bar=2). + + +[1]: http://example.com/?foo=1&bar=2 +[2]: http://att.com/ "AT&T" \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_auto_links.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_auto_links.html new file mode 100644 index 00000000..8e85d010 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_auto_links.html @@ -0,0 +1,12 @@ +

    Link: http://example.com/.

    +

    With an ampersand: http://example.com/?foo=1&bar=2

    + +

    Blockquoted: http://example.com/

    +
    +

    Auto-links should not occur here: <http://example.com/>

    +
    or here: <http://example.com/>
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_auto_links.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_auto_links.md new file mode 100644 index 00000000..abbc4886 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_auto_links.md @@ -0,0 +1,13 @@ +Link: . + +With an ampersand: + +* In a list? +* +* It should. + +> Blockquoted: + +Auto-links should not occur here: `` + + or here: \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_backslash_escapes.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_backslash_escapes.html new file mode 100644 index 00000000..587a8d60 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_backslash_escapes.html @@ -0,0 +1,67 @@ +

    These should all get escaped:

    +

    Backslash: \

    +

    Backtick: `

    +

    Asterisk: *

    +

    Underscore: _

    +

    Left brace: {

    +

    Right brace: }

    +

    Left bracket: [

    +

    Right bracket: ]

    +

    Left paren: (

    +

    Right paren: )

    +

    Greater-than: >

    +

    Hash: #

    +

    Period: .

    +

    Bang: !

    +

    Plus: +

    +

    Minus: -

    +

    These should not, because they occur within a code block:

    +
    Backslash: \\
    +
    +Backtick: \`
    +
    +Asterisk: \*
    +
    +Underscore: \_
    +
    +Left brace: \{
    +
    +Right brace: \}
    +
    +Left bracket: \[
    +
    +Right bracket: \]
    +
    +Left paren: \(
    +
    +Right paren: \)
    +
    +Greater-than: \>
    +
    +Hash: \#
    +
    +Period: \.
    +
    +Bang: \!
    +
    +Plus: \+
    +
    +Minus: \-
    +
    +

    Nor should these, which occur in code spans:

    +

    Backslash: \\

    +

    Backtick: \`

    +

    Asterisk: \*

    +

    Underscore: \_

    +

    Left brace: \{

    +

    Right brace: \}

    +

    Left bracket: \[

    +

    Right bracket: \]

    +

    Left paren: \(

    +

    Right paren: \)

    +

    Greater-than: \>

    +

    Hash: \#

    +

    Period: \.

    +

    Bang: \!

    +

    Plus: \+

    +

    Minus: \-

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_backslash_escapes.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_backslash_escapes.md new file mode 100644 index 00000000..16447a01 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_backslash_escapes.md @@ -0,0 +1,104 @@ +These should all get escaped: + +Backslash: \\ + +Backtick: \` + +Asterisk: \* + +Underscore: \_ + +Left brace: \{ + +Right brace: \} + +Left bracket: \[ + +Right bracket: \] + +Left paren: \( + +Right paren: \) + +Greater-than: \> + +Hash: \# + +Period: \. + +Bang: \! + +Plus: \+ + +Minus: \- + + + +These should not, because they occur within a code block: + + Backslash: \\ + + Backtick: \` + + Asterisk: \* + + Underscore: \_ + + Left brace: \{ + + Right brace: \} + + Left bracket: \[ + + Right bracket: \] + + Left paren: \( + + Right paren: \) + + Greater-than: \> + + Hash: \# + + Period: \. + + Bang: \! + + Plus: \+ + + Minus: \- + + +Nor should these, which occur in code spans: + +Backslash: `\\` + +Backtick: `` \` `` + +Asterisk: `\*` + +Underscore: `\_` + +Left brace: `\{` + +Right brace: `\}` + +Left bracket: `\[` + +Right bracket: `\]` + +Left paren: `\(` + +Right paren: `\)` + +Greater-than: `\>` + +Hash: `\#` + +Period: `\.` + +Bang: `\!` + +Plus: `\+` + +Minus: `\-` diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_blockquotes_with_code_blocks.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_blockquotes_with_code_blocks.html new file mode 100644 index 00000000..fc69abb4 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_blockquotes_with_code_blocks.html @@ -0,0 +1,11 @@ +

    Example:

    +
    sub status {
    +    print "working";
    +}
    +
    +

    Or:

    +
    sub status {
    +    return "working";
    +}
    +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_blockquotes_with_code_blocks.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_blockquotes_with_code_blocks.md new file mode 100644 index 00000000..c31d1710 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_blockquotes_with_code_blocks.md @@ -0,0 +1,11 @@ +> Example: +> +> sub status { +> print "working"; +> } +> +> Or: +> +> sub status { +> return "working"; +> } diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_horizontal_rules.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_horizontal_rules.html new file mode 100644 index 00000000..a89efdbb --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_horizontal_rules.html @@ -0,0 +1,39 @@ +

    Dashes:

    +
    +
    +
    +
    +
    ---
    +
    +
    +
    +
    +
    +
    - - -
    +
    +

    Asterisks:

    +
    +
    +
    +
    +
    ***
    +
    +
    +
    +
    +
    +
    * * *
    +
    +

    Underscores:

    +
    +
    +
    +
    +
    ___
    +
    +
    +
    +
    +
    +
    _ _ _
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_horizontal_rules.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_horizontal_rules.md new file mode 100644 index 00000000..1594bda2 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_horizontal_rules.md @@ -0,0 +1,67 @@ +Dashes: + +--- + + --- + + --- + + --- + + --- + +- - - + + - - - + + - - - + + - - - + + - - - + + +Asterisks: + +*** + + *** + + *** + + *** + + *** + +* * * + + * * * + + * * * + + * * * + + * * * + + +Underscores: + +___ + + ___ + + ___ + + ___ + + ___ + +_ _ _ + + _ _ _ + + _ _ _ + + _ _ _ + + _ _ _ diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_avanced.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_avanced.html new file mode 100644 index 00000000..39f5a6e5 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_avanced.html @@ -0,0 +1,11 @@ +

    Simple block on one line:

    +
    foo
    +

    And nested without indentation:

    +
    +
    +
    +foo +
    +
    +
    bar
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_avanced.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_avanced.md new file mode 100644 index 00000000..9d71ddcc --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_avanced.md @@ -0,0 +1,14 @@ +Simple block on one line: + +
    foo
    + +And nested without indentation: + +
    +
    +
    +foo +
    +
    +
    bar
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_comments.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_comments.html new file mode 100644 index 00000000..8df5e1c7 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_comments.html @@ -0,0 +1,8 @@ +

    Paragraph one.

    + + +

    Paragraph two.

    + +

    The end.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_comments.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_comments.md new file mode 100644 index 00000000..41d830d0 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_comments.md @@ -0,0 +1,13 @@ +Paragraph one. + + + + + +Paragraph two. + + + +The end. diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_simple.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_simple.html new file mode 100644 index 00000000..237ce670 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_simple.html @@ -0,0 +1,46 @@ +

    Here's a simple block:

    +
    + foo +
    +

    This should be a code block, though:

    +
    <div>
    +	foo
    +</div>
    +
    +

    As should this:

    +
    <div>foo</div>
    +
    +

    Now, nested:

    +
    +
    +
    + foo +
    +
    +
    +

    This should just be an HTML comment:

    + +

    Multiline:

    + +

    Code block:

    +
    <!-- Comment -->
    +
    +

    Just plain comment, with trailing spaces on the line:

    + +

    Code:

    +
    <hr />
    +
    +
    +

    Hr's:

    +
    +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_simple.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_simple.md new file mode 100644 index 00000000..14aa2dc2 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_inline_html_simple.md @@ -0,0 +1,69 @@ +Here's a simple block: + +
    + foo +
    + +This should be a code block, though: + +
    + foo +
    + +As should this: + +
    foo
    + +Now, nested: + +
    +
    +
    + foo +
    +
    +
    + +This should just be an HTML comment: + + + +Multiline: + + + +Code block: + + + +Just plain comment, with trailing spaces on the line: + + + +Code: + +
    + +Hr's: + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_inline_style.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_inline_style.html new file mode 100644 index 00000000..9c992e76 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_inline_style.html @@ -0,0 +1,5 @@ +

    Just a URL.

    +

    URL and title.

    +

    URL and title.

    +

    URL and title.

    +

    Empty.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_inline_style.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_inline_style.md new file mode 100644 index 00000000..4d0c1c26 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_inline_style.md @@ -0,0 +1,9 @@ +Just a [URL](/url/). + +[URL and title](/url/ "title"). + +[URL and title](/url/ "title preceded by two spaces"). + +[URL and title](/url/ "title preceded by a tab"). + +[Empty](). diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_reference_style.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_reference_style.html new file mode 100644 index 00000000..0f297a80 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_reference_style.html @@ -0,0 +1,10 @@ +

    Foo bar.

    +

    Foo bar.

    +

    Foo bar.

    +

    With embedded [brackets].

    +

    Indented once.

    +

    Indented twice.

    +

    Indented thrice.

    +

    Indented [four][] times.

    +
    [four]: /url
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_reference_style.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_reference_style.md new file mode 100644 index 00000000..b2fa7345 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_links_reference_style.md @@ -0,0 +1,31 @@ +Foo [bar] [1]. + +Foo [bar][1]. + +Foo [bar] +[1]. + +[1]: /url/ "Title" + + +With [embedded [brackets]] [b]. + + +Indented [once][]. + +Indented [twice][]. + +Indented [thrice][]. + +Indented [four][] times. + + [once]: /url + + [twice]: /url + + [thrice]: /url + + [four]: /url + + +[b]: /url/ diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_literal_quotes_in_titles.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_literal_quotes_in_titles.html new file mode 100644 index 00000000..62e86412 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_literal_quotes_in_titles.html @@ -0,0 +1,2 @@ +

    Foo bar.

    +

    Foo bar.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_literal_quotes_in_titles.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_literal_quotes_in_titles.md new file mode 100644 index 00000000..29d0e423 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_literal_quotes_in_titles.md @@ -0,0 +1,7 @@ +Foo [bar][]. + +Foo [bar](/url/ "Title with "quotes" inside"). + + + [bar]: /url/ "Title with "quotes" inside" + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_markdown_documentation_basics.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_markdown_documentation_basics.html new file mode 100644 index 00000000..9f80b83f --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_markdown_documentation_basics.html @@ -0,0 +1,243 @@ +

    Markdown: Basics

    + +

    Getting the Gist of Markdown's Formatting Syntax

    +

    This page offers a brief overview of what it's like to use Markdown. +The syntax page provides complete, detailed documentation for +every feature, but Markdown should be very easy to pick up simply by +looking at a few examples of it in action. The examples on this page +are written in a before/after style, showing example syntax and the +HTML output produced by Markdown.

    +

    It's also helpful to simply try Markdown out; the Dingus is a +web application that allows you type your own Markdown-formatted text +and translate it to XHTML.

    +

    Note: This document is itself written using Markdown; you +can see the source for it by adding '.text' to the URL.

    +

    Paragraphs, Headers, Blockquotes

    +

    A paragraph is simply one or more consecutive lines of text, separated +by one or more blank lines. (A blank line is any line that looks like a +blank line -- a line containing nothing spaces or tabs is considered +blank.) Normal paragraphs should not be intended with spaces or tabs.

    +

    Markdown offers two styles of headers: Setext and atx. +Setext-style headers for <h1> and <h2> are created by +"underlining" with equal signs (=) and hyphens (-), respectively. +To create an atx-style header, you put 1-6 hash marks (#) at the +beginning of the line -- the number of hashes equals the resulting +HTML header level.

    +

    Blockquotes are indicated using email-style '>' angle brackets.

    +

    Markdown:

    +
    A First Level Header
    +====================
    +
    +A Second Level Header
    +---------------------
    +
    +Now is the time for all good men to come to
    +the aid of their country. This is just a
    +regular paragraph.
    +
    +The quick brown fox jumped over the lazy
    +dog's back.
    +
    +### Header 3
    +
    +> This is a blockquote.
    +> 
    +> This is the second paragraph in the blockquote.
    +>
    +> ## This is an H2 in a blockquote
    +
    +

    Output:

    +
    <h1>A First Level Header</h1>
    +
    +<h2>A Second Level Header</h2>
    +
    +<p>Now is the time for all good men to come to
    +the aid of their country. This is just a
    +regular paragraph.</p>
    +
    +<p>The quick brown fox jumped over the lazy
    +dog's back.</p>
    +
    +<h3>Header 3</h3>
    +
    +<blockquote>
    +    <p>This is a blockquote.</p>
    +    
    +    <p>This is the second paragraph in the blockquote.</p>
    +    
    +    <h2>This is an H2 in a blockquote</h2>
    +</blockquote>
    +
    +

    Phrase Emphasis

    +

    Markdown uses asterisks and underscores to indicate spans of emphasis.

    +

    Markdown:

    +
    Some of these words *are emphasized*.
    +Some of these words _are emphasized also_.
    +
    +Use two asterisks for **strong emphasis**.
    +Or, if you prefer, __use two underscores instead__.
    +
    +

    Output:

    +
    <p>Some of these words <em>are emphasized</em>.
    +Some of these words <em>are emphasized also</em>.</p>
    +
    +<p>Use two asterisks for <strong>strong emphasis</strong>.
    +Or, if you prefer, <strong>use two underscores instead</strong>.</p>
    +
    +

    Lists

    +

    Unordered (bulleted) lists use asterisks, pluses, and hyphens (*, ++, and -) as list markers. These three markers are +interchangable; this:

    +
    *   Candy.
    +*   Gum.
    +*   Booze.
    +
    +

    this:

    +
    +   Candy.
    ++   Gum.
    ++   Booze.
    +
    +

    and this:

    +
    -   Candy.
    +-   Gum.
    +-   Booze.
    +
    +

    all produce the same output:

    +
    <ul>
    +<li>Candy.</li>
    +<li>Gum.</li>
    +<li>Booze.</li>
    +</ul>
    +
    +

    Ordered (numbered) lists use regular numbers, followed by periods, as +list markers:

    +
    1.  Red
    +2.  Green
    +3.  Blue
    +
    +

    Output:

    +
    <ol>
    +<li>Red</li>
    +<li>Green</li>
    +<li>Blue</li>
    +</ol>
    +
    +

    If you put blank lines between items, you'll get <p> tags for the +list item text. You can create multi-paragraph list items by indenting +the paragraphs by 4 spaces or 1 tab:

    +
    *   A list item.
    +
    +    With multiple paragraphs.
    +
    +*   Another item in the list.
    +
    +

    Output:

    +
    <ul>
    +<li><p>A list item.</p>
    +<p>With multiple paragraphs.</p></li>
    +<li><p>Another item in the list.</p></li>
    +</ul>
    +
    +
    +

    Links

    +

    Markdown supports two styles for creating links: inline and +reference. With both styles, you use square brackets to delimit the +text you want to turn into a link.

    +

    Inline-style links use parentheses immediately after the link text. +For example:

    +
    This is an [example link](http://example.com/).
    +
    +

    Output:

    +
    <p>This is an <a href="http://example.com/">
    +example link</a>.</p>
    +
    +

    Optionally, you may include a title attribute in the parentheses:

    +
    This is an [example link](http://example.com/ "With a Title").
    +
    +

    Output:

    +
    <p>This is an <a href="http://example.com/" title="With a Title">
    +example link</a>.</p>
    +
    +

    Reference-style links allow you to refer to your links by names, which +you define elsewhere in your document:

    +
    I get 10 times more traffic from [Google][1] than from
    +[Yahoo][2] or [MSN][3].
    +
    +[1]: http://google.com/        "Google"
    +[2]: http://search.yahoo.com/  "Yahoo Search"
    +[3]: http://search.msn.com/    "MSN Search"
    +
    +

    Output:

    +
    <p>I get 10 times more traffic from <a href="http://google.com/"
    +title="Google">Google</a> than from <a href="http://search.yahoo.com/"
    +title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
    +title="MSN Search">MSN</a>.</p>
    +
    +

    The title attribute is optional. Link names may contain letters, +numbers and spaces, but are not case sensitive:

    +
    I start my morning with a cup of coffee and
    +[The New York Times][NY Times].
    +
    +[ny times]: http://www.nytimes.com/
    +
    +

    Output:

    +
    <p>I start my morning with a cup of coffee and
    +<a href="http://www.nytimes.com/">The New York Times</a>.</p>
    +
    +

    Images

    +

    Image syntax is very much like link syntax.

    +

    Inline (titles are optional):

    +
    ![alt text](/path/to/img.jpg "Title")
    +
    +

    Reference-style:

    +
    ![alt text][id]
    +
    +[id]: /path/to/img.jpg "Title"
    +
    +

    Both of the above examples produce the same output:

    +
    <img src="/path/to/img.jpg" alt="alt text" title="Title" />
    +
    +

    Code

    +

    In a regular paragraph, you can create code span by wrapping text in +backtick quotes. Any ampersands (&) and angle brackets (< or +>) will automatically be translated into HTML entities. This makes +it easy to use Markdown to write about HTML example code:

    +
    I strongly recommend against using any `<blink>` tags.
    +
    +I wish SmartyPants used named entities like `&mdash;`
    +instead of decimal-encoded entites like `&#8212;`.
    +
    +

    Output:

    +
    <p>I strongly recommend against using any
    +<code>&lt;blink&gt;</code> tags.</p>
    +
    +<p>I wish SmartyPants used named entities like
    +<code>&amp;mdash;</code> instead of decimal-encoded
    +entites like <code>&amp;#8212;</code>.</p>
    +
    +

    To specify an entire block of pre-formatted code, indent every line of +the block by 4 spaces or 1 tab. Just like with code spans, &, <, +and > characters will be escaped automatically.

    +

    Markdown:

    +
    If you want your page to validate under XHTML 1.0 Strict,
    +you've got to put paragraph tags in your blockquotes:
    +
    +    <blockquote>
    +        <p>For example.</p>
    +    </blockquote>
    +
    +

    Output:

    +
    <p>If you want your page to validate under XHTML 1.0 Strict,
    +you've got to put paragraph tags in your blockquotes:</p>
    +
    +<pre><code>&lt;blockquote&gt;
    +    &lt;p&gt;For example.&lt;/p&gt;
    +&lt;/blockquote&gt;
    +</code></pre>
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_markdown_documentation_basics.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_markdown_documentation_basics.md new file mode 100644 index 00000000..486055ca --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_markdown_documentation_basics.md @@ -0,0 +1,306 @@ +Markdown: Basics +================ + + + + +Getting the Gist of Markdown's Formatting Syntax +------------------------------------------------ + +This page offers a brief overview of what it's like to use Markdown. +The [syntax page] [s] provides complete, detailed documentation for +every feature, but Markdown should be very easy to pick up simply by +looking at a few examples of it in action. The examples on this page +are written in a before/after style, showing example syntax and the +HTML output produced by Markdown. + +It's also helpful to simply try Markdown out; the [Dingus] [d] is a +web application that allows you type your own Markdown-formatted text +and translate it to XHTML. + +**Note:** This document is itself written using Markdown; you +can [see the source for it by adding '.text' to the URL] [src]. + + [s]: /projects/markdown/syntax "Markdown Syntax" + [d]: /projects/markdown/dingus "Markdown Dingus" + [src]: /projects/markdown/basics.text + + +## Paragraphs, Headers, Blockquotes ## + +A paragraph is simply one or more consecutive lines of text, separated +by one or more blank lines. (A blank line is any line that looks like a +blank line -- a line containing nothing spaces or tabs is considered +blank.) Normal paragraphs should not be intended with spaces or tabs. + +Markdown offers two styles of headers: *Setext* and *atx*. +Setext-style headers for `

    ` and `

    ` are created by +"underlining" with equal signs (`=`) and hyphens (`-`), respectively. +To create an atx-style header, you put 1-6 hash marks (`#`) at the +beginning of the line -- the number of hashes equals the resulting +HTML header level. + +Blockquotes are indicated using email-style '`>`' angle brackets. + +Markdown: + + A First Level Header + ==================== + + A Second Level Header + --------------------- + + Now is the time for all good men to come to + the aid of their country. This is just a + regular paragraph. + + The quick brown fox jumped over the lazy + dog's back. + + ### Header 3 + + > This is a blockquote. + > + > This is the second paragraph in the blockquote. + > + > ## This is an H2 in a blockquote + + +Output: + +

    A First Level Header

    + +

    A Second Level Header

    + +

    Now is the time for all good men to come to + the aid of their country. This is just a + regular paragraph.

    + +

    The quick brown fox jumped over the lazy + dog's back.

    + +

    Header 3

    + +
    +

    This is a blockquote.

    + +

    This is the second paragraph in the blockquote.

    + +

    This is an H2 in a blockquote

    +
    + + + +### Phrase Emphasis ### + +Markdown uses asterisks and underscores to indicate spans of emphasis. + +Markdown: + + Some of these words *are emphasized*. + Some of these words _are emphasized also_. + + Use two asterisks for **strong emphasis**. + Or, if you prefer, __use two underscores instead__. + +Output: + +

    Some of these words are emphasized. + Some of these words are emphasized also.

    + +

    Use two asterisks for strong emphasis. + Or, if you prefer, use two underscores instead.

    + + + +## Lists ## + +Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`, +`+`, and `-`) as list markers. These three markers are +interchangable; this: + + * Candy. + * Gum. + * Booze. + +this: + + + Candy. + + Gum. + + Booze. + +and this: + + - Candy. + - Gum. + - Booze. + +all produce the same output: + +
      +
    • Candy.
    • +
    • Gum.
    • +
    • Booze.
    • +
    + +Ordered (numbered) lists use regular numbers, followed by periods, as +list markers: + + 1. Red + 2. Green + 3. Blue + +Output: + +
      +
    1. Red
    2. +
    3. Green
    4. +
    5. Blue
    6. +
    + +If you put blank lines between items, you'll get `

    ` tags for the +list item text. You can create multi-paragraph list items by indenting +the paragraphs by 4 spaces or 1 tab: + + * A list item. + + With multiple paragraphs. + + * Another item in the list. + +Output: + +

      +
    • A list item.

      +

      With multiple paragraphs.

    • +
    • Another item in the list.

    • +
    + + + +### Links ### + +Markdown supports two styles for creating links: *inline* and +*reference*. With both styles, you use square brackets to delimit the +text you want to turn into a link. + +Inline-style links use parentheses immediately after the link text. +For example: + + This is an [example link](http://example.com/). + +Output: + +

    This is an + example link.

    + +Optionally, you may include a title attribute in the parentheses: + + This is an [example link](http://example.com/ "With a Title"). + +Output: + +

    This is an + example link.

    + +Reference-style links allow you to refer to your links by names, which +you define elsewhere in your document: + + I get 10 times more traffic from [Google][1] than from + [Yahoo][2] or [MSN][3]. + + [1]: http://google.com/ "Google" + [2]: http://search.yahoo.com/ "Yahoo Search" + [3]: http://search.msn.com/ "MSN Search" + +Output: + +

    I get 10 times more traffic from Google than from Yahoo or MSN.

    + +The title attribute is optional. Link names may contain letters, +numbers and spaces, but are *not* case sensitive: + + I start my morning with a cup of coffee and + [The New York Times][NY Times]. + + [ny times]: http://www.nytimes.com/ + +Output: + +

    I start my morning with a cup of coffee and + The New York Times.

    + + +### Images ### + +Image syntax is very much like link syntax. + +Inline (titles are optional): + + ![alt text](/path/to/img.jpg "Title") + +Reference-style: + + ![alt text][id] + + [id]: /path/to/img.jpg "Title" + +Both of the above examples produce the same output: + + alt text + + + +### Code ### + +In a regular paragraph, you can create code span by wrapping text in +backtick quotes. Any ampersands (`&`) and angle brackets (`<` or +`>`) will automatically be translated into HTML entities. This makes +it easy to use Markdown to write about HTML example code: + + I strongly recommend against using any `` tags. + + I wish SmartyPants used named entities like `—` + instead of decimal-encoded entites like `—`. + +Output: + +

    I strongly recommend against using any + <blink> tags.

    + +

    I wish SmartyPants used named entities like + &mdash; instead of decimal-encoded + entites like &#8212;.

    + + +To specify an entire block of pre-formatted code, indent every line of +the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`, +and `>` characters will be escaped automatically. + +Markdown: + + If you want your page to validate under XHTML 1.0 Strict, + you've got to put paragraph tags in your blockquotes: + +
    +

    For example.

    +
    + +Output: + +

    If you want your page to validate under XHTML 1.0 Strict, + you've got to put paragraph tags in your blockquotes:

    + +
    <blockquote>
    +        <p>For example.</p>
    +    </blockquote>
    +    
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_nested_blockquotes.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_nested_blockquotes.html new file mode 100644 index 00000000..d9900349 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_nested_blockquotes.html @@ -0,0 +1,5 @@ +

    foo

    +

    bar

    +
    +

    foo

    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_nested_blockquotes.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_nested_blockquotes.md new file mode 100644 index 00000000..ed3c624f --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_nested_blockquotes.md @@ -0,0 +1,5 @@ +> foo +> +> > bar +> +> foo diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_ordered_and_unordered_lists.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_ordered_and_unordered_lists.html new file mode 100644 index 00000000..e128e432 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_ordered_and_unordered_lists.html @@ -0,0 +1,125 @@ +

    Unordered

    +

    Asterisks tight:

    +
      +
    • asterisk 1
    • +
    • asterisk 2
    • +
    • asterisk 3
    • +
    +

    Asterisks loose:

    +
      +
    • asterisk 1

      +
    • +
    • asterisk 2

      +
    • +
    • asterisk 3

      +
    • +
    +
    +

    Pluses tight:

    +
      +
    • Plus 1
    • +
    • Plus 2
    • +
    • Plus 3
    • +
    +

    Pluses loose:

    +
      +
    • Plus 1

      +
    • +
    • Plus 2

      +
    • +
    • Plus 3

      +
    • +
    +
    +

    Minuses tight:

    +
      +
    • Minus 1
    • +
    • Minus 2
    • +
    • Minus 3
    • +
    +

    Minuses loose:

    +
      +
    • Minus 1

      +
    • +
    • Minus 2

      +
    • +
    • Minus 3

      +
    • +
    +

    Ordered

    +

    Tight:

    +
      +
    1. First
    2. +
    3. Second
    4. +
    5. Third
    6. +
    +

    and:

    +
      +
    1. One
    2. +
    3. Two
    4. +
    5. Three
    6. +
    +

    Loose using tabs:

    +
      +
    1. First

      +
    2. +
    3. Second

      +
    4. +
    5. Third

      +
    6. +
    +

    and using spaces:

    +
      +
    1. One

      +
    2. +
    3. Two

      +
    4. +
    5. Three

      +
    6. +
    +

    Multiple paragraphs:

    +
      +
    1. Item 1, graf one.

      +

      Item 2. graf two. The quick brown fox jumped over the lazy dog's +back.

      +
    2. +
    3. Item 2.

      +
    4. +
    5. Item 3.

      +
    6. +
    +

    Nested

    +
      +
    • Tab
        +
      • Tab
          +
        • Tab
        • +
        +
      • +
      +
    • +
    +

    Here's another:

    +
      +
    1. First
    2. +
    3. Second:
        +
      • Fee
      • +
      • Fie
      • +
      • Foe
      • +
      +
    4. +
    5. Third
    6. +
    +

    Same thing but with paragraphs:

    +
      +
    1. First

      +
    2. +
    3. Second:

      +
        +
      • Fee
      • +
      • Fie
      • +
      • Foe
      • +
      +
    4. +
    5. Third

      +
    6. +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_ordered_and_unordered_lists.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_ordered_and_unordered_lists.md new file mode 100644 index 00000000..726b1375 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_ordered_and_unordered_lists.md @@ -0,0 +1,123 @@ +## Unordered + +Asterisks tight: + +* asterisk 1 +* asterisk 2 +* asterisk 3 + + +Asterisks loose: + +* asterisk 1 + +* asterisk 2 + +* asterisk 3 + +- - - + +Pluses tight: + ++ Plus 1 ++ Plus 2 ++ Plus 3 + + +Pluses loose: + ++ Plus 1 + ++ Plus 2 + ++ Plus 3 + +* * * + + +Minuses tight: + +- Minus 1 +- Minus 2 +- Minus 3 + + +Minuses loose: + +- Minus 1 + +- Minus 2 + +- Minus 3 + + +## Ordered + +Tight: + +1. First +2. Second +3. Third + +and: + +1. One +2. Two +3. Three + + +Loose using tabs: + +1. First + +2. Second + +3. Third + +and using spaces: + +1. One + +2. Two + +3. Three + +Multiple paragraphs: + +1. Item 1, graf one. + + Item 2. graf two. The quick brown fox jumped over the lazy dog's + back. + +2. Item 2. + +3. Item 3. + + + +## Nested + +* Tab + * Tab + * Tab + +Here's another: + +1. First +2. Second: + * Fee + * Fie + * Foe +3. Third + +Same thing but with paragraphs: + +1. First + +2. Second: + + * Fee + * Fie + * Foe + +3. Third diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_strong_and_em_together.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_strong_and_em_together.html new file mode 100644 index 00000000..26295948 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_strong_and_em_together.html @@ -0,0 +1,4 @@ +

    This is strong and em.

    +

    So is this word.

    +

    This is strong and em.

    +

    So is this word.

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_strong_and_em_together.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_strong_and_em_together.md new file mode 100644 index 00000000..95ee690d --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_strong_and_em_together.md @@ -0,0 +1,7 @@ +***This is strong and em.*** + +So is ***this*** word. + +___This is strong and em.___ + +So is ___this___ word. diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tabs.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tabs.html new file mode 100644 index 00000000..82110b92 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tabs.html @@ -0,0 +1,21 @@ +
      +
    • this is a list item +indented with tabs

      +
    • +
    • this is a list item +indented with spaces

      +
    • +
    +

    Code:

    +
    this code block is indented by one tab
    +
    +

    And:

    +
    	this code block is indented by two tabs
    +
    +

    And:

    +
    +	this is an example list item
    +	indented with tabs
    +
    ++   this is an example list item
    +    indented with spaces
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tabs.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tabs.md new file mode 100644 index 00000000..589d1136 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tabs.md @@ -0,0 +1,21 @@ ++ this is a list item + indented with tabs + ++ this is a list item + indented with spaces + +Code: + + this code block is indented by one tab + +And: + + this code block is indented by two tabs + +And: + + + this is an example list item + indented with tabs + + + this is an example list item + indented with spaces diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tidyness.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tidyness.html new file mode 100644 index 00000000..564644df --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tidyness.html @@ -0,0 +1,7 @@ +

    A list within a blockquote:

    +
      +
    • asterisk 1
    • +
    • asterisk 2
    • +
    • asterisk 3
    • +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tidyness.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tidyness.md new file mode 100644 index 00000000..5f18b8da --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/md1_tidyness.md @@ -0,0 +1,5 @@ +> A list within a blockquote: +> +> * asterisk 1 +> * asterisk 2 +> * asterisk 3 diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/nested-lists.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/nested-lists.html new file mode 100644 index 00000000..8c1efabd --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/nested-lists.html @@ -0,0 +1,150 @@ +
      +
    • list1
    • +
    • list2
    • +
    • list3
    • +
    +
    +
      +
    • list1
        +
      • list2
      • +
      +
    • +
    • list3
    • +
    +
    +
      +
    • list1
    • +
    • list2
    • +
    • list3
    • +
    +
    +
      +
    • list1
        +
      • list2
      • +
      +
    • +
    • list3
    • +
    +
    +
      +
    • list1
    • +
    • list2
    • +
    • list3
    • +
    +
    +
      +
    • list1
        +
      • list2
      • +
      +
    • +
    • list3
    • +
    +
    +
      +
    • list1
    • +
    • list2
    • +
    • list3
    • +
    +
    +
      +
    • list1
        +
      • list2
      • +
      +
    • +
    • list3
    • +
    +
    +
      +
    1. li

      +
    2. +
    3. li

      +
        +
      • li
      • +
      • li
      • +
      +
    4. +
    5. li

      +
    6. +
    +
    +
      +
    1. li
    2. +
    3. li
        +
      • li
      • +
      • li
      • +
      +
    4. +
    5. li
    6. +
    +
    +
      +
    • li

      +
    • +
    • li

      +
        +
      1. li
      2. +
      3. li
      4. +
      +
    • +
    • li

      +
    • +
    +
    +
      +
    • li
    • +
    • li
        +
      1. li
      2. +
      3. li
      4. +
      +
    • +
    • li
    • +
    +
    +
      +
    • test
    • +
    • test
        +
      • test
      • +
      • test
      • +
      +
    • +
    • test
    • +
    +
    +
      +
    • test
    • +
    • test

      +
        +
      • test
      • +
      • test
      • +
      +
    • +
    • test

      +
    • +
    +
    +
      +
    • test
    • +
    • test

      +
        +
      • test
      • +
      • test
      • +
      +
    • +
    • test
    • +
    +
    +
      +
    • test

      +
    • +
    • test

      +
        +
      • test

        +
      • +
      • test

        +
      • +
      +
    • +
    • test

      +
    • +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/nested-lists.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/nested-lists.md new file mode 100644 index 00000000..e0c12508 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/nested-lists.md @@ -0,0 +1,123 @@ +- list1 + - list2 +- list3 + +------ + +- list1 + - list2 +- list3 + +------ + + - list1 + - list2 + - list3 + +------ + + - list1 + - list2 + - list3 + +------ + + - list1 + - list2 + - list3 + +------ + + - list1 + - list2 + - list3 + +------ + + - list1 + - list2 + - list3 + +------ + + - list1 + - list2 + - list3 + +------ + +1. li + +2. li + + - li + - li + +3. li + +------ + +1. li +2. li + - li + - li +3. li + +------ + +- li + +- li + + 1. li + 2. li + +- li + +------ + +- li +- li + 1. li + 2. li +- li + +------ + +- test +- test + - test + - test +- test + +------ + +- test +- test + + - test + - test + +- test + +------ +- test +- test + + - test + - test +- test + +------ + +- test + +- test + + - test + + - test + +- test + +------ diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/newline.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/newline.html new file mode 100644 index 00000000..96303f2c --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/newline.html @@ -0,0 +1,3 @@ +

    This is a paragraph with a newline
    +next line

    +

    next par

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/newline.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/newline.md new file mode 100644 index 00000000..26b4354f --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/newline.md @@ -0,0 +1,4 @@ +This is a paragraph with a newline +next line + +next par diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/paragraph.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/paragraph.html new file mode 100644 index 00000000..6cd6d65d --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/paragraph.html @@ -0,0 +1,3 @@ +

    paragraph1 word2

    +

    paragraph2 word2 word3 +paragraph2 line2

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/paragraph.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/paragraph.md new file mode 100644 index 00000000..174c30e7 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/paragraph.md @@ -0,0 +1,4 @@ +paragraph1 word2 + +paragraph2 word2 word3 +paragraph2 line2 \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/references.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/references.html new file mode 100644 index 00000000..d2470c8f --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/references.html @@ -0,0 +1,11 @@ +

    In the following example we will im[ple]ment support for fenced code blocks which are part +of the github flavored markdown.

    +

    hey, check this.

    +

    ref on end of line this +next line.

    +

    this is a multi +line reference.

    +

    this is a Link +with reference.

    +

    [ ]

    +

    [not a] reference

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/references.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/references.md new file mode 100644 index 00000000..451c3c6f --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/references.md @@ -0,0 +1,27 @@ +In the following example we will im[ple]ment support for [fenced code blocks][] which are part +of the [github flavored markdown][gfm]. + +[fenced code blocks]: https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks + "Fenced code block feature of github flavored markdown" +[gfm]: https://github.com +[unused]: https://github.com/unused + +hey, check [this]. + +[this]: https://github.com/cebe/markdown + +ref on end of line [this] +next line. + +this is a [multi +line] reference. + +this is a [Link +with][multi +line] reference. + +[multi line]: http://example.com + +[ ] + +[not a] reference \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/specs.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/specs.html new file mode 100644 index 00000000..275027ba --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/specs.html @@ -0,0 +1,717 @@ +

    Markdown: Syntax

    + + +

    Note: This document is itself written using Markdown; you +can see the source for it by adding '.text' to the URL.

    +
    +

    Overview

    +

    Philosophy

    +

    Markdown is intended to be as easy-to-read and easy-to-write as is feasible.

    +

    Readability, however, is emphasized above all else. A Markdown-formatted +document should be publishable as-is, as plain text, without looking +like it's been marked up with tags or formatting instructions. While +Markdown's syntax has been influenced by several existing text-to-HTML +filters -- including Setext, atx, Textile, reStructuredText, +Grutatext, and EtText -- the single biggest source of +inspiration for Markdown's syntax is the format of plain text email.

    +

    To this end, Markdown's syntax is comprised entirely of punctuation +characters, which punctuation characters have been carefully chosen so +as to look like what they mean. E.g., asterisks around a word actually +look like *emphasis*. Markdown lists look like, well, lists. Even +blockquotes look like quoted passages of text, assuming you've ever +used email.

    +

    Inline HTML

    +

    Markdown's syntax is intended for one purpose: to be used as a +format for writing for the web.

    +

    Markdown is not a replacement for HTML, or even close to it. Its +syntax is very small, corresponding only to a very small subset of +HTML tags. The idea is not to create a syntax that makes it easier +to insert HTML tags. In my opinion, HTML tags are already easy to +insert. The idea for Markdown is to make it easy to read, write, and +edit prose. HTML is a publishing format; Markdown is a writing +format. Thus, Markdown's formatting syntax only addresses issues that +can be conveyed in plain text.

    +

    For any markup that is not covered by Markdown's syntax, you simply +use HTML itself. There's no need to preface it or delimit it to +indicate that you're switching from Markdown to HTML; you just use +the tags.

    +

    The only restrictions are that block-level HTML elements -- e.g. <div>, +<table>, <pre>, <p>, etc. -- must be separated from surrounding +content by blank lines, and the start and end tags of the block should +not be indented with tabs or spaces. Markdown is smart enough not +to add extra (unwanted) <p> tags around HTML block-level tags.

    +

    For example, to add an HTML table to a Markdown article:

    +
    This is a regular paragraph.
    +
    +<table>
    +    <tr>
    +        <td>Foo</td>
    +    </tr>
    +</table>
    +
    +This is another regular paragraph.
    +
    +

    Note that Markdown formatting syntax is not processed within block-level +HTML tags. E.g., you can't use Markdown-style *emphasis* inside an +HTML block.

    +

    Span-level HTML tags -- e.g. <span>, <cite>, or <del> -- can be +used anywhere in a Markdown paragraph, list item, or header. If you +want, you can even use HTML tags instead of Markdown formatting; e.g. if +you'd prefer to use HTML <a> or <img> tags instead of Markdown's +link or image syntax, go right ahead.

    +

    Unlike block-level HTML tags, Markdown syntax is processed within +span-level tags.

    +

    Automatic Escaping for Special Characters

    +

    In HTML, there are two characters that demand special treatment: < +and &. Left angle brackets are used to start tags; ampersands are +used to denote HTML entities. If you want to use them as literal +characters, you must escape them as entities, e.g. &lt;, and +&amp;.

    +

    Ampersands in particular are bedeviling for web writers. If you want to +write about 'AT&T', you need to write 'AT&amp;T'. You even need to +escape ampersands within URLs. Thus, if you want to link to:

    +
    http://images.google.com/images?num=30&q=larry+bird
    +
    +

    you need to encode the URL as:

    +
    http://images.google.com/images?num=30&amp;q=larry+bird
    +
    +

    in your anchor tag href attribute. Needless to say, this is easy to +forget, and is probably the single most common source of HTML validation +errors in otherwise well-marked-up web sites.

    +

    Markdown allows you to use these characters naturally, taking care of +all the necessary escaping for you. If you use an ampersand as part of +an HTML entity, it remains unchanged; otherwise it will be translated +into &amp;.

    +

    So, if you want to include a copyright symbol in your article, you can write:

    +
    &copy;
    +
    +

    and Markdown will leave it alone. But if you write:

    +
    AT&T
    +
    +

    Markdown will translate it to:

    +
    AT&amp;T
    +
    +

    Similarly, because Markdown supports inline HTML, if you use +angle brackets as delimiters for HTML tags, Markdown will treat them as +such. But if you write:

    +
    4 < 5
    +
    +

    Markdown will translate it to:

    +
    4 &lt; 5
    +
    +

    However, inside Markdown code spans and blocks, angle brackets and +ampersands are always encoded automatically. This makes it easy to use +Markdown to write about HTML code. (As opposed to raw HTML, which is a +terrible format for writing about HTML syntax, because every single < +and & in your example code needs to be escaped.)

    +
    +

    Block Elements

    +

    Paragraphs and Line Breaks

    +

    A paragraph is simply one or more consecutive lines of text, separated +by one or more blank lines. (A blank line is any line that looks like a +blank line -- a line containing nothing but spaces or tabs is considered +blank.) Normal paragraphs should not be indented with spaces or tabs.

    +

    The implication of the "one or more consecutive lines of text" rule is +that Markdown supports "hard-wrapped" text paragraphs. This differs +significantly from most other text-to-HTML formatters (including Movable +Type's "Convert Line Breaks" option) which translate every line break +character in a paragraph into a <br /> tag.

    +

    When you do want to insert a <br /> break tag using Markdown, you +end a line with two or more spaces, then type return.

    +

    Yes, this takes a tad more effort to create a <br />, but a simplistic +"every line break is a <br />" rule wouldn't work for Markdown. +Markdown's email-style blockquoting and multi-paragraph list items +work best -- and look better -- when you format them with hard breaks.

    + +

    Markdown supports two styles of headers, Setext and atx.

    +

    Setext-style headers are "underlined" using equal signs (for first-level +headers) and dashes (for second-level headers). For example:

    +
    This is an H1
    +=============
    +
    +This is an H2
    +-------------
    +
    +

    Any number of underlining ='s or -'s will work.

    +

    Atx-style headers use 1-6 hash characters at the start of the line, +corresponding to header levels 1-6. For example:

    +
    # This is an H1
    +
    +## This is an H2
    +
    +###### This is an H6
    +
    +

    Optionally, you may "close" atx-style headers. This is purely +cosmetic -- you can use this if you think it looks better. The +closing hashes don't even need to match the number of hashes +used to open the header. (The number of opening hashes +determines the header level.) :

    +
    # This is an H1 #
    +
    +## This is an H2 ##
    +
    +### This is an H3 ######
    +
    +

    Blockquotes

    +

    Markdown uses email-style > characters for blockquoting. If you're +familiar with quoting passages of text in an email message, then you +know how to create a blockquote in Markdown. It looks best if you hard +wrap the text and put a > before every line:

    +
    > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
    +> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
    +> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
    +>
    +> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
    +> id sem consectetuer libero luctus adipiscing.
    +
    +

    Markdown allows you to be lazy and only put the > before the first +line of a hard-wrapped paragraph:

    +
    > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
    +consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
    +Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
    +
    +> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
    +id sem consectetuer libero luctus adipiscing.
    +
    +

    Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by +adding additional levels of >:

    +
    > This is the first level of quoting.
    +>
    +> > This is nested blockquote.
    +>
    +> Back to the first level.
    +
    +

    Blockquotes can contain other Markdown elements, including headers, lists, +and code blocks:

    +
    > ## This is a header.
    +>
    +> 1.   This is the first list item.
    +> 2.   This is the second list item.
    +>
    +> Here's some example code:
    +>
    +>     return shell_exec("echo $input | $markdown_script");
    +
    +

    Any decent text editor should make email-style quoting easy. For +example, with BBEdit, you can make a selection and choose Increase +Quote Level from the Text menu.

    +

    Lists

    +

    Markdown supports ordered (numbered) and unordered (bulleted) lists.

    +

    Unordered lists use asterisks, pluses, and hyphens -- interchangably +-- as list markers:

    +
    *   Red
    +*   Green
    +*   Blue
    +
    +

    is equivalent to:

    +
    +   Red
    ++   Green
    ++   Blue
    +
    +

    and:

    +
    -   Red
    +-   Green
    +-   Blue
    +
    +

    Ordered lists use numbers followed by periods:

    +
    1.  Bird
    +2.  McHale
    +3.  Parish
    +
    +

    It's important to note that the actual numbers you use to mark the +list have no effect on the HTML output Markdown produces. The HTML +Markdown produces from the above list is:

    +
    <ol>
    +<li>Bird</li>
    +<li>McHale</li>
    +<li>Parish</li>
    +</ol>
    +
    +

    If you instead wrote the list in Markdown like this:

    +
    1.  Bird
    +1.  McHale
    +1.  Parish
    +
    +

    or even:

    +
    3. Bird
    +1. McHale
    +8. Parish
    +
    +

    you'd get the exact same HTML output. The point is, if you want to, +you can use ordinal numbers in your ordered Markdown lists, so that +the numbers in your source match the numbers in your published HTML. +But if you want to be lazy, you don't have to.

    +

    If you do use lazy list numbering, however, you should still start the +list with the number 1. At some point in the future, Markdown may support +starting ordered lists at an arbitrary number.

    +

    List markers typically start at the left margin, but may be indented by +up to three spaces. List markers must be followed by one or more spaces +or a tab.

    +

    To make lists look nice, you can wrap items with hanging indents:

    +
    *   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    +    Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
    +    viverra nec, fringilla in, laoreet vitae, risus.
    +*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
    +    Suspendisse id sem consectetuer libero luctus adipiscing.
    +
    +

    But if you want to be lazy, you don't have to:

    +
    *   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    +Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
    +viverra nec, fringilla in, laoreet vitae, risus.
    +*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
    +Suspendisse id sem consectetuer libero luctus adipiscing.
    +
    +

    If list items are separated by blank lines, Markdown will wrap the +items in <p> tags in the HTML output. For example, this input:

    +
    *   Bird
    +*   Magic
    +
    +

    will turn into:

    +
    <ul>
    +<li>Bird</li>
    +<li>Magic</li>
    +</ul>
    +
    +

    But this:

    +
    *   Bird
    +
    +*   Magic
    +
    +

    will turn into:

    +
    <ul>
    +<li><p>Bird</p></li>
    +<li><p>Magic</p></li>
    +</ul>
    +
    +

    List items may consist of multiple paragraphs. Each subsequent +paragraph in a list item must be indented by either 4 spaces +or one tab:

    +
    1.  This is a list item with two paragraphs. Lorem ipsum dolor
    +    sit amet, consectetuer adipiscing elit. Aliquam hendrerit
    +    mi posuere lectus.
    +
    +    Vestibulum enim wisi, viverra nec, fringilla in, laoreet
    +    vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
    +    sit amet velit.
    +
    +2.  Suspendisse id sem consectetuer libero luctus adipiscing.
    +
    +

    It looks nice if you indent every line of the subsequent +paragraphs, but here again, Markdown will allow you to be +lazy:

    +
    *   This is a list item with two paragraphs.
    +
    +    This is the second paragraph in the list item. You're
    +only required to indent the first line. Lorem ipsum dolor
    +sit amet, consectetuer adipiscing elit.
    +
    +*   Another item in the same list.
    +
    +

    To put a blockquote within a list item, the blockquote's > +delimiters need to be indented:

    +
    *   A list item with a blockquote:
    +
    +    > This is a blockquote
    +    > inside a list item.
    +
    +

    To put a code block within a list item, the code block needs +to be indented twice -- 8 spaces or two tabs:

    +
    *   A list item with a code block:
    +
    +        <code goes here>
    +
    +

    It's worth noting that it's possible to trigger an ordered list by +accident, by writing something like this:

    +
    1986. What a great season.
    +
    +

    In other words, a number-period-space sequence at the beginning of a +line. To avoid this, you can backslash-escape the period:

    +
    1986\. What a great season.
    +
    +

    Code Blocks

    +

    Pre-formatted code blocks are used for writing about programming or +markup source code. Rather than forming normal paragraphs, the lines +of a code block are interpreted literally. Markdown wraps a code block +in both <pre> and <code> tags.

    +

    To produce a code block in Markdown, simply indent every line of the +block by at least 4 spaces or 1 tab. For example, given this input:

    +
    This is a normal paragraph:
    +
    +    This is a code block.
    +
    +

    Markdown will generate:

    +
    <p>This is a normal paragraph:</p>
    +
    +<pre><code>This is a code block.
    +</code></pre>
    +
    +

    One level of indentation -- 4 spaces or 1 tab -- is removed from each +line of the code block. For example, this:

    +
    Here is an example of AppleScript:
    +
    +    tell application "Foo"
    +        beep
    +    end tell
    +
    +

    will turn into:

    +
    <p>Here is an example of AppleScript:</p>
    +
    +<pre><code>tell application "Foo"
    +    beep
    +end tell
    +</code></pre>
    +
    +

    A code block continues until it reaches a line that is not indented +(or the end of the article).

    +

    Within a code block, ampersands (&) and angle brackets (< and >) +are automatically converted into HTML entities. This makes it very +easy to include example HTML source code using Markdown -- just paste +it and indent it, and Markdown will handle the hassle of encoding the +ampersands and angle brackets. For example, this:

    +
        <div class="footer">
    +        &copy; 2004 Foo Corporation
    +    </div>
    +
    +

    will turn into:

    +
    <pre><code>&lt;div class="footer"&gt;
    +    &amp;copy; 2004 Foo Corporation
    +&lt;/div&gt;
    +</code></pre>
    +
    +

    Regular Markdown syntax is not processed within code blocks. E.g., +asterisks are just literal asterisks within a code block. This means +it's also easy to use Markdown to write about Markdown's own syntax.

    +

    Horizontal Rules

    +

    You can produce a horizontal rule tag (<hr />) by placing three or +more hyphens, asterisks, or underscores on a line by themselves. If you +wish, you may use spaces between the hyphens or asterisks. Each of the +following lines will produce a horizontal rule:

    +
    * * *
    +
    +***
    +
    +*****
    +
    +- - -
    +
    +---------------------------------------
    +
    +_ _ _
    +
    +
    +

    Span Elements

    + +

    Markdown supports two style of links: inline and reference.

    +

    In both styles, the link text is delimited by [square brackets].

    +

    To create an inline link, use a set of regular parentheses immediately +after the link text's closing square bracket. Inside the parentheses, +put the URL where you want the link to point, along with an optional +title for the link, surrounded in quotes. For example:

    +
    This is [an example](http://example.com/ "Title") inline link.
    +
    +[This link](http://example.net/) has no title attribute.
    +
    +

    Will produce:

    +
    <p>This is <a href="http://example.com/" title="Title">
    +an example</a> inline link.</p>
    +
    +<p><a href="http://example.net/">This link</a> has no
    +title attribute.</p>
    +
    +

    If you're referring to a local resource on the same server, you can +use relative paths:

    +
    See my [About](/about/) page for details.
    +
    +

    Reference-style links use a second set of square brackets, inside +which you place a label of your choosing to identify the link:

    +
    This is [an example][id] reference-style link.
    +
    +

    You can optionally use a space to separate the sets of brackets:

    +
    This is [an example] [id] reference-style link.
    +
    +

    Then, anywhere in the document, you define your link label like this, +on a line by itself:

    +
    [id]: http://example.com/  "Optional Title Here"
    +
    +

    That is:

    +
      +
    • Square brackets containing the link identifier (optionally +indented from the left margin using up to three spaces);
    • +
    • followed by a colon;
    • +
    • followed by one or more spaces (or tabs);
    • +
    • followed by the URL for the link;
    • +
    • optionally followed by a title attribute for the link, enclosed +in double or single quotes, or enclosed in parentheses.
    • +
    +

    The following three link definitions are equivalent:

    +
    [foo]: http://example.com/  "Optional Title Here"
    +[foo]: http://example.com/  'Optional Title Here'
    +[foo]: http://example.com/  (Optional Title Here)
    +
    +

    Note: There is a known bug in Markdown.pl 1.0.1 which prevents +single quotes from being used to delimit link titles.

    +

    The link URL may, optionally, be surrounded by angle brackets:

    +
    [id]: <http://example.com/>  "Optional Title Here"
    +
    +

    You can put the title attribute on the next line and use extra spaces +or tabs for padding, which tends to look better with longer URLs:

    +
    [id]: http://example.com/longish/path/to/resource/here
    +    "Optional Title Here"
    +
    +

    Link definitions are only used for creating links during Markdown +processing, and are stripped from your document in the HTML output.

    +

    Link definition names may consist of letters, numbers, spaces, and +punctuation -- but they are not case sensitive. E.g. these two +links:

    +
    [link text][a]
    +[link text][A]
    +
    +

    are equivalent.

    +

    The implicit link name shortcut allows you to omit the name of the +link, in which case the link text itself is used as the name. +Just use an empty set of square brackets -- e.g., to link the word +"Google" to the google.com web site, you could simply write:

    +
    [Google][]
    +
    +

    And then define the link:

    +
    [Google]: http://google.com/
    +
    +

    Because link names may contain spaces, this shortcut even works for +multiple words in the link text:

    +
    Visit [Daring Fireball][] for more information.
    +
    +

    And then define the link:

    +
    [Daring Fireball]: http://daringfireball.net/
    +
    +

    Link definitions can be placed anywhere in your Markdown document. I +tend to put them immediately after each paragraph in which they're +used, but if you want, you can put them all at the end of your +document, sort of like footnotes.

    +

    Here's an example of reference links in action:

    +
    I get 10 times more traffic from [Google] [1] than from
    +[Yahoo] [2] or [MSN] [3].
    +
    +  [1]: http://google.com/        "Google"
    +  [2]: http://search.yahoo.com/  "Yahoo Search"
    +  [3]: http://search.msn.com/    "MSN Search"
    +
    +

    Using the implicit link name shortcut, you could instead write:

    +
    I get 10 times more traffic from [Google][] than from
    +[Yahoo][] or [MSN][].
    +
    +  [google]: http://google.com/        "Google"
    +  [yahoo]:  http://search.yahoo.com/  "Yahoo Search"
    +  [msn]:    http://search.msn.com/    "MSN Search"
    +
    +

    Both of the above examples will produce the following HTML output:

    +
    <p>I get 10 times more traffic from <a href="http://google.com/"
    +title="Google">Google</a> than from
    +<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
    +or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
    +
    +

    For comparison, here is the same paragraph written using +Markdown's inline link style:

    +
    I get 10 times more traffic from [Google](http://google.com/ "Google")
    +than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
    +[MSN](http://search.msn.com/ "MSN Search").
    +
    +

    The point of reference-style links is not that they're easier to +write. The point is that with reference-style links, your document +source is vastly more readable. Compare the above examples: using +reference-style links, the paragraph itself is only 81 characters +long; with inline-style links, it's 176 characters; and as raw HTML, +it's 234 characters. In the raw HTML, there's more markup than there +is text.

    +

    With Markdown's reference-style links, a source document much more +closely resembles the final output, as rendered in a browser. By +allowing you to move the markup-related metadata out of the paragraph, +you can add links without interrupting the narrative flow of your +prose.

    +

    Emphasis

    +

    Markdown treats asterisks (*) and underscores (_) as indicators of +emphasis. Text wrapped with one * or _ will be wrapped with an +HTML <em> tag; double *'s or _'s will be wrapped with an HTML +<strong> tag. E.g., this input:

    +
    *single asterisks*
    +
    +_single underscores_
    +
    +**double asterisks**
    +
    +__double underscores__
    +
    +

    will produce:

    +
    <em>single asterisks</em>
    +
    +<em>single underscores</em>
    +
    +<strong>double asterisks</strong>
    +
    +<strong>double underscores</strong>
    +
    +

    You can use whichever style you prefer; the lone restriction is that +the same character must be used to open and close an emphasis span.

    +

    Emphasis can be used in the middle of a word:

    +
    un*frigging*believable
    +
    +

    But if you surround an * or _ with spaces, it'll be treated as a +literal asterisk or underscore.

    +

    To produce a literal asterisk or underscore at a position where it +would otherwise be used as an emphasis delimiter, you can backslash +escape it:

    +
    \*this text is surrounded by literal asterisks\*
    +
    +

    Code

    +

    To indicate a span of code, wrap it with backtick quotes (`). +Unlike a pre-formatted code block, a code span indicates code within a +normal paragraph. For example:

    +
    Use the `printf()` function.
    +
    +

    will produce:

    +
    <p>Use the <code>printf()</code> function.</p>
    +
    +

    To include a literal backtick character within a code span, you can use +multiple backticks as the opening and closing delimiters:

    +
    ``There is a literal backtick (`) here.``
    +
    +

    which will produce this:

    +
    <p><code>There is a literal backtick (`) here.</code></p>
    +
    +

    The backtick delimiters surrounding a code span may include spaces -- +one after the opening, one before the closing. This allows you to place +literal backtick characters at the beginning or end of a code span:

    +
    A single backtick in a code span: `` ` ``
    +
    +A backtick-delimited string in a code span: `` `foo` ``
    +
    +

    will produce:

    +
    <p>A single backtick in a code span: <code>`</code></p>
    +
    +<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
    +
    +

    With a code span, ampersands and angle brackets are encoded as HTML +entities automatically, which makes it easy to include example HTML +tags. Markdown will turn this:

    +
    Please don't use any `<blink>` tags.
    +
    +

    into:

    +
    <p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>
    +
    +

    You can write this:

    +
    `&#8212;` is the decimal-encoded equivalent of `&mdash;`.
    +
    +

    to produce:

    +
    <p><code>&amp;#8212;</code> is the decimal-encoded
    +equivalent of <code>&amp;mdash;</code>.</p>
    +
    +

    Images

    +

    Admittedly, it's fairly difficult to devise a "natural" syntax for +placing images into a plain text document format.

    +

    Markdown uses an image syntax that is intended to resemble the syntax +for links, allowing for two styles: inline and reference.

    +

    Inline image syntax looks like this:

    +
    ![Alt text](/path/to/img.jpg)
    +
    +![Alt text](/path/to/img.jpg "Optional title")
    +
    +

    That is:

    +
      +
    • An exclamation mark: !;
    • +
    • followed by a set of square brackets, containing the alt +attribute text for the image;
    • +
    • followed by a set of parentheses, containing the URL or path to +the image, and an optional title attribute enclosed in double +or single quotes.
    • +
    +

    Reference-style image syntax looks like this:

    +
    ![Alt text][id]
    +
    +

    Where "id" is the name of a defined image reference. Image references +are defined using syntax identical to link references:

    +
    [id]: url/to/image  "Optional title attribute"
    +
    +

    As of this writing, Markdown has no syntax for specifying the +dimensions of an image; if this is important to you, you can simply +use regular HTML <img> tags.

    +
    +

    Miscellaneous

    + +

    Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:

    +
    <http://example.com/>
    +
    +

    Markdown will turn this into:

    +
    <a href="http://example.com/">http://example.com/</a>
    +
    +

    Automatic links for email addresses work similarly, except that +Markdown will also perform a bit of randomized decimal and hex +entity-encoding to help obscure your address from address-harvesting +spambots. For example, Markdown will turn this:

    +
    <address@example.com>
    +
    +

    into something like this:

    +
    <a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;
    +&#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;
    +&#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;
    +&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>
    +
    +

    which will render in a browser as a clickable link to "address@example.com".

    +

    (This sort of entity-encoding trick will indeed fool many, if not +most, address-harvesting bots, but it definitely won't fool all of +them. It's better than nothing, but an address published in this way +will probably eventually start receiving spam.)

    +

    Backslash Escapes

    +

    Markdown allows you to use backslash escapes to generate literal +characters which would otherwise have special meaning in Markdown's +formatting syntax. For example, if you wanted to surround a word +with literal asterisks (instead of an HTML <em> tag), you can use +backslashes before the asterisks, like this:

    +
    \*literal asterisks\*
    +
    +

    Markdown provides backslash escapes for the following characters:

    +
    \	backslash
    +`	backtick
    +*	asterisk
    +_	underscore
    +{}	curly braces
    +[]	square brackets
    +()	parentheses
    +#	hash mark
    ++	plus sign
    +-	minus sign (hyphen)
    +.	dot
    +!	exclamation mark
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/specs.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/specs.md new file mode 100644 index 00000000..b47c8ca0 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/specs.md @@ -0,0 +1,899 @@ +Markdown: Syntax +================ + + + + +* [Overview](#overview) + * [Philosophy](#philosophy) + * [Inline HTML](#html) + * [Automatic Escaping for Special Characters](#autoescape) +* [Block Elements](#block) + * [Paragraphs and Line Breaks](#p) + * [Headers](#header) + * [Blockquotes](#blockquote) + * [Lists](#list) + * [Code Blocks](#precode) + * [Horizontal Rules](#hr) +* [Span Elements](#span) + * [Links](#link) + * [Emphasis](#em) + * [Code](#code) + * [Images](#img) +* [Miscellaneous](#misc) + * [Backslash Escapes](#backslash) + * [Automatic Links](#autolink) + + +**Note:** This document is itself written using Markdown; you +can [see the source for it by adding '.text' to the URL][src]. + + [src]: /projects/markdown/syntax.text + +* * * + +

    Overview

    + +

    Philosophy

    + +Markdown is intended to be as easy-to-read and easy-to-write as is feasible. + +Readability, however, is emphasized above all else. A Markdown-formatted +document should be publishable as-is, as plain text, without looking +like it's been marked up with tags or formatting instructions. While +Markdown's syntax has been influenced by several existing text-to-HTML +filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4], +[Grutatext] [5], and [EtText] [6] -- the single biggest source of +inspiration for Markdown's syntax is the format of plain text email. + + [1]: http://docutils.sourceforge.net/mirror/setext.html + [2]: http://www.aaronsw.com/2002/atx/ + [3]: http://textism.com/tools/textile/ + [4]: http://docutils.sourceforge.net/rst.html + [5]: http://www.triptico.com/software/grutatxt.html + [6]: http://ettext.taint.org/doc/ + +To this end, Markdown's syntax is comprised entirely of punctuation +characters, which punctuation characters have been carefully chosen so +as to look like what they mean. E.g., asterisks around a word actually +look like \*emphasis\*. Markdown lists look like, well, lists. Even +blockquotes look like quoted passages of text, assuming you've ever +used email. + + + +

    Inline HTML

    + +Markdown's syntax is intended for one purpose: to be used as a +format for *writing* for the web. + +Markdown is not a replacement for HTML, or even close to it. Its +syntax is very small, corresponding only to a very small subset of +HTML tags. The idea is *not* to create a syntax that makes it easier +to insert HTML tags. In my opinion, HTML tags are already easy to +insert. The idea for Markdown is to make it easy to read, write, and +edit prose. HTML is a *publishing* format; Markdown is a *writing* +format. Thus, Markdown's formatting syntax only addresses issues that +can be conveyed in plain text. + +For any markup that is not covered by Markdown's syntax, you simply +use HTML itself. There's no need to preface it or delimit it to +indicate that you're switching from Markdown to HTML; you just use +the tags. + +The only restrictions are that block-level HTML elements -- e.g. `
    `, +``, `
    `, `

    `, etc. -- must be separated from surrounding +content by blank lines, and the start and end tags of the block should +not be indented with tabs or spaces. Markdown is smart enough not +to add extra (unwanted) `

    ` tags around HTML block-level tags. + +For example, to add an HTML table to a Markdown article: + + This is a regular paragraph. + +

    + + + +
    Foo
    + + This is another regular paragraph. + +Note that Markdown formatting syntax is not processed within block-level +HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an +HTML block. + +Span-level HTML tags -- e.g. ``, ``, or `` -- can be +used anywhere in a Markdown paragraph, list item, or header. If you +want, you can even use HTML tags instead of Markdown formatting; e.g. if +you'd prefer to use HTML `` or `` tags instead of Markdown's +link or image syntax, go right ahead. + +Unlike block-level HTML tags, Markdown syntax *is* processed within +span-level tags. + + +

    Automatic Escaping for Special Characters

    + +In HTML, there are two characters that demand special treatment: `<` +and `&`. Left angle brackets are used to start tags; ampersands are +used to denote HTML entities. If you want to use them as literal +characters, you must escape them as entities, e.g. `<`, and +`&`. + +Ampersands in particular are bedeviling for web writers. If you want to +write about 'AT&T', you need to write '`AT&T`'. You even need to +escape ampersands within URLs. Thus, if you want to link to: + + http://images.google.com/images?num=30&q=larry+bird + +you need to encode the URL as: + + http://images.google.com/images?num=30&q=larry+bird + +in your anchor tag `href` attribute. Needless to say, this is easy to +forget, and is probably the single most common source of HTML validation +errors in otherwise well-marked-up web sites. + +Markdown allows you to use these characters naturally, taking care of +all the necessary escaping for you. If you use an ampersand as part of +an HTML entity, it remains unchanged; otherwise it will be translated +into `&`. + +So, if you want to include a copyright symbol in your article, you can write: + + © + +and Markdown will leave it alone. But if you write: + + AT&T + +Markdown will translate it to: + + AT&T + +Similarly, because Markdown supports [inline HTML](#html), if you use +angle brackets as delimiters for HTML tags, Markdown will treat them as +such. But if you write: + + 4 < 5 + +Markdown will translate it to: + + 4 < 5 + +However, inside Markdown code spans and blocks, angle brackets and +ampersands are *always* encoded automatically. This makes it easy to use +Markdown to write about HTML code. (As opposed to raw HTML, which is a +terrible format for writing about HTML syntax, because every single `<` +and `&` in your example code needs to be escaped.) + + +* * * + + +

    Block Elements

    + + +

    Paragraphs and Line Breaks

    + +A paragraph is simply one or more consecutive lines of text, separated +by one or more blank lines. (A blank line is any line that looks like a +blank line -- a line containing nothing but spaces or tabs is considered +blank.) Normal paragraphs should not be indented with spaces or tabs. + +The implication of the "one or more consecutive lines of text" rule is +that Markdown supports "hard-wrapped" text paragraphs. This differs +significantly from most other text-to-HTML formatters (including Movable +Type's "Convert Line Breaks" option) which translate every line break +character in a paragraph into a `
    ` tag. + +When you *do* want to insert a `
    ` break tag using Markdown, you +end a line with two or more spaces, then type return. + +Yes, this takes a tad more effort to create a `
    `, but a simplistic +"every line break is a `
    `" rule wouldn't work for Markdown. +Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l] +work best -- and look better -- when you format them with hard breaks. + + [bq]: #blockquote + [l]: #list + + + + + +Markdown supports two styles of headers, [Setext] [1] and [atx] [2]. + +Setext-style headers are "underlined" using equal signs (for first-level +headers) and dashes (for second-level headers). For example: + + This is an H1 + ============= + + This is an H2 + ------------- + +Any number of underlining `=`'s or `-`'s will work. + +Atx-style headers use 1-6 hash characters at the start of the line, +corresponding to header levels 1-6. For example: + + # This is an H1 + + ## This is an H2 + + ###### This is an H6 + +Optionally, you may "close" atx-style headers. This is purely +cosmetic -- you can use this if you think it looks better. The +closing hashes don't even need to match the number of hashes +used to open the header. (The number of opening hashes +determines the header level.) : + + # This is an H1 # + + ## This is an H2 ## + + ### This is an H3 ###### + + +

    Blockquotes

    + +Markdown uses email-style `>` characters for blockquoting. If you're +familiar with quoting passages of text in an email message, then you +know how to create a blockquote in Markdown. It looks best if you hard +wrap the text and put a `>` before every line: + + > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, + > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. + > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. + > + > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse + > id sem consectetuer libero luctus adipiscing. + +Markdown allows you to be lazy and only put the `>` before the first +line of a hard-wrapped paragraph: + + > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, + consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. + Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. + + > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse + id sem consectetuer libero luctus adipiscing. + +Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by +adding additional levels of `>`: + + > This is the first level of quoting. + > + > > This is nested blockquote. + > + > Back to the first level. + +Blockquotes can contain other Markdown elements, including headers, lists, +and code blocks: + + > ## This is a header. + > + > 1. This is the first list item. + > 2. This is the second list item. + > + > Here's some example code: + > + > return shell_exec("echo $input | $markdown_script"); + +Any decent text editor should make email-style quoting easy. For +example, with BBEdit, you can make a selection and choose Increase +Quote Level from the Text menu. + + +

    Lists

    + +Markdown supports ordered (numbered) and unordered (bulleted) lists. + +Unordered lists use asterisks, pluses, and hyphens -- interchangably +-- as list markers: + + * Red + * Green + * Blue + +is equivalent to: + + + Red + + Green + + Blue + +and: + + - Red + - Green + - Blue + +Ordered lists use numbers followed by periods: + + 1. Bird + 2. McHale + 3. Parish + +It's important to note that the actual numbers you use to mark the +list have no effect on the HTML output Markdown produces. The HTML +Markdown produces from the above list is: + +
      +
    1. Bird
    2. +
    3. McHale
    4. +
    5. Parish
    6. +
    + +If you instead wrote the list in Markdown like this: + + 1. Bird + 1. McHale + 1. Parish + +or even: + + 3. Bird + 1. McHale + 8. Parish + +you'd get the exact same HTML output. The point is, if you want to, +you can use ordinal numbers in your ordered Markdown lists, so that +the numbers in your source match the numbers in your published HTML. +But if you want to be lazy, you don't have to. + +If you do use lazy list numbering, however, you should still start the +list with the number 1. At some point in the future, Markdown may support +starting ordered lists at an arbitrary number. + +List markers typically start at the left margin, but may be indented by +up to three spaces. List markers must be followed by one or more spaces +or a tab. + +To make lists look nice, you can wrap items with hanging indents: + + * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, + viverra nec, fringilla in, laoreet vitae, risus. + * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. + Suspendisse id sem consectetuer libero luctus adipiscing. + +But if you want to be lazy, you don't have to: + + * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, + viverra nec, fringilla in, laoreet vitae, risus. + * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. + Suspendisse id sem consectetuer libero luctus adipiscing. + +If list items are separated by blank lines, Markdown will wrap the +items in `

    ` tags in the HTML output. For example, this input: + + * Bird + * Magic + +will turn into: + +

      +
    • Bird
    • +
    • Magic
    • +
    + +But this: + + * Bird + + * Magic + +will turn into: + +
      +
    • Bird

    • +
    • Magic

    • +
    + +List items may consist of multiple paragraphs. Each subsequent +paragraph in a list item must be indented by either 4 spaces +or one tab: + + 1. This is a list item with two paragraphs. Lorem ipsum dolor + sit amet, consectetuer adipiscing elit. Aliquam hendrerit + mi posuere lectus. + + Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. Donec sit amet nisl. Aliquam semper ipsum + sit amet velit. + + 2. Suspendisse id sem consectetuer libero luctus adipiscing. + +It looks nice if you indent every line of the subsequent +paragraphs, but here again, Markdown will allow you to be +lazy: + + * This is a list item with two paragraphs. + + This is the second paragraph in the list item. You're + only required to indent the first line. Lorem ipsum dolor + sit amet, consectetuer adipiscing elit. + + * Another item in the same list. + +To put a blockquote within a list item, the blockquote's `>` +delimiters need to be indented: + + * A list item with a blockquote: + + > This is a blockquote + > inside a list item. + +To put a code block within a list item, the code block needs +to be indented *twice* -- 8 spaces or two tabs: + + * A list item with a code block: + + + + +It's worth noting that it's possible to trigger an ordered list by +accident, by writing something like this: + + 1986. What a great season. + +In other words, a *number-period-space* sequence at the beginning of a +line. To avoid this, you can backslash-escape the period: + + 1986\. What a great season. + + + +

    Code Blocks

    + +Pre-formatted code blocks are used for writing about programming or +markup source code. Rather than forming normal paragraphs, the lines +of a code block are interpreted literally. Markdown wraps a code block +in both `
    ` and `` tags.
    +
    +To produce a code block in Markdown, simply indent every line of the
    +block by at least 4 spaces or 1 tab. For example, given this input:
    +
    +    This is a normal paragraph:
    +
    +        This is a code block.
    +
    +Markdown will generate:
    +
    +    

    This is a normal paragraph:

    + +
    This is a code block.
    +    
    + +One level of indentation -- 4 spaces or 1 tab -- is removed from each +line of the code block. For example, this: + + Here is an example of AppleScript: + + tell application "Foo" + beep + end tell + +will turn into: + +

    Here is an example of AppleScript:

    + +
    tell application "Foo"
    +        beep
    +    end tell
    +    
    + +A code block continues until it reaches a line that is not indented +(or the end of the article). + +Within a code block, ampersands (`&`) and angle brackets (`<` and `>`) +are automatically converted into HTML entities. This makes it very +easy to include example HTML source code using Markdown -- just paste +it and indent it, and Markdown will handle the hassle of encoding the +ampersands and angle brackets. For example, this: + + + +will turn into: + +
    <div class="footer">
    +        &copy; 2004 Foo Corporation
    +    </div>
    +    
    + +Regular Markdown syntax is not processed within code blocks. E.g., +asterisks are just literal asterisks within a code block. This means +it's also easy to use Markdown to write about Markdown's own syntax. + + + +

    Horizontal Rules

    + +You can produce a horizontal rule tag (`
    `) by placing three or +more hyphens, asterisks, or underscores on a line by themselves. If you +wish, you may use spaces between the hyphens or asterisks. Each of the +following lines will produce a horizontal rule: + + * * * + + *** + + ***** + + - - - + + --------------------------------------- + + _ _ _ + + +* * * + +

    Span Elements

    + + + +Markdown supports two style of links: *inline* and *reference*. + +In both styles, the link text is delimited by [square brackets]. + +To create an inline link, use a set of regular parentheses immediately +after the link text's closing square bracket. Inside the parentheses, +put the URL where you want the link to point, along with an *optional* +title for the link, surrounded in quotes. For example: + + This is [an example](http://example.com/ "Title") inline link. + + [This link](http://example.net/) has no title attribute. + +Will produce: + +

    This is + an example inline link.

    + +

    This link has no + title attribute.

    + +If you're referring to a local resource on the same server, you can +use relative paths: + + See my [About](/about/) page for details. + +Reference-style links use a second set of square brackets, inside +which you place a label of your choosing to identify the link: + + This is [an example][id] reference-style link. + +You can optionally use a space to separate the sets of brackets: + + This is [an example] [id] reference-style link. + +Then, anywhere in the document, you define your link label like this, +on a line by itself: + + [id]: http://example.com/ "Optional Title Here" + +That is: + +* Square brackets containing the link identifier (optionally + indented from the left margin using up to three spaces); +* followed by a colon; +* followed by one or more spaces (or tabs); +* followed by the URL for the link; +* optionally followed by a title attribute for the link, enclosed + in double or single quotes, or enclosed in parentheses. + +The following three link definitions are equivalent: + + [foo]: http://example.com/ "Optional Title Here" + [foo]: http://example.com/ 'Optional Title Here' + [foo]: http://example.com/ (Optional Title Here) + +**Note:** There is a known bug in Markdown.pl 1.0.1 which prevents +single quotes from being used to delimit link titles. + +The link URL may, optionally, be surrounded by angle brackets: + + [id]: "Optional Title Here" + +You can put the title attribute on the next line and use extra spaces +or tabs for padding, which tends to look better with longer URLs: + + [id]: http://example.com/longish/path/to/resource/here + "Optional Title Here" + +Link definitions are only used for creating links during Markdown +processing, and are stripped from your document in the HTML output. + +Link definition names may consist of letters, numbers, spaces, and +punctuation -- but they are *not* case sensitive. E.g. these two +links: + + [link text][a] + [link text][A] + +are equivalent. + +The *implicit link name* shortcut allows you to omit the name of the +link, in which case the link text itself is used as the name. +Just use an empty set of square brackets -- e.g., to link the word +"Google" to the google.com web site, you could simply write: + + [Google][] + +And then define the link: + + [Google]: http://google.com/ + +Because link names may contain spaces, this shortcut even works for +multiple words in the link text: + + Visit [Daring Fireball][] for more information. + +And then define the link: + + [Daring Fireball]: http://daringfireball.net/ + +Link definitions can be placed anywhere in your Markdown document. I +tend to put them immediately after each paragraph in which they're +used, but if you want, you can put them all at the end of your +document, sort of like footnotes. + +Here's an example of reference links in action: + + I get 10 times more traffic from [Google] [1] than from + [Yahoo] [2] or [MSN] [3]. + + [1]: http://google.com/ "Google" + [2]: http://search.yahoo.com/ "Yahoo Search" + [3]: http://search.msn.com/ "MSN Search" + +Using the implicit link name shortcut, you could instead write: + + I get 10 times more traffic from [Google][] than from + [Yahoo][] or [MSN][]. + + [google]: http://google.com/ "Google" + [yahoo]: http://search.yahoo.com/ "Yahoo Search" + [msn]: http://search.msn.com/ "MSN Search" + +Both of the above examples will produce the following HTML output: + +

    I get 10 times more traffic from Google than from + Yahoo + or MSN.

    + +For comparison, here is the same paragraph written using +Markdown's inline link style: + + I get 10 times more traffic from [Google](http://google.com/ "Google") + than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or + [MSN](http://search.msn.com/ "MSN Search"). + +The point of reference-style links is not that they're easier to +write. The point is that with reference-style links, your document +source is vastly more readable. Compare the above examples: using +reference-style links, the paragraph itself is only 81 characters +long; with inline-style links, it's 176 characters; and as raw HTML, +it's 234 characters. In the raw HTML, there's more markup than there +is text. + +With Markdown's reference-style links, a source document much more +closely resembles the final output, as rendered in a browser. By +allowing you to move the markup-related metadata out of the paragraph, +you can add links without interrupting the narrative flow of your +prose. + + +

    Emphasis

    + +Markdown treats asterisks (`*`) and underscores (`_`) as indicators of +emphasis. Text wrapped with one `*` or `_` will be wrapped with an +HTML `` tag; double `*`'s or `_`'s will be wrapped with an HTML +`` tag. E.g., this input: + + *single asterisks* + + _single underscores_ + + **double asterisks** + + __double underscores__ + +will produce: + + single asterisks + + single underscores + + double asterisks + + double underscores + +You can use whichever style you prefer; the lone restriction is that +the same character must be used to open and close an emphasis span. + +Emphasis can be used in the middle of a word: + + un*frigging*believable + +But if you surround an `*` or `_` with spaces, it'll be treated as a +literal asterisk or underscore. + +To produce a literal asterisk or underscore at a position where it +would otherwise be used as an emphasis delimiter, you can backslash +escape it: + + \*this text is surrounded by literal asterisks\* + + + +

    Code

    + +To indicate a span of code, wrap it with backtick quotes (`` ` ``). +Unlike a pre-formatted code block, a code span indicates code within a +normal paragraph. For example: + + Use the `printf()` function. + +will produce: + +

    Use the printf() function.

    + +To include a literal backtick character within a code span, you can use +multiple backticks as the opening and closing delimiters: + + ``There is a literal backtick (`) here.`` + +which will produce this: + +

    There is a literal backtick (`) here.

    + +The backtick delimiters surrounding a code span may include spaces -- +one after the opening, one before the closing. This allows you to place +literal backtick characters at the beginning or end of a code span: + + A single backtick in a code span: `` ` `` + + A backtick-delimited string in a code span: `` `foo` `` + +will produce: + +

    A single backtick in a code span: `

    + +

    A backtick-delimited string in a code span: `foo`

    + +With a code span, ampersands and angle brackets are encoded as HTML +entities automatically, which makes it easy to include example HTML +tags. Markdown will turn this: + + Please don't use any `` tags. + +into: + +

    Please don't use any <blink> tags.

    + +You can write this: + + `—` is the decimal-encoded equivalent of `—`. + +to produce: + +

    &#8212; is the decimal-encoded + equivalent of &mdash;.

    + + + +

    Images

    + +Admittedly, it's fairly difficult to devise a "natural" syntax for +placing images into a plain text document format. + +Markdown uses an image syntax that is intended to resemble the syntax +for links, allowing for two styles: *inline* and *reference*. + +Inline image syntax looks like this: + + ![Alt text](/path/to/img.jpg) + + ![Alt text](/path/to/img.jpg "Optional title") + +That is: + +* An exclamation mark: `!`; +* followed by a set of square brackets, containing the `alt` + attribute text for the image; +* followed by a set of parentheses, containing the URL or path to + the image, and an optional `title` attribute enclosed in double + or single quotes. + +Reference-style image syntax looks like this: + + ![Alt text][id] + +Where "id" is the name of a defined image reference. Image references +are defined using syntax identical to link references: + + [id]: url/to/image "Optional title attribute" + +As of this writing, Markdown has no syntax for specifying the +dimensions of an image; if this is important to you, you can simply +use regular HTML `` tags. + + +* * * + + +

    Miscellaneous

    + + + +Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this: + + + +Markdown will turn this into: + + http://example.com/ + +Automatic links for email addresses work similarly, except that +Markdown will also perform a bit of randomized decimal and hex +entity-encoding to help obscure your address from address-harvesting +spambots. For example, Markdown will turn this: + + + +into something like this: + + address@exa + mple.com + +which will render in a browser as a clickable link to "address@example.com". + +(This sort of entity-encoding trick will indeed fool many, if not +most, address-harvesting bots, but it definitely won't fool all of +them. It's better than nothing, but an address published in this way +will probably eventually start receiving spam.) + + + +

    Backslash Escapes

    + +Markdown allows you to use backslash escapes to generate literal +characters which would otherwise have special meaning in Markdown's +formatting syntax. For example, if you wanted to surround a word +with literal asterisks (instead of an HTML `` tag), you can use +backslashes before the asterisks, like this: + + \*literal asterisks\* + +Markdown provides backslash escapes for the following characters: + + \ backslash + ` backtick + * asterisk + _ underscore + {} curly braces + [] square brackets + () parentheses + # hash mark + + plus sign + - minus sign (hyphen) + . dot + ! exclamation mark + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/test_precedence.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/test_precedence.html new file mode 100644 index 00000000..897d75e2 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/test_precedence.html @@ -0,0 +1,5 @@ +

    Not a headline but two HR:

    +
    +
    +
    +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/test_precedence.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/test_precedence.md new file mode 100644 index 00000000..bab435b3 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/test_precedence.md @@ -0,0 +1,8 @@ +Not a headline but two HR: + +*** +--- + +--- +*** + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/unicode.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/unicode.html new file mode 100644 index 00000000..dc739c8a --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/unicode.html @@ -0,0 +1,13 @@ +

    这是一段Unicode文本测试

    +

    This file should be saved under UTF-8 without BOM.

    +

    All content below sampled from Wikipedia in different languages.

    +

    ZH: +Unicode(中文:è¬åœ‹ç¢¼ã€åœ‹éš›ç¢¼ã€çµ±ä¸€ç¢¼ã€å–®ä¸€ç¢¼ï¼‰æ˜¯é›»è…¦ç§‘學領域裡的一項業界標準。它对世界上大部分的文字系統進行了整ç†ã€ç·¨ç¢¼ï¼Œä½¿å¾—電腦å¯ä»¥ç”¨æ›´ç‚ºç°¡å–®çš„æ–¹å¼ä¾†å‘ˆç¾å’Œè™•ç†æ–‡å­—。

    +

    JA: +Unicode(ユニコード)ã¨ã¯ã€ç¬¦å·åŒ–文字集åˆã‚„文字符å·åŒ–æ–¹å¼ãªã©ã‚’定ã‚ãŸã€æ–‡å­—ã‚³ãƒ¼ãƒ‰ã®æ¥­ç•Œè¦æ ¼ã§ã‚る。文字集åˆï¼ˆæ–‡å­—セット)ãŒå˜ä¸€ã®å¤§è¦æ¨¡æ–‡å­—セットã§ã‚ã‚‹ã“ã¨ï¼ˆã€ŒUniã€ã¨ã„ã†åã¯ãれã«ç”±æ¥ã™ã‚‹ï¼‰ãªã©ãŒç‰¹å¾´ã§ã‚る。

    +

    KO: +유니코드(Unicode)는 ì „ ì„¸ê³„ì˜ ëª¨ë“  문ìžë¥¼ 컴퓨터ì—서 ì¼ê´€ë˜ê²Œ 표현하고 다룰 수 있ë„ë¡ ì„¤ê³„ëœ ì‚°ì—… 표준ì´ë©°, 유니코드 협회(Unicode Consortium)ê°€ 제정한다. ì´ í‘œì¤€ì—는 ISO 10646 ë¬¸ìž ì§‘í•©, ë¬¸ìž ì¸ì½”딩, ë¬¸ìž ì •ë³´ ë°ì´í„°ë² ì´ìФ, 문ìžë“¤ì„ 다루기 위한 알고리즘 ë“±ì„ í¬í•¨í•˜ê³  있다

    +

    AS: +ইউনিক’ড (English: Unicode) হৈছে কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à§°à§° লিখন পà§à§°à¦£à¦¾à¦²à§€à¦¤ থকা আখৰ বা চিনবোৰৰ সংহত নিয়মীকৰণ,নিৰà§à¦¦à§‡à¦¶à¦¨à¦¾ আৰৠপà§à§°à¦¤à¦¿à¦¨à¦¿à¦§à¦¿à¦¤à§à¦¬ কৰিব পৰাকৈ বà§à¦¯à§±à¦¹à§ƒà¦¤ à¦à¦• কাৰিকৰী মান । ১৯৯১ চনত Unicode Consortium নামৰ অপেছাদাৰী সংগঠনটোৱে ইয়াক উদà§à¦­à¦¾à§±à¦¨ কৰে । শেহতীয়াকৈ

    +

    AR: +ÙÙŠ علم الحاسوب، الترميز الموحد (يونيكود[1] أو ÙŠÙونÙÙƒÙود[2]) معيار يمكن الحواسيب من تمثيل النصوص المكتوبة بأغلب نظم الكتابة ومعالجتها، بصورة متناسقة. يتكون يونيكود من 100ØŒ000 Ù…Ø­Ø±ÙØŒ وطقم من مخططات الرموز كمرجع مرئي، ونهج ÙÙŠ الترميز، وطقم من ترميزات المحار٠المعيارية، وسرد لخصائص

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/unicode.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/unicode.md new file mode 100644 index 00000000..bca5889b --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/unicode.md @@ -0,0 +1,21 @@ +这是一段Unicode文本测试 +=============================== + +This file should be saved under UTF-8 without BOM. + +All content below sampled from [Wikipedia](https://en.wikipedia.org/wiki/Unicode) in different languages. + +ZH: +Unicode(中文:è¬åœ‹ç¢¼ã€åœ‹éš›ç¢¼ã€çµ±ä¸€ç¢¼ã€å–®ä¸€ç¢¼ï¼‰æ˜¯é›»è…¦ç§‘學領域裡的一項業界標準。它对世界上大部分的文字系統進行了整ç†ã€ç·¨ç¢¼ï¼Œä½¿å¾—電腦å¯ä»¥ç”¨æ›´ç‚ºç°¡å–®çš„æ–¹å¼ä¾†å‘ˆç¾å’Œè™•ç†æ–‡å­—。 + +JA: +Unicode(ユニコード)ã¨ã¯ã€ç¬¦å·åŒ–文字集åˆã‚„文字符å·åŒ–æ–¹å¼ãªã©ã‚’定ã‚ãŸã€æ–‡å­—ã‚³ãƒ¼ãƒ‰ã®æ¥­ç•Œè¦æ ¼ã§ã‚る。文字集åˆï¼ˆæ–‡å­—セット)ãŒå˜ä¸€ã®å¤§è¦æ¨¡æ–‡å­—セットã§ã‚ã‚‹ã“ã¨ï¼ˆã€ŒUniã€ã¨ã„ã†åã¯ãれã«ç”±æ¥ã™ã‚‹ï¼‰ãªã©ãŒç‰¹å¾´ã§ã‚る。 + +KO: +유니코드(Unicode)는 ì „ ì„¸ê³„ì˜ ëª¨ë“  문ìžë¥¼ 컴퓨터ì—서 ì¼ê´€ë˜ê²Œ 표현하고 다룰 수 있ë„ë¡ ì„¤ê³„ëœ ì‚°ì—… 표준ì´ë©°, 유니코드 협회(Unicode Consortium)ê°€ 제정한다. ì´ í‘œì¤€ì—는 ISO 10646 ë¬¸ìž ì§‘í•©, ë¬¸ìž ì¸ì½”딩, ë¬¸ìž ì •ë³´ ë°ì´í„°ë² ì´ìФ, 문ìžë“¤ì„ 다루기 위한 알고리즘 ë“±ì„ í¬í•¨í•˜ê³  있다 + +AS: +ইউনিক’ড (English: Unicode) হৈছে কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à§°à§° লিখন পà§à§°à¦£à¦¾à¦²à§€à¦¤ থকা আখৰ বা চিনবোৰৰ সংহত নিয়মীকৰণ,নিৰà§à¦¦à§‡à¦¶à¦¨à¦¾ আৰৠপà§à§°à¦¤à¦¿à¦¨à¦¿à¦§à¦¿à¦¤à§à¦¬ কৰিব পৰাকৈ বà§à¦¯à§±à¦¹à§ƒà¦¤ à¦à¦• কাৰিকৰী মান । ১৯৯১ চনত Unicode Consortium নামৰ অপেছাদাৰী সংগঠনটোৱে ইয়াক উদà§à¦­à¦¾à§±à¦¨ কৰে । শেহতীয়াকৈ + +AR: +ÙÙŠ علم الحاسوب، الترميز الموحد (يونيكود[1] أو ÙŠÙونÙÙƒÙود[2]) معيار يمكن الحواسيب من تمثيل النصوص المكتوبة بأغلب نظم الكتابة ومعالجتها، بصورة متناسقة. يتكون يونيكود من 100ØŒ000 Ù…Ø­Ø±ÙØŒ وطقم من مخططات الرموز كمرجع مرئي، ونهج ÙÙŠ الترميز، وطقم من ترميزات المحار٠المعيارية، وسرد لخصائص diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/utf8-do-not-kill-characters.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/utf8-do-not-kill-characters.html new file mode 100644 index 00000000..13db1b89 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/utf8-do-not-kill-characters.html @@ -0,0 +1,3 @@ +

    абвгдеёжзийклмнопрÑтуфхцчшщъыьÑÑŽÑ

    +

    there is a charater, é…

    +

    Arabic Latter "Ù… (M)"

    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/utf8-do-not-kill-characters.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/utf8-do-not-kill-characters.md new file mode 100644 index 00000000..d1a7e646 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-data/utf8-do-not-kill-characters.md @@ -0,0 +1,5 @@ +абвгдеёжзийклмнопрÑтуфхцчшщъыьÑÑŽÑ + +there is a charater, é… + +Arabic Latter "Ù… (M)" \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/list.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/list.html new file mode 100644 index 00000000..8a21b776 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/list.html @@ -0,0 +1,23 @@ +
      +
    1. item1, num1
    2. +
    3. item2, num2
    4. +
    5. item3, num3
    6. +
    +
    +
      +
    1. item1, num3
    2. +
    3. item2, num4
    4. +
    5. item3, num5
    6. +
    +
    +
      +
    1. item1, num4
    2. +
    3. item2, num5
    4. +
    5. item3, num6
    6. +
    +
    +
      +
    1. item1, num5
    2. +
    3. item2, num6
    4. +
    5. item3, num7
    6. +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/list.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/list.md new file mode 100644 index 00000000..623b0dab --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/list.md @@ -0,0 +1,21 @@ +1. item1, num1 +2. item2, num2 +4. item3, num3 + +--- + +3. item1, num3 +12. item2, num4 +125. item3, num5 + +--- + +4. item1, num4 +12. item2, num5 +125. item3, num6 + +--- + + 5. item1, num5 + 12. item2, num6 +125. item3, num7 \ No newline at end of file diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/md1_ordered_and_unordered_lists.html b/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/md1_ordered_and_unordered_lists.html new file mode 100644 index 00000000..18def7e3 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/md1_ordered_and_unordered_lists.html @@ -0,0 +1,66 @@ +

    Ordered, start's with 4

    +

    Tight:

    +
      +
    1. Four
    2. +
    3. Five
    4. +
    +

    and:

    +
      +
    1. Four
    2. +
    3. Five
    4. +
    5. Six
    6. +
    +

    Loose using tabs, start's with 5:

    +
      +
    1. Five

      +
    2. +
    3. Six

      +
    4. +
    5. Seven

      +
    6. +
    +

    and using spaces:

    +
      +
    1. Five

      +
    2. +
    3. Six

      +
    4. +
    5. Seven

      +
    6. +
    +

    Multiple paragraphs, start's with 5:

    +
      +
    1. Item 1, graf one.

      +

      Item 2. graf two. The quick brown fox jumped over the lazy dog's +back.

      +
    2. +
    3. Item 2.

      +
    4. +
    5. Item 3.

      +
    6. +
    +

    Nested, start's with 5

    +
      +
    1. Five
    2. +
    3. Six:
        +
      • Fee
      • +
      • Fie
      • +
      • Foe
      • +
      +
    4. +
    5. Seven
    6. +
    +

    Same thing but with paragraphs:

    +
      +
    1. Five

      +
    2. +
    3. Six:

      +
        +
      • Fee
      • +
      • Fie
      • +
      • Foe
      • +
      +
    4. +
    5. Seven

      +
    6. +
    diff --git a/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/md1_ordered_and_unordered_lists.md b/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/md1_ordered_and_unordered_lists.md new file mode 100644 index 00000000..569beaff --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/markdown-ol-start-num-data/md1_ordered_and_unordered_lists.md @@ -0,0 +1,62 @@ +## Ordered, start's with 4 + +Tight: + +4. Four +5. Five + +and: + +4. Four +5. Five +6. Six + + +Loose using tabs, start's with 5: + +5. Five + +6. Six + +7. Seven + +and using spaces: + +5. Five + +6. Six + +7. Seven + +Multiple paragraphs, start's with 5: + +5. Item 1, graf one. + + Item 2. graf two. The quick brown fox jumped over the lazy dog's + back. + +6. Item 2. + +7. Item 3. + +## Nested, start's with 5 + +5. Five +6. Six: + * Fee + * Fie + * Foe +7. Seven + +Same thing but with paragraphs: + +5. Five + +6. Six: + + * Fee + * Fie + * Foe + +7. Seven + diff --git a/core/lib/composer/vendor/cebe/markdown/tests/profile.php b/core/lib/composer/vendor/cebe/markdown/tests/profile.php new file mode 100644 index 00000000..7888d873 --- /dev/null +++ b/core/lib/composer/vendor/cebe/markdown/tests/profile.php @@ -0,0 +1,31 @@ +parse($markdown); +} + +$xhprof_data = xhprof_disable(); + +$XHPROF_ROOT = __DIR__ . '/../vendor/facebook/xhprof/'; +include_once $XHPROF_ROOT . '/xhprof_lib/utils/xhprof_lib.php'; +include_once $XHPROF_ROOT . '/xhprof_lib/utils/xhprof_runs.php'; + +$xhprof_runs = new XHProfRuns_Default(); +$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_testing"); + +echo "http://localhost/xhprof/xhprof_html/index.php?run={$run_id}&source=xhprof_testing\n"; diff --git a/core/lib/composer/vendor/composer/ClassLoader.php b/core/lib/composer/vendor/composer/ClassLoader.php index ff6ecfb8..dc02dfb1 100644 --- a/core/lib/composer/vendor/composer/ClassLoader.php +++ b/core/lib/composer/vendor/composer/ClassLoader.php @@ -53,8 +53,9 @@ class ClassLoader private $useIncludePath = false; private $classMap = array(); - private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; public function getPrefixes() { @@ -271,6 +272,26 @@ class ClassLoader return $this->classMapAuthoritative; } + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + /** * Registers this instance as an autoloader. * @@ -313,29 +334,34 @@ class ClassLoader */ public function findFile($class) { - // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 - if ('\\' == $class[0]) { - $class = substr($class, 1); - } - // class map lookup if (isset($this->classMap[$class])) { return $this->classMap[$class]; } - if ($this->classMapAuthoritative) { + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { return false; } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } $file = $this->findFileWithExtension($class, '.php'); // Search for Hack files if we are running on HHVM - if ($file === null && defined('HHVM_VERSION')) { + if (false === $file && defined('HHVM_VERSION')) { $file = $this->findFileWithExtension($class, '.hh'); } - if ($file === null) { + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { // Remember that this class does not exist. - return $this->classMap[$class] = false; + $this->missingClasses[$class] = true; } return $file; @@ -348,10 +374,14 @@ class ClassLoader $first = $class[0]; if (isset($this->prefixLengthsPsr4[$first])) { - foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { - if (0 === strpos($class, $prefix)) { - foreach ($this->prefixDirsPsr4[$prefix] as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath.'\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { return $file; } } @@ -399,6 +429,8 @@ class ClassLoader if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } + + return false; } } diff --git a/core/lib/composer/vendor/composer/LICENSE b/core/lib/composer/vendor/composer/LICENSE index 1a281248..f27399a0 100644 --- a/core/lib/composer/vendor/composer/LICENSE +++ b/core/lib/composer/vendor/composer/LICENSE @@ -1,5 +1,5 @@ -Copyright (c) 2016 Nils Adermann, Jordi Boggiano +Copyright (c) Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/core/lib/composer/vendor/composer/autoload_classmap.php b/core/lib/composer/vendor/composer/autoload_classmap.php index 520a91d8..619a3202 100644 --- a/core/lib/composer/vendor/composer/autoload_classmap.php +++ b/core/lib/composer/vendor/composer/autoload_classmap.php @@ -178,7 +178,7 @@ return array( 'PHPUnit\\Util\\TestDox\\XmlResultPrinter' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php', 'PHPUnit\\Util\\TextTestListRenderer' => $vendorDir . '/phpunit/phpunit/src/Util/TextTestListRenderer.php', 'PHPUnit\\Util\\Type' => $vendorDir . '/phpunit/phpunit/src/Util/Type.php', - 'PHPUnit\\Util\\Xml' => $vendorDir . '/phpunit/phpunit/src/Util/XML.php', + 'PHPUnit\\Util\\Xml' => $vendorDir . '/phpunit/phpunit/src/Util/Xml.php', 'PHPUnit\\Util\\XmlTestListRenderer' => $vendorDir . '/phpunit/phpunit/src/Util/XmlTestListRenderer.php', 'PHPUnit_Framework_MockObject_MockObject' => $vendorDir . '/phpunit/phpunit-mock-objects/src/MockObject.php', 'PHP_Timer' => $vendorDir . '/phpunit/php-timer/src/Timer.php', diff --git a/core/lib/composer/vendor/composer/autoload_namespaces.php b/core/lib/composer/vendor/composer/autoload_namespaces.php index afaf5392..2f02ee99 100644 --- a/core/lib/composer/vendor/composer/autoload_namespaces.php +++ b/core/lib/composer/vendor/composer/autoload_namespaces.php @@ -11,6 +11,7 @@ return array( 'PEAR' => array($vendorDir . '/pear/pear_exception'), 'Net' => array($vendorDir . '/pear/net_smtp', $vendorDir . '/pear/net_socket'), 'Mail' => array($vendorDir . '/pear/mail'), + 'ForceUTF8\\' => array($vendorDir . '/neitanod/forceutf8/src'), 'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib'), 'Dflydev\\DotAccessData' => array($vendorDir . '/dflydev/dot-access-data/src'), 'Console' => array($vendorDir . '/pear/console_getopt'), diff --git a/core/lib/composer/vendor/composer/autoload_psr4.php b/core/lib/composer/vendor/composer/autoload_psr4.php index 97f8fc9c..9fbdf136 100644 --- a/core/lib/composer/vendor/composer/autoload_psr4.php +++ b/core/lib/composer/vendor/composer/autoload_psr4.php @@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir); return array( 'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'), + 'cebe\\markdown\\' => array($vendorDir . '/cebe/markdown'), 'Whoops\\' => array($vendorDir . '/filp/whoops/src/Whoops'), 'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), @@ -34,5 +35,6 @@ return array( 'Consolidation\\Log\\' => array($vendorDir . '/consolidation/log/src'), 'Consolidation\\Config\\' => array($vendorDir . '/consolidation/config/src'), 'Consolidation\\AnnotatedCommand\\' => array($vendorDir . '/consolidation/annotated-command/src'), + 'Base64Url\\' => array($vendorDir . '/spomky-labs/base64url/src'), '' => array($baseDir . '/../../src'), ); diff --git a/core/lib/composer/vendor/composer/autoload_real.php b/core/lib/composer/vendor/composer/autoload_real.php index 9b640787..41618983 100644 --- a/core/lib/composer/vendor/composer/autoload_real.php +++ b/core/lib/composer/vendor/composer/autoload_real.php @@ -24,10 +24,10 @@ class ComposerAutoloaderInit6d4a28cd96a5bc5d5b97781c062572d9 spl_autoload_unregister(array('ComposerAutoloaderInit6d4a28cd96a5bc5d5b97781c062572d9', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; - array_push($includePaths, get_include_path()); - set_include_path(join(PATH_SEPARATOR, $includePaths)); + $includePaths[] = get_include_path(); + set_include_path(implode(PATH_SEPARATOR, $includePaths)); - $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION'); + $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; diff --git a/core/lib/composer/vendor/composer/autoload_static.php b/core/lib/composer/vendor/composer/autoload_static.php index 787f1750..b3dee8ca 100644 --- a/core/lib/composer/vendor/composer/autoload_static.php +++ b/core/lib/composer/vendor/composer/autoload_static.php @@ -17,6 +17,10 @@ class ComposerStaticInit6d4a28cd96a5bc5d5b97781c062572d9 array ( 'phpDocumentor\\Reflection\\' => 25, ), + 'c' => + array ( + 'cebe\\markdown\\' => 14, + ), 'W' => array ( 'Whoops\\' => 7, @@ -77,6 +81,10 @@ class ComposerStaticInit6d4a28cd96a5bc5d5b97781c062572d9 'Consolidation\\Config\\' => 21, 'Consolidation\\AnnotatedCommand\\' => 31, ), + 'B' => + array ( + 'Base64Url\\' => 10, + ), ); public static $prefixDirsPsr4 = array ( @@ -86,6 +94,10 @@ class ComposerStaticInit6d4a28cd96a5bc5d5b97781c062572d9 1 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src', 2 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src', ), + 'cebe\\markdown\\' => + array ( + 0 => __DIR__ . '/..' . '/cebe/markdown', + ), 'Whoops\\' => array ( 0 => __DIR__ . '/..' . '/filp/whoops/src/Whoops', @@ -194,6 +206,10 @@ class ComposerStaticInit6d4a28cd96a5bc5d5b97781c062572d9 array ( 0 => __DIR__ . '/..' . '/consolidation/annotated-command/src', ), + 'Base64Url\\' => + array ( + 0 => __DIR__ . '/..' . '/spomky-labs/base64url/src', + ), ); public static $fallbackDirsPsr4 = array ( @@ -234,6 +250,13 @@ class ComposerStaticInit6d4a28cd96a5bc5d5b97781c062572d9 0 => __DIR__ . '/..' . '/pear/mail', ), ), + 'F' => + array ( + 'ForceUTF8\\' => + array ( + 0 => __DIR__ . '/..' . '/neitanod/forceutf8/src', + ), + ), 'D' => array ( 'Doctrine\\Common\\Lexer\\' => @@ -431,7 +454,7 @@ class ComposerStaticInit6d4a28cd96a5bc5d5b97781c062572d9 'PHPUnit\\Util\\TestDox\\XmlResultPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php', 'PHPUnit\\Util\\TextTestListRenderer' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/TextTestListRenderer.php', 'PHPUnit\\Util\\Type' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Type.php', - 'PHPUnit\\Util\\Xml' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/XML.php', + 'PHPUnit\\Util\\Xml' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/Xml.php', 'PHPUnit\\Util\\XmlTestListRenderer' => __DIR__ . '/..' . '/phpunit/phpunit/src/Util/XmlTestListRenderer.php', 'PHPUnit_Framework_MockObject_MockObject' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/src/MockObject.php', 'PHP_Timer' => __DIR__ . '/..' . '/phpunit/php-timer/src/Timer.php', diff --git a/core/lib/composer/vendor/composer/include_paths.php b/core/lib/composer/vendor/composer/include_paths.php index 7b7813d4..f5f2d7b7 100644 --- a/core/lib/composer/vendor/composer/include_paths.php +++ b/core/lib/composer/vendor/composer/include_paths.php @@ -7,9 +7,9 @@ $baseDir = dirname($vendorDir); return array( $vendorDir . '/pear/console_getopt', + $vendorDir . '/pear/mail', $vendorDir . '/pear/net_smtp', $vendorDir . '/pear/net_socket', $vendorDir . '/pear/pear-core-minimal/src', $vendorDir . '/pear/pear_exception', - $vendorDir . '/pear/mail', ); diff --git a/core/lib/composer/vendor/composer/installed.json b/core/lib/composer/vendor/composer/installed.json index 75a599c1..33681105 100644 --- a/core/lib/composer/vendor/composer/installed.json +++ b/core/lib/composer/vendor/composer/installed.json @@ -1,4 +1,66 @@ [ + { + "name": "cebe/markdown", + "version": "1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/cebe/markdown.git", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "shasum": "" + }, + "require": { + "lib-pcre": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "cebe/indent": "*", + "facebook/xhprof": "*@dev", + "phpunit/phpunit": "4.1.*" + }, + "time": "2018-03-26T11:24:36+00:00", + "bin": [ + "bin/markdown" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "cebe\\markdown\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Creator" + } + ], + "description": "A super fast, highly extensible markdown parser for PHP", + "homepage": "https://github.com/cebe/markdown#readme", + "keywords": [ + "extensible", + "fast", + "gfm", + "markdown", + "markdown-extra" + ] + }, { "name": "consolidation/annotated-command", "version": "2.8.2", @@ -27,7 +89,7 @@ "satooshi/php-coveralls": "^1.0.2 | dev-master", "squizlabs/php_codesniffer": "^2.7" }, - "time": "2017-11-29 16:23:23", + "time": "2017-11-29T16:23:23+00:00", "type": "library", "extra": { "branch-alias": { @@ -83,7 +145,7 @@ "suggest": { "symfony/yaml": "Required to use Consolidation\\Config\\Loader\\YamlConfigLoader" }, - "time": "2017-12-22 17:28:19", + "time": "2017-12-22T17:28:19+00:00", "type": "library", "extra": { "branch-alias": { @@ -133,7 +195,7 @@ "satooshi/php-coveralls": "dev-master", "squizlabs/php_codesniffer": "2.*" }, - "time": "2017-11-29 01:44:16", + "time": "2017-11-29T01:44:16+00:00", "type": "library", "extra": { "branch-alias": { @@ -184,7 +246,7 @@ "squizlabs/php_codesniffer": "^2.7", "victorjonsson/markdowndocs": "^1.3" }, - "time": "2017-11-29 15:25:38", + "time": "2017-11-29T15:25:38+00:00", "type": "library", "extra": { "branch-alias": { @@ -259,7 +321,7 @@ "patchwork/jsqueeze": "For minifying JS files in taskMinify", "pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively." }, - "time": "2017-12-29 06:48:35", + "time": "2017-12-29T06:48:35+00:00", "bin": [ "robo" ], @@ -306,7 +368,7 @@ "require": { "psr/container": "^1.0" }, - "time": "2017-02-14 19:40:03", + "time": "2017-02-14T19:40:03+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -339,7 +401,7 @@ "require": { "php": ">=5.3.2" }, - "time": "2017-01-20 21:14:22", + "time": "2017-01-20T21:14:22+00:00", "type": "library", "extra": { "branch-alias": { @@ -407,7 +469,7 @@ "phpunit/phpunit": "~4.0", "squizlabs/php_codesniffer": "~2.0" }, - "time": "2015-06-14 21:17:01", + "time": "2015-06-14T21:17:01+00:00", "type": "library", "extra": { "branch-alias": { @@ -456,7 +518,7 @@ "require": { "php": ">=5.3.2" }, - "time": "2014-09-09 13:34:57", + "time": "2014-09-09T13:34:57+00:00", "type": "library", "extra": { "branch-alias": { @@ -521,7 +583,7 @@ "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" }, - "time": "2017-11-15 23:40:40", + "time": "2017-11-15T23:40:40+00:00", "type": "library", "extra": { "branch-alias": { @@ -581,7 +643,7 @@ "symfony/var-dumper": "Pretty print complex values better with var-dumper available", "whoops/soap": "Formats errors as SOAP responses" }, - "time": "2017-11-23 18:22:44", + "time": "2017-11-23T18:22:44+00:00", "type": "library", "extra": { "branch-alias": { @@ -647,7 +709,7 @@ "twig/extensions": "Is necessary if you want to use the Twig extractor", "twig/twig": "Is necessary if you want to use the Twig extractor" }, - "time": "2016-06-15 18:14:14", + "time": "2016-06-15T18:14:14+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -699,7 +761,7 @@ "require-dev": { "phpunit/phpunit": "^4" }, - "time": "2017-03-23 17:02:28", + "time": "2017-03-23T17:02:28+00:00", "bin": [ "bin/export-plural-rules", "bin/export-plural-rules.php" @@ -766,7 +828,7 @@ "satooshi/php-coveralls": "^1.0.2|dev-master", "squizlabs/php_codesniffer": "^2.7" }, - "time": "2017-12-21 22:14:55", + "time": "2017-12-21T22:14:55+00:00", "type": "library", "extra": { "branch-alias": { @@ -816,7 +878,7 @@ "satooshi/php-coveralls": "^1.0.2|dev-master", "squizlabs/php_codesniffer": "^2.7" }, - "time": "2017-12-16 16:06:03", + "time": "2017-12-16T16:06:03+00:00", "type": "library", "extra": { "branch-alias": { @@ -869,7 +931,7 @@ "require-dev": { "phpunit/phpunit": "4.*" }, - "time": "2017-05-10 09:20:27", + "time": "2017-05-10T09:20:27+00:00", "type": "library", "extra": { "branch-alias": { @@ -950,7 +1012,7 @@ "ruflin/elastica": "Allow sending log messages to an Elastic Search server", "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" }, - "time": "2015-03-09 09:58:04", + "time": "2015-03-09T09:58:04+00:00", "type": "library", "extra": { "branch-alias": { @@ -1005,7 +1067,7 @@ "doctrine/common": "^2.6", "phpunit/phpunit": "^4.1" }, - "time": "2017-10-19 19:58:43", + "time": "2017-10-19T19:58:43+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1029,6 +1091,42 @@ "object graph" ] }, + { + "name": "neitanod/forceutf8", + "version": "v2.0.1", + "version_normalized": "2.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/neitanod/forceutf8.git", + "reference": "47c883ab2739e7938a8bb0bfd1c29d48c88858de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/neitanod/forceutf8/zipball/47c883ab2739e7938a8bb0bfd1c29d48c88858de", + "reference": "47c883ab2739e7938a8bb0bfd1c29d48c88858de", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2017-05-22T18:50:57+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "ForceUTF8\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "authors": [ + { + "name": "Sebastián Grignoli", + "email": "grignoli@gmail.com" + } + ], + "description": "PHP Class Encoding featuring popular Encoding::toUTF8() function --formerly known as forceUTF8()-- that fixes mixed encoded strings.", + "homepage": "https://github.com/neitanod/forceutf8" + }, { "name": "pear/console_getopt", "version": "v1.4.1", @@ -1044,7 +1142,7 @@ "reference": "82f05cd1aa3edf34e19aa7c8ca312ce13a6a577f", "shasum": "" }, - "time": "2015-07-20 20:28:12", + "time": "2015-07-20T20:28:12+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1078,6 +1176,66 @@ ], "description": "More info available on: http://pear.php.net/package/Console_Getopt" }, + { + "name": "pear/mail", + "version": "v1.4.1", + "version_normalized": "1.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/pear/Mail.git", + "reference": "9609ed5e42ac5b221dfd9af85de005c59d418ee7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/Mail/zipball/9609ed5e42ac5b221dfd9af85de005c59d418ee7", + "reference": "9609ed5e42ac5b221dfd9af85de005c59d418ee7", + "shasum": "" + }, + "require": { + "pear/pear-core-minimal": "~1.9", + "php": ">=5.2.1" + }, + "require-dev": { + "pear/pear": "*" + }, + "suggest": { + "pear/net_smtp": "Install optionally via your project's composer.json" + }, + "time": "2017-04-11T17:27:29+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Mail": "./" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "./" + ], + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Chuck Hagenbuch", + "email": "chuck@horde.org", + "role": "Lead" + }, + { + "name": "Richard Heyes", + "email": "richard@phpguru.org", + "role": "Developer" + }, + { + "name": "Aleksander Machniak", + "email": "alec@alec.pl", + "role": "Developer" + } + ], + "description": "Class that provides multiple interfaces for sending emails.", + "homepage": "http://pear.php.net/package/Mail" + }, { "name": "pear/net_smtp", "version": "1.7.3", @@ -1104,7 +1262,7 @@ "suggest": { "pear/auth_sasl": "Install optionally via your project's composer.json" }, - "time": "2017-01-14 18:19:55", + "time": "2017-01-14T18:19:55+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1162,7 +1320,7 @@ "require-dev": { "phpunit/phpunit": "^4" }, - "time": "2017-04-06 15:16:38", + "time": "2017-04-06T15:16:38+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1218,7 +1376,7 @@ "replace": { "rsky/pear-core-min": "self.version" }, - "time": "2017-02-28 16:46:11", + "time": "2017-02-28T16:46:11+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1263,7 +1421,7 @@ "require-dev": { "phpunit/phpunit": "*" }, - "time": "2015-02-10 20:07:52", + "time": "2015-02-10T20:07:52+00:00", "type": "class", "extra": { "branch-alias": { @@ -1320,7 +1478,7 @@ "phar-io/version": "^1.0.1", "php": "^5.6 || ^7.0" }, - "time": "2017-03-05 18:14:27", + "time": "2017-03-05T18:14:27+00:00", "type": "library", "extra": { "branch-alias": { @@ -1374,7 +1532,7 @@ "require": { "php": "^5.6 || ^7.0" }, - "time": "2017-03-05 17:38:23", + "time": "2017-03-05T17:38:23+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1426,7 +1584,7 @@ "require-dev": { "phpunit/phpunit": "^4.6" }, - "time": "2017-09-11 18:02:19", + "time": "2017-09-11T18:02:19+00:00", "type": "library", "extra": { "branch-alias": { @@ -1487,7 +1645,7 @@ "mockery/mockery": "^1.0", "phpunit/phpunit": "^6.4" }, - "time": "2017-11-27 17:38:31", + "time": "2017-11-27T17:38:31+00:00", "type": "library", "extra": { "branch-alias": { @@ -1537,7 +1695,7 @@ "mockery/mockery": "^0.9.4", "phpunit/phpunit": "^5.2||^4.8.24" }, - "time": "2017-07-14 14:27:02", + "time": "2017-07-14T14:27:02+00:00", "type": "library", "extra": { "branch-alias": { @@ -1589,7 +1747,7 @@ "phpspec/phpspec": "^2.5|^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7" }, - "time": "2017-11-24 13:59:53", + "time": "2017-11-24T13:59:53+00:00", "type": "library", "extra": { "branch-alias": { @@ -1661,7 +1819,7 @@ "suggest": { "ext-xdebug": "^2.5.5" }, - "time": "2017-12-06 09:29:45", + "time": "2017-12-06T09:29:45+00:00", "type": "library", "extra": { "branch-alias": { @@ -1711,7 +1869,7 @@ "require": { "php": ">=5.3.3" }, - "time": "2017-11-27 13:52:08", + "time": "2017-11-27T13:52:08+00:00", "type": "library", "extra": { "branch-alias": { @@ -1760,7 +1918,7 @@ "require": { "php": ">=5.3.3" }, - "time": "2015-06-21 13:50:34", + "time": "2015-06-21T13:50:34+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1806,7 +1964,7 @@ "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, - "time": "2017-02-26 11:10:40", + "time": "2017-02-26T11:10:40+00:00", "type": "library", "extra": { "branch-alias": { @@ -1858,7 +2016,7 @@ "require-dev": { "phpunit/phpunit": "^6.2.4" }, - "time": "2017-11-27 05:48:46", + "time": "2017-11-27T05:48:46+00:00", "type": "library", "extra": { "branch-alias": { @@ -1938,7 +2096,7 @@ "ext-xdebug": "*", "phpunit/php-invoker": "^1.1" }, - "time": "2017-12-17 06:31:19", + "time": "2017-12-17T06:31:19+00:00", "bin": [ "phpunit" ], @@ -2003,7 +2161,7 @@ "suggest": { "ext-soap": "*" }, - "time": "2018-01-06 05:45:45", + "time": "2018-01-06T05:45:45+00:00", "type": "library", "extra": { "branch-alias": { @@ -2052,7 +2210,7 @@ "require": { "php": ">=5.3.0" }, - "time": "2017-02-14 16:28:37", + "time": "2017-02-14T16:28:37+00:00", "type": "library", "extra": { "branch-alias": { @@ -2103,7 +2261,7 @@ "require": { "php": ">=5.3.0" }, - "time": "2016-10-10 12:19:37", + "time": "2016-10-10T12:19:37+00:00", "type": "library", "extra": { "branch-alias": { @@ -2155,7 +2313,7 @@ "require-dev": { "phpunit/phpunit": "^5.7 || ^6.0" }, - "time": "2017-03-04 06:30:41", + "time": "2017-03-04T06:30:41+00:00", "type": "library", "extra": { "branch-alias": { @@ -2204,7 +2362,7 @@ "require-dev": { "phpunit/phpunit": "^6.4" }, - "time": "2017-12-22 14:50:35", + "time": "2017-12-22T14:50:35+00:00", "type": "library", "extra": { "branch-alias": { @@ -2268,7 +2426,7 @@ "require-dev": { "phpunit/phpunit": "^6.2" }, - "time": "2017-08-03 08:09:46", + "time": "2017-08-03T08:09:46+00:00", "type": "library", "extra": { "branch-alias": { @@ -2322,7 +2480,7 @@ "require-dev": { "phpunit/phpunit": "^6.1" }, - "time": "2017-07-01 08:51:00", + "time": "2017-07-01T08:51:00+00:00", "type": "library", "extra": { "branch-alias": { @@ -2376,7 +2534,7 @@ "ext-mbstring": "*", "phpunit/phpunit": "^6.0" }, - "time": "2017-04-03 13:19:02", + "time": "2017-04-03T13:19:02+00:00", "type": "library", "extra": { "branch-alias": { @@ -2446,7 +2604,7 @@ "suggest": { "ext-uopz": "*" }, - "time": "2017-04-27 15:39:26", + "time": "2017-04-27T15:39:26+00:00", "type": "library", "extra": { "branch-alias": { @@ -2498,7 +2656,7 @@ "require-dev": { "phpunit/phpunit": "^6.0" }, - "time": "2017-08-03 12:35:26", + "time": "2017-08-03T12:35:26+00:00", "type": "library", "extra": { "branch-alias": { @@ -2545,7 +2703,7 @@ "require-dev": { "phpunit/phpunit": "^6.0" }, - "time": "2017-03-29 09:07:27", + "time": "2017-03-29T09:07:27+00:00", "type": "library", "extra": { "branch-alias": { @@ -2592,7 +2750,7 @@ "require-dev": { "phpunit/phpunit": "^6.0" }, - "time": "2017-03-03 06:23:57", + "time": "2017-03-03T06:23:57+00:00", "type": "library", "extra": { "branch-alias": { @@ -2644,7 +2802,7 @@ "require": { "php": ">=5.6.0" }, - "time": "2015-07-28 20:34:47", + "time": "2015-07-28T20:34:47+00:00", "type": "library", "extra": { "branch-alias": { @@ -2688,7 +2846,7 @@ "require": { "php": ">=5.6" }, - "time": "2016-10-03 07:35:21", + "time": "2016-10-03T07:35:21+00:00", "type": "library", "extra": { "branch-alias": { @@ -2715,6 +2873,60 @@ "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version" }, + { + "name": "spomky-labs/base64url", + "version": "v1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/base64url.git", + "reference": "ef6d5fb93894063d9cee996022259fd08d6646ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/ef6d5fb93894063d9cee996022259fd08d6646ea", + "reference": "ef6d5fb93894063d9cee996022259fd08d6646ea", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "time": "2016-01-21T19:50:30+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Base64Url\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/base64url/contributors" + } + ], + "description": "Base 64 URL Safe Encoding/decoding PHP Library", + "homepage": "https://github.com/Spomky-Labs/base64url", + "keywords": [ + "base64", + "rfc4648", + "safe", + "url" + ] + }, { "name": "swiftmailer/swiftmailer", "version": "v6.0.2", @@ -2738,7 +2950,7 @@ "mockery/mockery": "~0.9.1", "symfony/phpunit-bridge": "~3.3@dev" }, - "time": "2017-09-30 22:39:41", + "time": "2017-09-30T22:39:41+00:00", "type": "library", "extra": { "branch-alias": { @@ -2810,7 +3022,7 @@ "symfony/lock": "", "symfony/process": "" }, - "time": "2018-01-03 07:37:34", + "time": "2018-01-03T07:37:34+00:00", "type": "library", "extra": { "branch-alias": { @@ -2868,7 +3080,7 @@ "require-dev": { "symfony/http-kernel": "~2.8|~3.0|~4.0" }, - "time": "2018-01-03 17:14:19", + "time": "2018-01-03T17:14:19+00:00", "type": "library", "extra": { "branch-alias": { @@ -2933,7 +3145,7 @@ "symfony/dependency-injection": "", "symfony/http-kernel": "" }, - "time": "2018-01-03 07:37:34", + "time": "2018-01-03T07:37:34+00:00", "type": "library", "extra": { "branch-alias": { @@ -2984,7 +3196,7 @@ "require": { "php": "^5.5.9|>=7.0.8" }, - "time": "2018-01-03 07:37:34", + "time": "2018-01-03T07:37:34+00:00", "type": "library", "extra": { "branch-alias": { @@ -3035,7 +3247,7 @@ "require": { "php": "^5.5.9|>=7.0.8" }, - "time": "2018-01-03 07:37:34", + "time": "2018-01-03T07:37:34+00:00", "type": "library", "extra": { "branch-alias": { @@ -3089,7 +3301,7 @@ "suggest": { "ext-mbstring": "For best performance" }, - "time": "2017-10-11 12:05:26", + "time": "2017-10-11T12:05:26+00:00", "type": "library", "extra": { "branch-alias": { @@ -3147,7 +3359,7 @@ "require": { "php": "^5.5.9|>=7.0.8" }, - "time": "2018-01-03 07:37:34", + "time": "2018-01-03T07:37:34+00:00", "type": "library", "extra": { "branch-alias": { @@ -3207,7 +3419,7 @@ "suggest": { "symfony/console": "For validating YAML files using the lint command" }, - "time": "2018-01-03 07:37:34", + "time": "2018-01-03T07:37:34+00:00", "type": "library", "extra": { "branch-alias": { @@ -3261,7 +3473,7 @@ "ext-xmlwriter": "*", "php": "^7.0" }, - "time": "2017-04-07 12:08:54", + "time": "2017-04-07T12:08:54+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3304,7 +3516,7 @@ "symfony/debug": "~2.7", "symfony/phpunit-bridge": "~2.7" }, - "time": "2016-01-11 14:02:19", + "time": "2016-01-11T14:02:19+00:00", "type": "library", "extra": { "branch-alias": { @@ -3367,7 +3579,7 @@ "phpunit/phpunit": "^4.6", "sebastian/version": "^1.0.1" }, - "time": "2016-11-23 20:04:58", + "time": "2016-11-23T20:04:58+00:00", "type": "library", "extra": { "branch-alias": { @@ -3396,65 +3608,5 @@ "check", "validate" ] - }, - { - "name": "pear/mail", - "version": "v1.4.1", - "version_normalized": "1.4.1.0", - "source": { - "type": "git", - "url": "https://github.com/pear/Mail.git", - "reference": "9609ed5e42ac5b221dfd9af85de005c59d418ee7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pear/Mail/zipball/9609ed5e42ac5b221dfd9af85de005c59d418ee7", - "reference": "9609ed5e42ac5b221dfd9af85de005c59d418ee7", - "shasum": "" - }, - "require": { - "pear/pear-core-minimal": "~1.9", - "php": ">=5.2.1" - }, - "require-dev": { - "pear/pear": "*" - }, - "suggest": { - "pear/net_smtp": "Install optionally via your project's composer.json" - }, - "time": "2017-04-11 17:27:29", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-0": { - "Mail": "./" - } - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "./" - ], - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Chuck Hagenbuch", - "email": "chuck@horde.org", - "role": "Lead" - }, - { - "name": "Richard Heyes", - "email": "richard@phpguru.org", - "role": "Developer" - }, - { - "name": "Aleksander Machniak", - "email": "alec@alec.pl", - "role": "Developer" - } - ], - "description": "Class that provides multiple interfaces for sending emails.", - "homepage": "http://pear.php.net/package/Mail" } ] diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src deleted file mode 120000 index 929cb3dc..00000000 --- a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src +++ /dev/null @@ -1 +0,0 @@ -../../src \ No newline at end of file diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Config.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Config.php new file mode 100644 index 00000000..25f714f2 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Config.php @@ -0,0 +1,157 @@ +config = new Data($data); + $this->setDefaults(new Data()); + } + + /** + * {@inheritdoc} + */ + public function has($key) + { + return ($this->config->has($key)); + } + + /** + * {@inheritdoc} + */ + public function get($key, $defaultFallback = null) + { + if ($this->has($key)) { + return $this->config->get($key); + } + return $this->getDefault($key, $defaultFallback); + } + + /** + * {@inheritdoc} + */ + public function set($key, $value) + { + $this->config->set($key, $value); + return $this; + } + + /** + * {@inheritdoc} + */ + public function import($data) + { + return $this->replace($data); + } + + /** + * {@inheritdoc} + */ + public function replace($data) + { + $this->config = new Data($data); + return $this; + } + + /** + * {@inheritdoc} + */ + public function combine($data) + { + if (!empty($data)) { + $this->config->import($data, true); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function export() + { + return $this->config->export(); + } + + /** + * {@inheritdoc} + */ + public function hasDefault($key) + { + return $this->getDefaults()->has($key); + } + + /** + * {@inheritdoc} + */ + public function getDefault($key, $defaultFallback = null) + { + return $this->hasDefault($key) ? $this->getDefaults()->get($key) : $defaultFallback; + } + + /** + * {@inheritdoc} + */ + public function setDefault($key, $value) + { + $this->getDefaults()->set($key, $value); + return $this; + } + + /** + * Return the class $defaults property and ensure it's a Data object + * TODO: remove Data object validation in 2.0 + * + * @return Data + */ + protected function getDefaults() + { + // Ensure $this->defaults is a Data object (not an array) + if (!$this->defaults instanceof Data) { + $this->setDefaults($this->defaults); + } + return $this->defaults; + } + + /** + * Sets the $defaults class parameter + * TODO: remove support for array in 2.0 as this would currently break backward compatibility + * + * @param Data|array $defaults + * + * @throws \Exception + */ + protected function setDefaults($defaults) + { + if (is_array($defaults)) { + $this->defaults = new Data($defaults); + } elseif ($defaults instanceof Data) { + $this->defaults = $defaults; + } else { + throw new \Exception("Unknown type provided for \$defaults"); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/ConfigInterface.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/ConfigInterface.php new file mode 100644 index 00000000..5124ea1f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/ConfigInterface.php @@ -0,0 +1,105 @@ + default-value + */ + public function getGlobalOptionDefaultValues(); +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Inject/ConfigForCommand.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Inject/ConfigForCommand.php new file mode 100644 index 00000000..ce2646e1 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Inject/ConfigForCommand.php @@ -0,0 +1,127 @@ +config = $config; + } + + public function setApplication(Application $application) + { + $this->application = $application; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ConsoleEvents::COMMAND => 'injectConfiguration']; + } + + /** + * Before a Console command runs, inject configuration settings + * for this command into the default value of the options of + * this command. + * + * @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event + */ + public function injectConfiguration(ConsoleCommandEvent $event) + { + $command = $event->getCommand(); + $this->injectConfigurationForGlobalOptions($event->getInput()); + $this->injectConfigurationForCommand($command, $event->getInput()); + + $targetOfHelpCommand = $this->getHelpCommandTarget($command, $event->getInput()); + if ($targetOfHelpCommand) { + $this->injectConfigurationForCommand($targetOfHelpCommand, $event->getInput()); + } + } + + protected function injectConfigurationForGlobalOptions($input) + { + if (!$this->application) { + return; + } + + $configGroup = new ConfigFallback($this->config, 'options'); + + $definition = $this->application->getDefinition(); + $options = $definition->getOptions(); + + return $this->injectConfigGroupIntoOptions($configGroup, $options, $input); + } + + protected function injectConfigurationForCommand($command, $input) + { + $commandName = $command->getName(); + $commandName = str_replace(':', '.', $commandName); + $configGroup = new ConfigFallback($this->config, $commandName, 'command.', '.options.'); + + $definition = $command->getDefinition(); + $options = $definition->getOptions(); + + return $this->injectConfigGroupIntoOptions($configGroup, $options, $input); + } + + protected function injectConfigGroupIntoOptions($configGroup, $options, $input) + { + foreach ($options as $option => $inputOption) { + $key = str_replace('.', '-', $option); + $value = $configGroup->get($key); + if ($value !== null) { + if (is_bool($value) && ($value == true)) { + $input->setOption($key, $value); + } elseif ($inputOption->acceptValue()) { + $inputOption->setDefault($value); + } + } + } + } + + protected function getHelpCommandTarget($command, $input) + { + if (($command->getName() != 'help') || (!isset($this->application))) { + return false; + } + + $this->fixInputForSymfony2($command, $input); + + // Symfony Console helpfully swaps 'command_name' and 'command' + // depending on whether the user entered `help foo` or `--help foo`. + // One of these is always `help`, and the other is the command we + // are actually interested in. + $nameOfCommandToDescribe = $input->getArgument('command_name'); + if ($nameOfCommandToDescribe == 'help') { + $nameOfCommandToDescribe = $input->getArgument('command'); + } + return $this->application->find($nameOfCommandToDescribe); + } + + protected function fixInputForSymfony2($command, $input) + { + // Symfony 3.x prepares $input for us; Symfony 2.x, on the other + // hand, passes it in prior to binding with the command definition, + // so we have to go to a little extra work. It may be inadvisable + // to do these steps for commands other than 'help'. + if (!$input->hasArgument('command_name')) { + $command->ignoreValidationErrors(); + $command->mergeApplicationDefinition(); + $input->bind($command->getDefinition()); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Inject/ConfigForSetters.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Inject/ConfigForSetters.php new file mode 100644 index 00000000..5ec87042 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Inject/ConfigForSetters.php @@ -0,0 +1,47 @@ +config = new ConfigMerge($config, $group, $prefix, $postfix); + } + + public function apply($object, $configurationKey) + { + $settings = $this->config->get($configurationKey); + foreach ($settings as $setterMethod => $args) { + $fn = [$object, $setterMethod]; + if (is_callable($fn)) { + $result = call_user_func_array($fn, (array)$args); + + // We require that $fn must only be used with setter methods. + // Setter methods are required to always return $this so that + // they may be chained. We will therefore throw an exception + // for any setter that returns something else. + if ($result != $object) { + $methodDescription = get_class($object) . "::$setterMethod"; + $propertyDescription = $this->config->describe($configurationKey); + throw new \Exception("$methodDescription did not return '\$this' when processing $propertyDescription."); + } + } + } + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigLoader.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigLoader.php new file mode 100644 index 00000000..ecc6f64f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigLoader.php @@ -0,0 +1,35 @@ +source; + } + + protected function setSourceName($source) + { + $this->source = $source; + return $this; + } + + public function export() + { + return $this->config; + } + + public function keys() + { + return array_keys($this->config); + } + + abstract public function load($path); +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigLoaderInterface.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigLoaderInterface.php new file mode 100644 index 00000000..9b155c1b --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/ConfigLoaderInterface.php @@ -0,0 +1,29 @@ +expander = $expander ?: new Expander(); + } + + /** + * Extend the configuration to be processed with the + * configuration provided by the specified loader. + * + * @param ConfigLoaderInterface $loader + */ + public function extend(ConfigLoaderInterface $loader) + { + return $this->addFromSource($loader->export(), $loader->getSourceName()); + } + + /** + * Extend the configuration to be processed with + * the provided nested array. + * + * @param array $data + */ + public function add($data) + { + $this->unprocessedConfig[] = $data; + return $this; + } + + /** + * Extend the configuration to be processed with + * the provided nested array. Also record the name + * of the data source, if applicable. + * + * @param array $data + * @param string $source + */ + protected function addFromSource($data, $source = '') + { + if (empty($source)) { + return $this->add($data); + } + $this->unprocessedConfig[$source] = $data; + return $this; + } + + /** + * Process all of the configuration that has been collected, + * and return a nested array. + * + * @return array + */ + public function export($referenceArray = []) + { + if (!empty($this->unprocessedConfig)) { + $this->processedConfig = $this->process( + $this->processedConfig, + $this->fetchUnprocessed(), + $referenceArray + ); + } + return $this->processedConfig; + } + + /** + * To aid in debugging: return the source of each configuration item. + * n.b. Must call this function *before* export and save the result + * if persistence is desired. + */ + public function sources() + { + $sources = []; + foreach ($this->unprocessedConfig as $sourceName => $config) { + if (!empty($sourceName)) { + $configSources = ArrayUtil::fillRecursive($config, $sourceName); + $sources = ArrayUtil::mergeRecursiveDistinct($sources, $configSources); + } + } + return $sources; + } + + /** + * Get the configuration to be processed, and clear out the + * 'unprocessed' list. + * + * @return array + */ + protected function fetchUnprocessed() + { + $toBeProcessed = $this->unprocessedConfig; + $this->unprocessedConfig = []; + return $toBeProcessed; + } + + /** + * Use a map-reduce to evaluate the items to be processed, + * and merge them into the processed array. + * + * @param array $processed + * @param array $toBeProcessed + * @return array + */ + protected function process(array $processed, array $toBeProcessed, $referenceArray = []) + { + $toBeReduced = array_map([$this, 'preprocess'], $toBeProcessed); + $reduced = array_reduce($toBeReduced, [$this, 'reduceOne'], $processed); + return $this->evaluate($reduced, $referenceArray); + } + + /** + * Process a single configuration file from the 'to be processed' + * list. By default this is a no-op. Override this method to + * provide any desired configuration preprocessing, e.g. dot-notation + * expansion of the configuration keys, etc. + * + * @param array $config + * @return array + */ + protected function preprocess(array $config) + { + return $config; + } + + /** + * Evaluate one item in the 'to be evaluated' list, and then + * merge it into the processed configuration (the 'carry'). + * + * @param array $processed + * @param array $config + * @return array + */ + protected function reduceOne(array $processed, array $config) + { + return ArrayUtil::mergeRecursiveDistinct($processed, $config); + } + + /** + * Evaluate one configuration item. + * + * @param array $processed + * @param array $config + * @return array + */ + protected function evaluate(array $config, $referenceArray = []) + { + return $this->expander->expandArrayProperties( + $config, + $referenceArray + ); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/YamlConfigLoader.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/YamlConfigLoader.php new file mode 100644 index 00000000..45705662 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Loader/YamlConfigLoader.php @@ -0,0 +1,26 @@ +setSourceName($path); + + // We silently skip any nonexistent config files, so that + // clients may simply `load` all of their candidates. + if (!file_exists($path)) { + $this->config = []; + return $this; + } + $this->config = (array) Yaml::parse(file_get_contents($path)); + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ArrayUtil.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ArrayUtil.php new file mode 100644 index 00000000..a23f854e --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ArrayUtil.php @@ -0,0 +1,75 @@ + &$value) { + $merged[$key] = self::mergeRecursiveValue($merged, $key, $value); + } + return $merged; + } + + /** + * Process the value in an mergeRecursiveDistinct - make a recursive + * call if needed. + */ + protected static function mergeRecursiveValue(&$merged, $key, $value) + { + if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { + return self::mergeRecursiveDistinct($merged[$key], $value); + } + return $value; + } + + /** + * Fills all of the leaf-node values of a nested array with the + * provided replacement value. + */ + public static function fillRecursive(array $data, $fill) + { + $result = []; + foreach ($data as $key => $value) { + $result[$key] = $fill; + if (self::isAssociative($value)) { + $result[$key] = self::fillRecursive($value, $fill); + } + } + return $result; + } + + /** + * Return true if the provided parameter is an array, and at least + * one key is non-numeric. + */ + public static function isAssociative($testArray) + { + if (!is_array($testArray)) { + return false; + } + foreach (array_keys($testArray) as $key) { + if (!is_numeric($key)) { + return true; + } + } + return false; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigFallback.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigFallback.php new file mode 100644 index 00000000..9f9972f6 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigFallback.php @@ -0,0 +1,51 @@ +getWithFallback($key, $this->group, $this->prefix, $this->postfix); + } + + /** + * Fetch an option value from a given key, or, if that specific key does + * not contain a value, then consult various fallback options until a + * value is found. + * + */ + protected function getWithFallback($key, $group, $prefix = '', $postfix = '.') + { + $configKey = "{$prefix}{$group}${postfix}{$key}"; + if ($this->config->has($configKey)) { + return $this->config->get($configKey); + } + if ($this->config->hasDefault($configKey)) { + return $this->config->getDefault($configKey); + } + $moreGeneralGroupname = $this->moreGeneralGroupName($group); + if ($moreGeneralGroupname) { + return $this->getWithFallback($key, $moreGeneralGroupname, $prefix, $postfix); + } + return null; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigGroup.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigGroup.php new file mode 100644 index 00000000..24b29dd8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigGroup.php @@ -0,0 +1,61 @@ +config = $config; + $this->group = $group; + $this->prefix = $prefix; + $this->postfix = $postfix; + } + + /** + * Return a description of the configuration group (with prefix and postfix). + */ + public function describe($property) + { + return $this->prefix . $this->group . $this->postfix . $property; + } + + /** + * Get the requested configuration key from the most specific configuration + * group that contains it. + */ + abstract public function get($key); + + /** + * Given a group name, such as "foo.bar.baz", return the next configuration + * group in the fallback hierarchy, e.g. "foo.bar". + */ + protected function moreGeneralGroupName($group) + { + $result = preg_replace('#\.[^.]*$#', '', $group); + if ($result != $group) { + return $result; + } + return false; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigMerge.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigMerge.php new file mode 100644 index 00000000..65fccf72 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigMerge.php @@ -0,0 +1,34 @@ +getWithMerge($key, $this->group, $this->prefix, $this->postfix); + } + + /** + * Merge available configuration from each configuration group. + */ + public function getWithMerge($key, $group, $prefix = '', $postfix = '.') + { + $configKey = "{$prefix}{$group}${postfix}{$key}"; + $result = $this->config->get($configKey, []); + if (!is_array($result)) { + throw new \UnexpectedValueException($configKey . ' must be a list of settings to apply.'); + } + $moreGeneralGroupname = $this->moreGeneralGroupName($group); + if ($moreGeneralGroupname) { + $result += $this->getWithMerge($key, $moreGeneralGroupname, $prefix, $postfix); + } + return $result; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigOverlay.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigOverlay.php new file mode 100644 index 00000000..d1f12697 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/ConfigOverlay.php @@ -0,0 +1,203 @@ +contexts[self::DEFAULT_CONTEXT] = new Config(); + $this->contexts[self::PROCESS_CONTEXT] = new Config(); + } + + /** + * Add a named configuration object to the configuration overlay. + * Configuration objects added LAST have HIGHEST priority, with the + * exception of the fact that the process context always has the + * highest priority. + * + * If a context has already been added, its priority will not change. + */ + public function addContext($name, ConfigInterface $config) + { + $process = $this->contexts[self::PROCESS_CONTEXT]; + unset($this->contexts[self::PROCESS_CONTEXT]); + $this->contexts[$name] = $config; + $this->contexts[self::PROCESS_CONTEXT] = $process; + + return $this; + } + + /** + * Add a placeholder context that will be prioritized higher than + * existing contexts. This is done to ensure that contexts added + * later will maintain a higher priority if the placeholder context + * is later relaced with a different configuration set via addContext(). + * + * @param string $name + * @return $this + */ + public function addPlaceholder($name) + { + return $this->addContext($name, new Config()); + } + + /** + * Increase the priority of the named context such that it is higher + * in priority than any existing context except for the 'process' + * context. + * + * @param string $name + * @return $this + */ + public function increasePriority($name) + { + $config = $this->getContext($name); + unset($this->contexts[$name]); + return $this->addContext($name, $config); + } + + public function hasContext($name) + { + return isset($this->contexts[$name]); + } + + public function getContext($name) + { + if ($this->hasContext($name)) { + return $this->contexts[$name]; + } + return new Config(); + } + + public function removeContext($name) + { + unset($this->contexts[$name]); + } + + /** + * Determine if a non-default config value exists. + */ + public function findContext($key) + { + foreach (array_reverse($this->contexts) as $name => $config) { + if ($config->has($key)) { + return $config; + } + } + return false; + } + + /** + * @inheritdoc + */ + public function has($key) + { + return $this->findContext($key) != false; + } + + /** + * @inheritdoc + */ + public function get($key, $default = null) + { + $context = $this->findContext($key); + if ($context) { + return $context->get($key, $default); + } + return $default; + } + + /** + * @inheritdoc + */ + public function set($key, $value) + { + $this->contexts[self::PROCESS_CONTEXT]->set($key, $value); + return $this; + } + + /** + * @inheritdoc + */ + public function import($data) + { + $this->unsupported(__FUNCTION__); + } + + /** + * @inheritdoc + */ + public function replace($data) + { + $this->unsupported(__FUNCTION__); + } + + /** + * @inheritdoc + */ + public function combine($data) + { + $this->unsupported(__FUNCTION__); + } + + /** + * @inheritdoc + */ + protected function unsupported($fn) + { + throw new \Exception("The method '$fn' is not supported for the ConfigOverlay class."); + } + + /** + * @inheritdoc + */ + public function export() + { + $export = []; + foreach ($this->contexts as $name => $config) { + $export = array_merge_recursive($export, $config->export()); + } + return $export; + } + + /** + * @inheritdoc + */ + public function hasDefault($key) + { + return $this->contexts[self::DEFAULT_CONTEXT]->has($key); + } + + /** + * @inheritdoc + */ + public function getDefault($key, $default = null) + { + return $this->contexts[self::DEFAULT_CONTEXT]->get($key, $default); + } + + /** + * @inheritdoc + */ + public function setDefault($key, $value) + { + $this->contexts[self::DEFAULT_CONTEXT]->set($key, $value); + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/EnvConfig.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/EnvConfig.php new file mode 100644 index 00000000..05f8d2a8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/src/Util/EnvConfig.php @@ -0,0 +1,96 @@ +prefix = strtoupper(rtrim($prefix, '_')) . '_'; + } + + /** + * @inheritdoc + */ + public function has($key) + { + return $this->get($key) !== null; + } + + /** + * @inheritdoc + */ + public function get($key, $defaultFallback = null) + { + $envKey = $this->prefix . strtoupper(strtr($key, '.-', '__')); + $envKey = str_replace($this->prefix . $this->prefix, $this->prefix, $envKey); + return getenv($envKey) ?: $defaultFallback; + } + + /** + * @inheritdoc + */ + public function set($key, $value) + { + throw new \Exception('Cannot call "set" on environmental configuration.'); + } + + /** + * @inheritdoc + */ + public function import($data) + { + // no-op + } + + /** + * @inheritdoc + */ + public function export() + { + return []; + } + + /** + * @inheritdoc + */ + public function hasDefault($key) + { + return false; + } + + /** + * @inheritdoc + */ + public function getDefault($key, $defaultFallback = null) + { + return $defaultFallback; + } + + /** + * @inheritdoc + */ + public function setDefault($key, $value) + { + throw new \Exception('Cannot call "setDefault" on environmental configuration.'); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests deleted file mode 120000 index c2ebfe53..00000000 --- a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests +++ /dev/null @@ -1 +0,0 @@ -../../tests \ No newline at end of file diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigForCommandTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigForCommandTest.php new file mode 100644 index 00000000..41da3076 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigForCommandTest.php @@ -0,0 +1,130 @@ + [ + 'global' => 'from-config', + ], + // Define some configuration settings for the options for + // the commands my:foo and my:bar. + 'command' => [ + 'my' => [ + // commands.my.options.* apply to all my:* commands. + 'options' => [ + 'dir' => '/etc/common', + 'priority' => 'normal', + ], + 'foo' => [ + // commands.my.foo.options.* apply only to the my:foo command. + 'options' => [ + 'name' => 'baz', + ], + ], + ], + ], + ]; + + $this->config = new Config($data); + } + + public function testInjection() + { + $command = new MyFooCommand(); + $input = new StringInput('my:foo'); + + list($status, $output) = $this->runCommandViaApplication($command, $input); + + $expectedOutput = <<< EOT +Enter my:foo +dir: /etc/common +name: baz +other: fish +EOT; + + $this->assertEquals(0, $status); + $this->assertEquals($expectedOutput, $output); + } + + public function testInjectionWithOverride() + { + $command = new MyFooCommand(); + $input = new StringInput('my:foo --name=Fred'); + + list($status, $output) = $this->runCommandViaApplication($command, $input); + + $expectedOutput = <<< EOT +Enter my:foo +dir: /etc/common +name: Fred +other: fish +EOT; + + $this->assertEquals(0, $status); + $this->assertEquals($expectedOutput, $output); + } + + public function testHelpDefaultInjection() + { + $command = new MyFooCommand(); + $input = new StringInput('help my:foo'); + + list($status, $output) = $this->runCommandViaApplication($command, $input); + + $expectedOutput = <<< EOT +What is the name of the thing we are naming [default: "baz"] +EOT; + + $this->assertEquals(0, $status); + $this->assertContains($expectedOutput, $output); + + $expectedOutput = <<< EOT +A certain global option. [default: "from-config"] +EOT; + + $this->assertContains($expectedOutput, $output); + } + + protected function runCommandViaApplication($command, $input) + { + $application = new Application('TestApplication', '0.0.0'); + $application->getDefinition() + ->addOption( + new InputOption('--global', null, InputOption::VALUE_REQUIRED, 'A certain global option.', 'hardcoded') + ); + + $output = new BufferedOutput(); + + $configInjector = new ConfigForCommand($this->config); + $configInjector->setApplication($application); + + $eventDispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher(); + $eventDispatcher->addSubscriber($configInjector); + $application->setDispatcher($eventDispatcher); + + $application->setAutoExit(false); + $application->add($command); + + $statusCode = $application->run($input, $output); + $commandOutput = trim($output->fetch()); + + return [$statusCode, $commandOutput]; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigForSettersTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigForSettersTest.php new file mode 100644 index 00000000..422b0a00 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigForSettersTest.php @@ -0,0 +1,87 @@ + [ + 'Operations' => [ + // task.Operations.settings apply to all tasks in + // any *.Tass.Operations namespace. + 'settings' => [ + 'dir' => '/base/dir', + ], + 'Frobulate' => [ + // task.Operations.Frobulate.settings applies only + // the Frobulate task. + 'settings' => [ + 'dir' => '/override/dir', + ], + ], + ], + ], + ]; + $config = new Config($data); + + $applicator = new ConfigForSetters($config, 'Operations.Frobulate', 'task.'); + + $testTarget = new ApplyConfigTestTarget(); + + $applicator->apply($testTarget, 'settings'); + + $this->assertEquals('/override/dir', $testTarget->getDir()); + $this->assertEquals(null, $testTarget->getBad()); + } + + public function testApplyBadConfig() + { + $data = [ + // Define some configuration settings for the configuration + // of some task \My\Tasks\Operations\Frobulate. + 'task' => [ + 'Operations' => [ + // task.Operations.settings apply to all tasks in + // any *.Tass.Operations namespace. + 'settings' => [ + 'dir' => '/base/dir', + ], + 'Frobulate' => [ + // task.Operations.Frobulate.settings applies only + // the Frobulate task. + 'settings' => [ + 'bad' => 'fire truck', + ], + ], + ], + ], + ]; + $config = new Config($data); + + $applicator = new ConfigForSetters($config, 'Operations.Frobulate', 'task.'); + + $testTarget = new ApplyConfigTestTarget(); + + $exceptionMessage = ''; + try + { + $applicator->apply($testTarget, 'settings'); + } + catch (\Exception $e) + { + $exceptionMessage = $e->getMessage(); + } + // We would prefer it if bad methods were never called; unfortunately, + // declaring the return type of a method cannot be done in a reliable + // way (via reflection) until php 7, so we allow these methods to be + // called for now. + $this->assertEquals('fire truck', $testTarget->getBad()); + $this->assertEquals('Consolidation\\TestUtils\\ApplyConfigTestTarget::bad did not return \'$this\' when processing task.Operations.Frobulate.settings.', $exceptionMessage); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigGroupTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigGroupTest.php new file mode 100644 index 00000000..21e470e5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigGroupTest.php @@ -0,0 +1,91 @@ + [ + 'my' => [ + // commands.my.options.* apply to all my:* commands. + 'options' => [ + 'path' => '/etc/common', + 'priority' => 'normal', + ], + 'foo' => [ + // commands.my.foo.options.* apply only to the my:foo command. + 'options' => [ + 'name' => 'baz', + ], + ], + 'bar' => [ + // Similarly, commands.my.bar.options is for the my:bar command. + 'options' => [ + 'priority' => 'high', + ], + ], + ], + ], + // Define some configuration settings for the configuration + // of some task \My\Tasks\Operations\Frobulate. + 'task' => [ + 'Operations' => [ + // task.Operations.settings apply to all tasks in + // any *.Tass.Operations namespace. + 'settings' => [ + 'dir' => '/base/dir', + ], + 'Frobulate' => [ + // task.Operations.Frobulate.settings applies only + // the Frobulate task. + 'settings' => [ + 'object' => 'fire truck', + ], + ], + ], + ], + ]; + + $this->config = new Config($data); + } + + public function testDotNotation() + { + // Test the test + $this->assertEquals('baz', $this->config->get('command.my.foo.options.name')); + } + + public function testFallback() + { + $fooFallback = new ConfigFallback($this->config, 'my.foo', 'command.', '.options.'); + $barFallback = new ConfigFallback($this->config, 'my.bar', 'command.', '.options.'); + + $this->assertEquals(null, $barFallback->get('name')); + $this->assertEquals('baz', $fooFallback->get('name')); + $this->assertEquals('high', $barFallback->get('priority')); + + $this->assertEquals('normal', $fooFallback->get('priority')); + $this->assertEquals('/etc/common', $barFallback->get('path')); + $this->assertEquals('/etc/common', $fooFallback->get('path')); + } + + public function testMerge() + { + $frobulateMerge = new ConfigMerge($this->config, 'Operations.Frobulate', 'task.'); + + $settings = $frobulateMerge->get('settings'); + $this->assertEquals('fire truck', $settings['object']); + $this->assertEquals('/base/dir', $settings['dir']); + $keys = array_keys($settings); + sort($keys); + $this->assertEquals('dir,object', implode(',', $keys)); + } +} + diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigLoaderTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigLoaderTest.php new file mode 100644 index 00000000..6dedb1f3 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigLoaderTest.php @@ -0,0 +1,29 @@ +assertTrue(file_exists($path)); + + $loader->load($path); + + $configFile = basename($loader->getSourceName()); + $this->assertEquals('config-1.yml', $configFile); + + // Make sure that the data we loaded contained the expected keys + $keys = $loader->keys(); + sort($keys); + $keysString = implode(',', $keys); + $this->assertEquals('c,m', $keysString); + + $configData = $loader->export(); + $this->assertEquals('foo', $configData['c']); + $this->assertEquals('1', $configData['m'][0]); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigOverlayTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigOverlayTest.php new file mode 100644 index 00000000..f7faf748 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigOverlayTest.php @@ -0,0 +1,168 @@ +import([ + 'hidden-by-a' => 'alias hidden-by-a', + 'hidden-by-process' => 'alias hidden-by-process', + 'options' =>[ + 'a-a' => 'alias-a', + ], + 'command' => [ + 'foo' => [ + 'bar' => [ + 'command' => [ + 'options' => [ + 'a-b' => 'alias-b', + ], + ], + ], + ], + ], + ]); + + $configFileContext = new Config(); + $configFileContext->import([ + 'hidden-by-cf' => 'config-file hidden-by-cf', + 'hidden-by-a' => 'config-file hidden-by-a', + 'hidden-by-process' => 'config-file hidden-by-process', + 'options' =>[ + 'cf-a' => 'config-file-a', + ], + 'command' => [ + 'foo' => [ + 'bar' => [ + 'command' => [ + 'options' => [ + 'cf-b' => 'config-file-b', + ], + ], + ], + ], + ], + ]); + + $this->overlay = new ConfigOverlay(); + $this->overlay->set('hidden-by-process', 'process-h'); + $this->overlay->addContext('cf', $configFileContext); + $this->overlay->addContext('a', $aliasContext); + $this->overlay->setDefault('df-a', 'default'); + $this->overlay->setDefault('hidden-by-a', 'default hidden-by-a'); + $this->overlay->setDefault('hidden-by-cf', 'default hidden-by-cf'); + $this->overlay->setDefault('hidden-by-process', 'default hidden-by-process'); + } + + public function testGetPriority() + { + $this->assertEquals('process-h', $this->overlay->get('hidden-by-process')); + $this->assertEquals('config-file hidden-by-cf', $this->overlay->get('hidden-by-cf')); + $this->assertEquals('alias hidden-by-a', $this->overlay->get('hidden-by-a')); + } + + public function testDefault() + { + $this->assertEquals('alias-a', $this->overlay->get('options.a-a')); + $this->assertEquals('alias-a', $this->overlay->get('options.a-a', 'ignored')); + $this->assertEquals('default', $this->overlay->getDefault('df-a', 'ignored')); + $this->assertEquals('nsv', $this->overlay->getDefault('a-a', 'nsv')); + + $this->overlay->setDefault('df-a', 'new value'); + $this->assertEquals('new value', $this->overlay->getDefault('df-a', 'ignored')); + } + + public function testExport() + { + $data = $this->overlay->export(); + + $this->assertEquals('config-file-a', $data['options']['cf-a']); + $this->assertEquals('alias-a', $data['options']['a-a']); + } + + /** + * @expectedException Exception + */ + public function testImport() + { + $data = $this->overlay->import(['a' => 'value']); + } + + public function testMaintainPriority() + { + // Get and re-add the 'cf' context. Its priority should not change. + $configFileContext = $this->overlay->getContext('cf'); + $this->overlay->addContext('cf', $configFileContext); + + // These asserts are the same as in testGetPriority + $this->assertEquals('process-h', $this->overlay->get('hidden-by-process')); + $this->assertEquals('config-file hidden-by-cf', $this->overlay->get('hidden-by-cf')); + $this->assertEquals('alias hidden-by-a', $this->overlay->get('hidden-by-a')); + } + + public function testChangePriority() + { + // Increase the priority of the 'cf' context. Now, it should have a higher + // priority than the 'alias' context, but should still have a lower + // priority than the 'process' context. + $this->overlay->increasePriority('cf'); + + // These asserts are the same as in testGetPriority + $this->assertEquals('process-h', $this->overlay->get('hidden-by-process')); + $this->assertEquals('config-file hidden-by-cf', $this->overlay->get('hidden-by-cf')); + + // This one has changed: the config-file value is now found instead + // of the alias value. + $this->assertEquals('config-file hidden-by-a', $this->overlay->get('hidden-by-a')); + } + + public function testPlaceholder() + { + $this->overlay->addPlaceholder('lower'); + + $higherContext = new Config(); + $higherContext->import(['priority-test' => 'higher']); + + $lowerContext = new Config(); + $lowerContext->import(['priority-test' => 'lower']); + + // Usually 'lower' would have the highest priority, since it is + // added last. However, our earlier call to 'addPlaceholder' reserves + // a spot for it, so the 'higher' context will end up with a higher + // priority. + $this->overlay->addContext('higher', $higherContext); + $this->overlay->addContext('lower', $lowerContext); + $this->assertEquals('higher', $this->overlay->get('priority-test', 'neither')); + + // Test to see that we can change the value of the 'higher' context, + // and the change will be reflected in the overlay. + $higherContext->set('priority-test', 'changed'); + $this->assertEquals('changed', $this->overlay->get('priority-test', 'neither')); + + // Test to see that the 'process' context still has the highest priority. + $this->overlay->set('priority-test', 'process'); + $higherContext->set('priority-test', 'ignored'); + $this->assertEquals('process', $this->overlay->get('priority-test', 'neither')); + } + + public function testDoesNotHave() + { + $context = $this->overlay->getContext('no-such-context'); + $data = $context->export(); + $this->assertEquals('[]', json_encode($data)); + + $this->assertTrue(!$this->overlay->has('no-such-key')); + $this->assertTrue(!$this->overlay->hasDefault('no-such-default')); + + $this->assertEquals('no-such-value', $this->overlay->get('no-such-key', 'no-such-value')); + + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigProcessorTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigProcessorTest.php new file mode 100644 index 00000000..ac645a28 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigProcessorTest.php @@ -0,0 +1,152 @@ + 'foo', + 'm' => [1], + ]; + $config2 = [ + 'b' => '${c}bar', + 'm' => [2], + ]; + $config3 = [ + 'a' => '${b}baz', + 'm' => [3], + ]; + + $processor = new ConfigProcessor(); + $processor->add($config1); + $processor->add($config2); + $processor->add($config3); + + $data = $processor->export(); + $this->assertEquals('foo', $data['c']); + $this->assertEquals('foobar', $data['b']); + $this->assertEquals('foobarbaz', $data['a']); + } + + public function processorForConfigMergeTest($provideSourceNames) + { + $config1 = [ + 'm' => [ + 'x' => 'x-1', + 'y' => [ + 'r' => 'r-1', + 's' => 's-1', + 't' => 't-1', + ], + 'z' => 'z-1', + ], + ]; + $config2 = [ + 'm' => [ + 'w' => 'w-2', + 'y' => [ + 'q' => 'q-2', + 's' => 's-2', + ], + 'z' => 'z-2', + ], + ]; + $config3 = [ + 'm' => [ + 'v' => 'v-3', + 'y' => [ + 't' => 't-3', + 'u' => 'u-3', + ], + 'z' => 'z-3', + ], + ]; + + $processor = new ConfigProcessor(); + $testLoader = new TestLoader(); + + $testLoader->set($config1); + $testLoader->setSourceName($provideSourceNames ? 'c-1' : ''); + $processor->extend($testLoader); + + $testLoader->set($config2); + $testLoader->setSourceName($provideSourceNames ? 'c-2' : ''); + $processor->extend($testLoader); + + $testLoader->set($config3); + $testLoader->setSourceName($provideSourceNames ? 'c-3' : ''); + $processor->extend($testLoader); + + return $processor; + } + + public function testConfigProcessorMergeAssociative() + { + $processor = $this->processorForConfigMergeTest(false); + $data = $processor->export(); + $this->assertEquals('{"m":{"x":"x-1","y":{"r":"r-1","s":"s-2","t":"t-3","q":"q-2","u":"u-3"},"z":"z-3","w":"w-2","v":"v-3"}}', json_encode($data)); + } + + public function testConfigProcessorMergeAssociativeWithSourceNames() + { + $processor = $this->processorForConfigMergeTest(true); + $sources = $processor->sources(); + $data = $processor->export(); + $this->assertEquals('{"m":{"x":"x-1","y":{"r":"r-1","s":"s-2","t":"t-3","q":"q-2","u":"u-3"},"z":"z-3","w":"w-2","v":"v-3"}}', json_encode($data)); + $this->assertEquals('c-1', $sources['m']['x']); + $this->assertEquals('c-1', $sources['m']['y']['r']); + $this->assertEquals('c-2', $sources['m']['w']); + $this->assertEquals('c-2', $sources['m']['y']['s']); + $this->assertEquals('c-3', $sources['m']['z']); + $this->assertEquals('c-3', $sources['m']['y']['u']); + } + + public function testConfiProcessorSources() + { + $processor = new ConfigProcessor(); + $loader = new YamlConfigLoader(); + $processor->extend($loader->load(__DIR__ . '/data/config-1.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-2.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-3.yml')); + + $sources = $processor->sources(); + + $data = $processor->export(); + $this->assertEquals('foo', $data['c']); + $this->assertEquals('foobar', $data['b']); + $this->assertEquals('foobarbaz', $data['a']); + + $this->assertEquals('3', $data['m'][0]); + + $this->assertEquals( __DIR__ . '/data/config-3.yml', $sources['a']); + $this->assertEquals( __DIR__ . '/data/config-2.yml', $sources['b']); + $this->assertEquals( __DIR__ . '/data/config-1.yml', $sources['c']); + $this->assertEquals( __DIR__ . '/data/config-3.yml', $sources['m']); + } + + public function testConfiProcessorSourcesLoadInReverseOrder() + { + $processor = new ConfigProcessor(); + $loader = new YamlConfigLoader(); + $processor->extend($loader->load(__DIR__ . '/data/config-3.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-2.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-1.yml')); + + $sources = $processor->sources(); + + $data = $processor->export(); + $this->assertEquals('foo', $data['c']); + $this->assertEquals('foobar', $data['b']); + $this->assertEquals('foobarbaz', $data['a']); + + $this->assertEquals('1', $data['m'][0]); + + $this->assertEquals( __DIR__ . '/data/config-3.yml', $sources['a']); + $this->assertEquals( __DIR__ . '/data/config-2.yml', $sources['b']); + $this->assertEquals( __DIR__ . '/data/config-1.yml', $sources['c']); + $this->assertEquals( __DIR__ . '/data/config-1.yml', $sources['m']); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigTest.php new file mode 100644 index 00000000..f2ace0ce --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/ConfigTest.php @@ -0,0 +1,140 @@ +set('foo', 'bar'); + $data = $config->export(); + $this->assertEquals('{"foo":"bar"}', json_encode($data)); + } + + public function testCombine() + { + // Pointless tests just to ensure everything is covered. + $config = new Config(); + $config->set('foo', 'bar'); + $config->set('baz', 'boz'); + $config2 = new Config(); + $config2->set('foo', 'fu'); + $config2->set('new', 'blue'); + $config->combine($config2->export()); + $this->assertEquals('fu', $config->get('foo')); + $this->assertEquals('boz', $config->get('baz')); + $this->assertEquals('blue', $config->get('new')); + } + + public function testDefault() + { + $data = [ + 'a' => 'foo', + 'b' => 'bar', + 'c' => 'boz', + ]; + + $foo = ["foo" => "bar"]; + + $config = new Config($data); + + $config->setDefault('c', 'other'); + $config->setDefault('d', 'other'); + $config->setDefault('f', $foo); + + $this->assertEquals('foo', $config->get('a')); + $this->assertEquals('boz', $config->get('c')); + $this->assertEquals('other', $config->get('d')); + $this->assertEquals('other', $config->getDefault('c')); + $this->assertEquals('', $config->get('e')); + $this->assertEquals('bar', $config->get('f.foo')); + $this->assertEquals('{"foo":"bar"}', json_encode($config->get('f'))); + } + + public function testDefaultsArray() + { + $data = ['a' => 'foo', 'b' => 'bar', 'c' => 'boz',]; + $defaults = ['d' => 'foo', 'e' => 'bar', 'f' => 'boz',]; + + // Create reflection class to test private methods + $configClass = new \ReflectionClass("Consolidation\Config\Config"); + + // $defaults + $defaultsProperty = $configClass->getProperty("defaults"); + $defaultsProperty->setAccessible(true); + + // $getDefaults + $getDefaultsMethod = $configClass->getMethod("getDefaults"); + $getDefaultsMethod->setAccessible(true); + + // Test the config class + $config = new Config($data); + + // Set $config::defaults to an array to test getter and setter + $defaultsProperty->setValue($config, $defaults); + $this->assertTrue(is_array($defaultsProperty->getValue($config))); + $this->assertInstanceOf('Dflydev\DotAccessData\Data', + $getDefaultsMethod->invoke($config)); + + // Set $config::defaults to a string to test exception + $defaultsProperty->setValue($config, "foo.bar"); + $this->setExpectedException("Exception"); + $getDefaultsMethod->invoke($config); + } + + public function testConfigurationWithCrossFileReferences() + { + $config = new Config(); + $processor = new ConfigProcessor(); + $loader = new YamlConfigLoader(); + $processor->extend($loader->load(__DIR__ . '/data/config-1.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-2.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-3.yml')); + + // Does not fail if configuration file cannot be found + $processor->extend($loader->load(__DIR__ . '/data/no-such-file.yml')); + + // We must capture the sources before exporting, as export + // dumps this information. + $sources = $processor->sources(); + + $config->import($processor->export()); + + $this->assertEquals(implode(',', $config->get('m')), '3'); + $this->assertEquals($config->get('a'), 'foobarbaz'); + + $this->assertEquals($sources['a'], __DIR__ . '/data/config-3.yml'); + $this->assertEquals($sources['b'], __DIR__ . '/data/config-2.yml'); + $this->assertEquals($sources['c'], __DIR__ . '/data/config-1.yml'); + } + + public function testConfigurationWithReverseOrderCrossFileReferences() + { + $config = new Config(); + $processor = new ConfigProcessor(); + $loader = new YamlConfigLoader(); + $processor->extend($loader->load(__DIR__ . '/data/config-3.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-2.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-1.yml')); + + $sources = $processor->sources(); + $config->import($processor->export()); + + $this->assertEquals(implode(',', $config->get('m')), '1'); + + if (strpos($config->get('a'), '$') !== false) { + throw new \PHPUnit_Framework_SkippedTestError( + 'Evaluation of cross-file references in reverse order not supported.' + ); + } + $this->assertEquals($config->get('a'), 'foobarbaz'); + + $this->assertEquals($sources['a'], __DIR__ . '/data/config-3.yml'); + $this->assertEquals($sources['b'], __DIR__ . '/data/config-2.yml'); + $this->assertEquals($sources['c'], __DIR__ . '/data/config-1.yml'); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-1.yml b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-1.yml new file mode 100644 index 00000000..e8f55a9d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-1.yml @@ -0,0 +1,3 @@ +c: foo +m: + - 1 diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-2.yml b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-2.yml new file mode 100644 index 00000000..baa7e63f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-2.yml @@ -0,0 +1,3 @@ +b: ${c}bar +m: + - 2 diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-3.yml b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-3.yml new file mode 100644 index 00000000..d5895642 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/data/config-3.yml @@ -0,0 +1,3 @@ +a: ${b}baz +m: + - 3 diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/install-scenario b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/install-scenario new file mode 100755 index 00000000..d77d57d0 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/install-scenario @@ -0,0 +1,23 @@ +#!/bin/bash + +SCENARIO=$1 +ACTION=${2-install} + +dir=dependencies/${SCENARIO} +if [ -z "$SCENARIO" ] ; then + SCENARIO=default + dir=. +fi + + +if [ ! -d "$dir" ] ; then + echo "Requested scenario '${SCENARIO}' does not exist." + exit 1 +fi + +echo "Switch to ${SCENARIO} scenario" + +set -ex + +composer -n --working-dir=$dir ${ACTION} --prefer-dist --no-scripts +composer -n --working-dir=$dir info diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/prep-dependencies b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/prep-dependencies new file mode 100755 index 00000000..d1898440 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/prep-dependencies @@ -0,0 +1,66 @@ +#!/bin/bash + +# +# This script is called automatically on every `composer update`. +# See "post-update-cmd" in the "scripts" section of composer.json. +# +# This script will create a derived composer.json / composer.lock +# pair for every test scenario. Test scenarios are defined in the +# "scenarios" file, which should be customized to suit the needs +# of the project. +# + +SELF_DIRNAME="`dirname -- "$0"`" +source ${SELF_DIRNAME}/scenarios + +echo +echo "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" +echo "::" +echo ":: Update dependencies for the following scenarios:" +echo "::" +echo ":: ${SCENARIOS}" +echo "::" +echo "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" +echo + +set -ex + +for SCENARIO in ${SCENARIOS} ; do + + dir=dependencies/${SCENARIO} + + # Define indirect variable names + stability_variable="stability_${SCENARIO}" + requirement_variable="requirement_${SCENARIO}" + platform_php_variable="platform_php_${SCENARIO}" + + echo "### Create $dir/composer.json for ${SCENARIO} scenario" + mkdir -p $dir + cp composer.json $dir + + # Then set our own platform php version if applicable (otherwise unset it) + composer -n --working-dir=$dir config platform.php "${!platform_php_variable---unset}" + + # Temporarily set our vendor directory to 'vendor' + composer -n --working-dir=$dir config vendor-dir vendor + + # Set an appropriate minimum stability for this version of Symfony + composer -n --working-dir=$dir config minimum-stability "${!stability_variable-stable}" + + # Add a constraint to limit the Symfony version + composer -n --working-dir=$dir require --dev --no-update "${!requirement_variable}" + + # Create the composer.lock file. Ignore the vendor directory created. + composer -n --working-dir=$dir update --no-scripts + + # Set the vendor directory to its final desired location. + composer -n --working-dir=$dir config vendor-dir '../../vendor' + + # The 'autoload' section specifies directory paths that are relative + # to the composer.json file. We will drop in some symlinks so that + # these paths will resolve as if the composer.json were in the root. + for target in $AUTOLOAD_DIRECTORIES ; do + ln -s -f ../../$target $dir + done + +done diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/scenarios b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/scenarios new file mode 100755 index 00000000..6a8f81b2 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/scripts/scenarios @@ -0,0 +1,12 @@ +#!/bin/bash + +SCENARIOS="symfony2 symfony3 symfony4" + +AUTOLOAD_DIRECTORIES='src tests' + +platform_php_symfony2='5.4' +platform_php_symfony3='5.6' + +requirement_symfony2='symfony/console:^2.8' +requirement_symfony3='symfony/console:^3' +requirement_symfony4='symfony/console:^4' diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/ApplyConfigTestTarget.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/ApplyConfigTestTarget.php new file mode 100644 index 00000000..6dace2be --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/ApplyConfigTestTarget.php @@ -0,0 +1,43 @@ +dir = $dir; + return $this; + } + + /** + * A getter for the 'dir' property that we will use to + * determine if the setter was called. + */ + public function getDir() + { + return $this->dir; + } + + /** + * A bad setter that does not return $this. + */ + public function bad($value) + { + $this->value = $value; + } + + /** + * A getter for the bad setter. + */ + public function getBad() + { + return $this->value; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/MyFooCommand.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/MyFooCommand.php new file mode 100644 index 00000000..0487a024 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/MyFooCommand.php @@ -0,0 +1,47 @@ +setName('my:foo') + ->setDescription('My foo command.') + ->setHelp('This command tests command option injection by echoing its options') + ->addOption( + 'other', + null, + InputOption::VALUE_REQUIRED, + 'Some other option', + 'fish' + ) + ->addOption( + 'name', + null, + InputOption::VALUE_REQUIRED, + 'What is the name of the thing we are naming', + 'George' + ) + ->addOption( + 'dir', + null, + InputOption::VALUE_REQUIRED, + 'What is the base directory to use for this command', + '/default/path' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $output->writeln('Enter my:foo'); + $output->writeln('dir: ' . $input->getOption('dir')); + $output->writeln('name: ' . $input->getOption('name')); + $output->writeln('other: ' . $input->getOption('other')); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/TestLoader.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/TestLoader.php new file mode 100644 index 00000000..241e5120 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony2/tests/src/TestLoader.php @@ -0,0 +1,36 @@ +data = $data; + } + + public function setSourceName($name) + { + $this->sourceName = $name; + } + + public function export() + { + return $this->data; + } + + public function keys() + { + return array_keys($this->data); + } + + public function getSourceName() + { + return $this->sourceName; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src deleted file mode 120000 index 929cb3dc..00000000 --- a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src +++ /dev/null @@ -1 +0,0 @@ -../../src \ No newline at end of file diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Config.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Config.php new file mode 100644 index 00000000..25f714f2 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Config.php @@ -0,0 +1,157 @@ +config = new Data($data); + $this->setDefaults(new Data()); + } + + /** + * {@inheritdoc} + */ + public function has($key) + { + return ($this->config->has($key)); + } + + /** + * {@inheritdoc} + */ + public function get($key, $defaultFallback = null) + { + if ($this->has($key)) { + return $this->config->get($key); + } + return $this->getDefault($key, $defaultFallback); + } + + /** + * {@inheritdoc} + */ + public function set($key, $value) + { + $this->config->set($key, $value); + return $this; + } + + /** + * {@inheritdoc} + */ + public function import($data) + { + return $this->replace($data); + } + + /** + * {@inheritdoc} + */ + public function replace($data) + { + $this->config = new Data($data); + return $this; + } + + /** + * {@inheritdoc} + */ + public function combine($data) + { + if (!empty($data)) { + $this->config->import($data, true); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function export() + { + return $this->config->export(); + } + + /** + * {@inheritdoc} + */ + public function hasDefault($key) + { + return $this->getDefaults()->has($key); + } + + /** + * {@inheritdoc} + */ + public function getDefault($key, $defaultFallback = null) + { + return $this->hasDefault($key) ? $this->getDefaults()->get($key) : $defaultFallback; + } + + /** + * {@inheritdoc} + */ + public function setDefault($key, $value) + { + $this->getDefaults()->set($key, $value); + return $this; + } + + /** + * Return the class $defaults property and ensure it's a Data object + * TODO: remove Data object validation in 2.0 + * + * @return Data + */ + protected function getDefaults() + { + // Ensure $this->defaults is a Data object (not an array) + if (!$this->defaults instanceof Data) { + $this->setDefaults($this->defaults); + } + return $this->defaults; + } + + /** + * Sets the $defaults class parameter + * TODO: remove support for array in 2.0 as this would currently break backward compatibility + * + * @param Data|array $defaults + * + * @throws \Exception + */ + protected function setDefaults($defaults) + { + if (is_array($defaults)) { + $this->defaults = new Data($defaults); + } elseif ($defaults instanceof Data) { + $this->defaults = $defaults; + } else { + throw new \Exception("Unknown type provided for \$defaults"); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/ConfigInterface.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/ConfigInterface.php new file mode 100644 index 00000000..5124ea1f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/ConfigInterface.php @@ -0,0 +1,105 @@ + default-value + */ + public function getGlobalOptionDefaultValues(); +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Inject/ConfigForCommand.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Inject/ConfigForCommand.php new file mode 100644 index 00000000..ce2646e1 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Inject/ConfigForCommand.php @@ -0,0 +1,127 @@ +config = $config; + } + + public function setApplication(Application $application) + { + $this->application = $application; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ConsoleEvents::COMMAND => 'injectConfiguration']; + } + + /** + * Before a Console command runs, inject configuration settings + * for this command into the default value of the options of + * this command. + * + * @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event + */ + public function injectConfiguration(ConsoleCommandEvent $event) + { + $command = $event->getCommand(); + $this->injectConfigurationForGlobalOptions($event->getInput()); + $this->injectConfigurationForCommand($command, $event->getInput()); + + $targetOfHelpCommand = $this->getHelpCommandTarget($command, $event->getInput()); + if ($targetOfHelpCommand) { + $this->injectConfigurationForCommand($targetOfHelpCommand, $event->getInput()); + } + } + + protected function injectConfigurationForGlobalOptions($input) + { + if (!$this->application) { + return; + } + + $configGroup = new ConfigFallback($this->config, 'options'); + + $definition = $this->application->getDefinition(); + $options = $definition->getOptions(); + + return $this->injectConfigGroupIntoOptions($configGroup, $options, $input); + } + + protected function injectConfigurationForCommand($command, $input) + { + $commandName = $command->getName(); + $commandName = str_replace(':', '.', $commandName); + $configGroup = new ConfigFallback($this->config, $commandName, 'command.', '.options.'); + + $definition = $command->getDefinition(); + $options = $definition->getOptions(); + + return $this->injectConfigGroupIntoOptions($configGroup, $options, $input); + } + + protected function injectConfigGroupIntoOptions($configGroup, $options, $input) + { + foreach ($options as $option => $inputOption) { + $key = str_replace('.', '-', $option); + $value = $configGroup->get($key); + if ($value !== null) { + if (is_bool($value) && ($value == true)) { + $input->setOption($key, $value); + } elseif ($inputOption->acceptValue()) { + $inputOption->setDefault($value); + } + } + } + } + + protected function getHelpCommandTarget($command, $input) + { + if (($command->getName() != 'help') || (!isset($this->application))) { + return false; + } + + $this->fixInputForSymfony2($command, $input); + + // Symfony Console helpfully swaps 'command_name' and 'command' + // depending on whether the user entered `help foo` or `--help foo`. + // One of these is always `help`, and the other is the command we + // are actually interested in. + $nameOfCommandToDescribe = $input->getArgument('command_name'); + if ($nameOfCommandToDescribe == 'help') { + $nameOfCommandToDescribe = $input->getArgument('command'); + } + return $this->application->find($nameOfCommandToDescribe); + } + + protected function fixInputForSymfony2($command, $input) + { + // Symfony 3.x prepares $input for us; Symfony 2.x, on the other + // hand, passes it in prior to binding with the command definition, + // so we have to go to a little extra work. It may be inadvisable + // to do these steps for commands other than 'help'. + if (!$input->hasArgument('command_name')) { + $command->ignoreValidationErrors(); + $command->mergeApplicationDefinition(); + $input->bind($command->getDefinition()); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Inject/ConfigForSetters.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Inject/ConfigForSetters.php new file mode 100644 index 00000000..5ec87042 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Inject/ConfigForSetters.php @@ -0,0 +1,47 @@ +config = new ConfigMerge($config, $group, $prefix, $postfix); + } + + public function apply($object, $configurationKey) + { + $settings = $this->config->get($configurationKey); + foreach ($settings as $setterMethod => $args) { + $fn = [$object, $setterMethod]; + if (is_callable($fn)) { + $result = call_user_func_array($fn, (array)$args); + + // We require that $fn must only be used with setter methods. + // Setter methods are required to always return $this so that + // they may be chained. We will therefore throw an exception + // for any setter that returns something else. + if ($result != $object) { + $methodDescription = get_class($object) . "::$setterMethod"; + $propertyDescription = $this->config->describe($configurationKey); + throw new \Exception("$methodDescription did not return '\$this' when processing $propertyDescription."); + } + } + } + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigLoader.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigLoader.php new file mode 100644 index 00000000..ecc6f64f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigLoader.php @@ -0,0 +1,35 @@ +source; + } + + protected function setSourceName($source) + { + $this->source = $source; + return $this; + } + + public function export() + { + return $this->config; + } + + public function keys() + { + return array_keys($this->config); + } + + abstract public function load($path); +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigLoaderInterface.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigLoaderInterface.php new file mode 100644 index 00000000..9b155c1b --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/ConfigLoaderInterface.php @@ -0,0 +1,29 @@ +expander = $expander ?: new Expander(); + } + + /** + * Extend the configuration to be processed with the + * configuration provided by the specified loader. + * + * @param ConfigLoaderInterface $loader + */ + public function extend(ConfigLoaderInterface $loader) + { + return $this->addFromSource($loader->export(), $loader->getSourceName()); + } + + /** + * Extend the configuration to be processed with + * the provided nested array. + * + * @param array $data + */ + public function add($data) + { + $this->unprocessedConfig[] = $data; + return $this; + } + + /** + * Extend the configuration to be processed with + * the provided nested array. Also record the name + * of the data source, if applicable. + * + * @param array $data + * @param string $source + */ + protected function addFromSource($data, $source = '') + { + if (empty($source)) { + return $this->add($data); + } + $this->unprocessedConfig[$source] = $data; + return $this; + } + + /** + * Process all of the configuration that has been collected, + * and return a nested array. + * + * @return array + */ + public function export($referenceArray = []) + { + if (!empty($this->unprocessedConfig)) { + $this->processedConfig = $this->process( + $this->processedConfig, + $this->fetchUnprocessed(), + $referenceArray + ); + } + return $this->processedConfig; + } + + /** + * To aid in debugging: return the source of each configuration item. + * n.b. Must call this function *before* export and save the result + * if persistence is desired. + */ + public function sources() + { + $sources = []; + foreach ($this->unprocessedConfig as $sourceName => $config) { + if (!empty($sourceName)) { + $configSources = ArrayUtil::fillRecursive($config, $sourceName); + $sources = ArrayUtil::mergeRecursiveDistinct($sources, $configSources); + } + } + return $sources; + } + + /** + * Get the configuration to be processed, and clear out the + * 'unprocessed' list. + * + * @return array + */ + protected function fetchUnprocessed() + { + $toBeProcessed = $this->unprocessedConfig; + $this->unprocessedConfig = []; + return $toBeProcessed; + } + + /** + * Use a map-reduce to evaluate the items to be processed, + * and merge them into the processed array. + * + * @param array $processed + * @param array $toBeProcessed + * @return array + */ + protected function process(array $processed, array $toBeProcessed, $referenceArray = []) + { + $toBeReduced = array_map([$this, 'preprocess'], $toBeProcessed); + $reduced = array_reduce($toBeReduced, [$this, 'reduceOne'], $processed); + return $this->evaluate($reduced, $referenceArray); + } + + /** + * Process a single configuration file from the 'to be processed' + * list. By default this is a no-op. Override this method to + * provide any desired configuration preprocessing, e.g. dot-notation + * expansion of the configuration keys, etc. + * + * @param array $config + * @return array + */ + protected function preprocess(array $config) + { + return $config; + } + + /** + * Evaluate one item in the 'to be evaluated' list, and then + * merge it into the processed configuration (the 'carry'). + * + * @param array $processed + * @param array $config + * @return array + */ + protected function reduceOne(array $processed, array $config) + { + return ArrayUtil::mergeRecursiveDistinct($processed, $config); + } + + /** + * Evaluate one configuration item. + * + * @param array $processed + * @param array $config + * @return array + */ + protected function evaluate(array $config, $referenceArray = []) + { + return $this->expander->expandArrayProperties( + $config, + $referenceArray + ); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/YamlConfigLoader.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/YamlConfigLoader.php new file mode 100644 index 00000000..45705662 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Loader/YamlConfigLoader.php @@ -0,0 +1,26 @@ +setSourceName($path); + + // We silently skip any nonexistent config files, so that + // clients may simply `load` all of their candidates. + if (!file_exists($path)) { + $this->config = []; + return $this; + } + $this->config = (array) Yaml::parse(file_get_contents($path)); + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ArrayUtil.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ArrayUtil.php new file mode 100644 index 00000000..a23f854e --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ArrayUtil.php @@ -0,0 +1,75 @@ + &$value) { + $merged[$key] = self::mergeRecursiveValue($merged, $key, $value); + } + return $merged; + } + + /** + * Process the value in an mergeRecursiveDistinct - make a recursive + * call if needed. + */ + protected static function mergeRecursiveValue(&$merged, $key, $value) + { + if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { + return self::mergeRecursiveDistinct($merged[$key], $value); + } + return $value; + } + + /** + * Fills all of the leaf-node values of a nested array with the + * provided replacement value. + */ + public static function fillRecursive(array $data, $fill) + { + $result = []; + foreach ($data as $key => $value) { + $result[$key] = $fill; + if (self::isAssociative($value)) { + $result[$key] = self::fillRecursive($value, $fill); + } + } + return $result; + } + + /** + * Return true if the provided parameter is an array, and at least + * one key is non-numeric. + */ + public static function isAssociative($testArray) + { + if (!is_array($testArray)) { + return false; + } + foreach (array_keys($testArray) as $key) { + if (!is_numeric($key)) { + return true; + } + } + return false; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigFallback.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigFallback.php new file mode 100644 index 00000000..9f9972f6 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigFallback.php @@ -0,0 +1,51 @@ +getWithFallback($key, $this->group, $this->prefix, $this->postfix); + } + + /** + * Fetch an option value from a given key, or, if that specific key does + * not contain a value, then consult various fallback options until a + * value is found. + * + */ + protected function getWithFallback($key, $group, $prefix = '', $postfix = '.') + { + $configKey = "{$prefix}{$group}${postfix}{$key}"; + if ($this->config->has($configKey)) { + return $this->config->get($configKey); + } + if ($this->config->hasDefault($configKey)) { + return $this->config->getDefault($configKey); + } + $moreGeneralGroupname = $this->moreGeneralGroupName($group); + if ($moreGeneralGroupname) { + return $this->getWithFallback($key, $moreGeneralGroupname, $prefix, $postfix); + } + return null; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigGroup.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigGroup.php new file mode 100644 index 00000000..24b29dd8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigGroup.php @@ -0,0 +1,61 @@ +config = $config; + $this->group = $group; + $this->prefix = $prefix; + $this->postfix = $postfix; + } + + /** + * Return a description of the configuration group (with prefix and postfix). + */ + public function describe($property) + { + return $this->prefix . $this->group . $this->postfix . $property; + } + + /** + * Get the requested configuration key from the most specific configuration + * group that contains it. + */ + abstract public function get($key); + + /** + * Given a group name, such as "foo.bar.baz", return the next configuration + * group in the fallback hierarchy, e.g. "foo.bar". + */ + protected function moreGeneralGroupName($group) + { + $result = preg_replace('#\.[^.]*$#', '', $group); + if ($result != $group) { + return $result; + } + return false; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigMerge.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigMerge.php new file mode 100644 index 00000000..65fccf72 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigMerge.php @@ -0,0 +1,34 @@ +getWithMerge($key, $this->group, $this->prefix, $this->postfix); + } + + /** + * Merge available configuration from each configuration group. + */ + public function getWithMerge($key, $group, $prefix = '', $postfix = '.') + { + $configKey = "{$prefix}{$group}${postfix}{$key}"; + $result = $this->config->get($configKey, []); + if (!is_array($result)) { + throw new \UnexpectedValueException($configKey . ' must be a list of settings to apply.'); + } + $moreGeneralGroupname = $this->moreGeneralGroupName($group); + if ($moreGeneralGroupname) { + $result += $this->getWithMerge($key, $moreGeneralGroupname, $prefix, $postfix); + } + return $result; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigOverlay.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigOverlay.php new file mode 100644 index 00000000..d1f12697 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/ConfigOverlay.php @@ -0,0 +1,203 @@ +contexts[self::DEFAULT_CONTEXT] = new Config(); + $this->contexts[self::PROCESS_CONTEXT] = new Config(); + } + + /** + * Add a named configuration object to the configuration overlay. + * Configuration objects added LAST have HIGHEST priority, with the + * exception of the fact that the process context always has the + * highest priority. + * + * If a context has already been added, its priority will not change. + */ + public function addContext($name, ConfigInterface $config) + { + $process = $this->contexts[self::PROCESS_CONTEXT]; + unset($this->contexts[self::PROCESS_CONTEXT]); + $this->contexts[$name] = $config; + $this->contexts[self::PROCESS_CONTEXT] = $process; + + return $this; + } + + /** + * Add a placeholder context that will be prioritized higher than + * existing contexts. This is done to ensure that contexts added + * later will maintain a higher priority if the placeholder context + * is later relaced with a different configuration set via addContext(). + * + * @param string $name + * @return $this + */ + public function addPlaceholder($name) + { + return $this->addContext($name, new Config()); + } + + /** + * Increase the priority of the named context such that it is higher + * in priority than any existing context except for the 'process' + * context. + * + * @param string $name + * @return $this + */ + public function increasePriority($name) + { + $config = $this->getContext($name); + unset($this->contexts[$name]); + return $this->addContext($name, $config); + } + + public function hasContext($name) + { + return isset($this->contexts[$name]); + } + + public function getContext($name) + { + if ($this->hasContext($name)) { + return $this->contexts[$name]; + } + return new Config(); + } + + public function removeContext($name) + { + unset($this->contexts[$name]); + } + + /** + * Determine if a non-default config value exists. + */ + public function findContext($key) + { + foreach (array_reverse($this->contexts) as $name => $config) { + if ($config->has($key)) { + return $config; + } + } + return false; + } + + /** + * @inheritdoc + */ + public function has($key) + { + return $this->findContext($key) != false; + } + + /** + * @inheritdoc + */ + public function get($key, $default = null) + { + $context = $this->findContext($key); + if ($context) { + return $context->get($key, $default); + } + return $default; + } + + /** + * @inheritdoc + */ + public function set($key, $value) + { + $this->contexts[self::PROCESS_CONTEXT]->set($key, $value); + return $this; + } + + /** + * @inheritdoc + */ + public function import($data) + { + $this->unsupported(__FUNCTION__); + } + + /** + * @inheritdoc + */ + public function replace($data) + { + $this->unsupported(__FUNCTION__); + } + + /** + * @inheritdoc + */ + public function combine($data) + { + $this->unsupported(__FUNCTION__); + } + + /** + * @inheritdoc + */ + protected function unsupported($fn) + { + throw new \Exception("The method '$fn' is not supported for the ConfigOverlay class."); + } + + /** + * @inheritdoc + */ + public function export() + { + $export = []; + foreach ($this->contexts as $name => $config) { + $export = array_merge_recursive($export, $config->export()); + } + return $export; + } + + /** + * @inheritdoc + */ + public function hasDefault($key) + { + return $this->contexts[self::DEFAULT_CONTEXT]->has($key); + } + + /** + * @inheritdoc + */ + public function getDefault($key, $default = null) + { + return $this->contexts[self::DEFAULT_CONTEXT]->get($key, $default); + } + + /** + * @inheritdoc + */ + public function setDefault($key, $value) + { + $this->contexts[self::DEFAULT_CONTEXT]->set($key, $value); + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/EnvConfig.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/EnvConfig.php new file mode 100644 index 00000000..05f8d2a8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/src/Util/EnvConfig.php @@ -0,0 +1,96 @@ +prefix = strtoupper(rtrim($prefix, '_')) . '_'; + } + + /** + * @inheritdoc + */ + public function has($key) + { + return $this->get($key) !== null; + } + + /** + * @inheritdoc + */ + public function get($key, $defaultFallback = null) + { + $envKey = $this->prefix . strtoupper(strtr($key, '.-', '__')); + $envKey = str_replace($this->prefix . $this->prefix, $this->prefix, $envKey); + return getenv($envKey) ?: $defaultFallback; + } + + /** + * @inheritdoc + */ + public function set($key, $value) + { + throw new \Exception('Cannot call "set" on environmental configuration.'); + } + + /** + * @inheritdoc + */ + public function import($data) + { + // no-op + } + + /** + * @inheritdoc + */ + public function export() + { + return []; + } + + /** + * @inheritdoc + */ + public function hasDefault($key) + { + return false; + } + + /** + * @inheritdoc + */ + public function getDefault($key, $defaultFallback = null) + { + return $defaultFallback; + } + + /** + * @inheritdoc + */ + public function setDefault($key, $value) + { + throw new \Exception('Cannot call "setDefault" on environmental configuration.'); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests deleted file mode 120000 index c2ebfe53..00000000 --- a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests +++ /dev/null @@ -1 +0,0 @@ -../../tests \ No newline at end of file diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigForCommandTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigForCommandTest.php new file mode 100644 index 00000000..41da3076 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigForCommandTest.php @@ -0,0 +1,130 @@ + [ + 'global' => 'from-config', + ], + // Define some configuration settings for the options for + // the commands my:foo and my:bar. + 'command' => [ + 'my' => [ + // commands.my.options.* apply to all my:* commands. + 'options' => [ + 'dir' => '/etc/common', + 'priority' => 'normal', + ], + 'foo' => [ + // commands.my.foo.options.* apply only to the my:foo command. + 'options' => [ + 'name' => 'baz', + ], + ], + ], + ], + ]; + + $this->config = new Config($data); + } + + public function testInjection() + { + $command = new MyFooCommand(); + $input = new StringInput('my:foo'); + + list($status, $output) = $this->runCommandViaApplication($command, $input); + + $expectedOutput = <<< EOT +Enter my:foo +dir: /etc/common +name: baz +other: fish +EOT; + + $this->assertEquals(0, $status); + $this->assertEquals($expectedOutput, $output); + } + + public function testInjectionWithOverride() + { + $command = new MyFooCommand(); + $input = new StringInput('my:foo --name=Fred'); + + list($status, $output) = $this->runCommandViaApplication($command, $input); + + $expectedOutput = <<< EOT +Enter my:foo +dir: /etc/common +name: Fred +other: fish +EOT; + + $this->assertEquals(0, $status); + $this->assertEquals($expectedOutput, $output); + } + + public function testHelpDefaultInjection() + { + $command = new MyFooCommand(); + $input = new StringInput('help my:foo'); + + list($status, $output) = $this->runCommandViaApplication($command, $input); + + $expectedOutput = <<< EOT +What is the name of the thing we are naming [default: "baz"] +EOT; + + $this->assertEquals(0, $status); + $this->assertContains($expectedOutput, $output); + + $expectedOutput = <<< EOT +A certain global option. [default: "from-config"] +EOT; + + $this->assertContains($expectedOutput, $output); + } + + protected function runCommandViaApplication($command, $input) + { + $application = new Application('TestApplication', '0.0.0'); + $application->getDefinition() + ->addOption( + new InputOption('--global', null, InputOption::VALUE_REQUIRED, 'A certain global option.', 'hardcoded') + ); + + $output = new BufferedOutput(); + + $configInjector = new ConfigForCommand($this->config); + $configInjector->setApplication($application); + + $eventDispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher(); + $eventDispatcher->addSubscriber($configInjector); + $application->setDispatcher($eventDispatcher); + + $application->setAutoExit(false); + $application->add($command); + + $statusCode = $application->run($input, $output); + $commandOutput = trim($output->fetch()); + + return [$statusCode, $commandOutput]; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigForSettersTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigForSettersTest.php new file mode 100644 index 00000000..422b0a00 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigForSettersTest.php @@ -0,0 +1,87 @@ + [ + 'Operations' => [ + // task.Operations.settings apply to all tasks in + // any *.Tass.Operations namespace. + 'settings' => [ + 'dir' => '/base/dir', + ], + 'Frobulate' => [ + // task.Operations.Frobulate.settings applies only + // the Frobulate task. + 'settings' => [ + 'dir' => '/override/dir', + ], + ], + ], + ], + ]; + $config = new Config($data); + + $applicator = new ConfigForSetters($config, 'Operations.Frobulate', 'task.'); + + $testTarget = new ApplyConfigTestTarget(); + + $applicator->apply($testTarget, 'settings'); + + $this->assertEquals('/override/dir', $testTarget->getDir()); + $this->assertEquals(null, $testTarget->getBad()); + } + + public function testApplyBadConfig() + { + $data = [ + // Define some configuration settings for the configuration + // of some task \My\Tasks\Operations\Frobulate. + 'task' => [ + 'Operations' => [ + // task.Operations.settings apply to all tasks in + // any *.Tass.Operations namespace. + 'settings' => [ + 'dir' => '/base/dir', + ], + 'Frobulate' => [ + // task.Operations.Frobulate.settings applies only + // the Frobulate task. + 'settings' => [ + 'bad' => 'fire truck', + ], + ], + ], + ], + ]; + $config = new Config($data); + + $applicator = new ConfigForSetters($config, 'Operations.Frobulate', 'task.'); + + $testTarget = new ApplyConfigTestTarget(); + + $exceptionMessage = ''; + try + { + $applicator->apply($testTarget, 'settings'); + } + catch (\Exception $e) + { + $exceptionMessage = $e->getMessage(); + } + // We would prefer it if bad methods were never called; unfortunately, + // declaring the return type of a method cannot be done in a reliable + // way (via reflection) until php 7, so we allow these methods to be + // called for now. + $this->assertEquals('fire truck', $testTarget->getBad()); + $this->assertEquals('Consolidation\\TestUtils\\ApplyConfigTestTarget::bad did not return \'$this\' when processing task.Operations.Frobulate.settings.', $exceptionMessage); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigGroupTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigGroupTest.php new file mode 100644 index 00000000..21e470e5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigGroupTest.php @@ -0,0 +1,91 @@ + [ + 'my' => [ + // commands.my.options.* apply to all my:* commands. + 'options' => [ + 'path' => '/etc/common', + 'priority' => 'normal', + ], + 'foo' => [ + // commands.my.foo.options.* apply only to the my:foo command. + 'options' => [ + 'name' => 'baz', + ], + ], + 'bar' => [ + // Similarly, commands.my.bar.options is for the my:bar command. + 'options' => [ + 'priority' => 'high', + ], + ], + ], + ], + // Define some configuration settings for the configuration + // of some task \My\Tasks\Operations\Frobulate. + 'task' => [ + 'Operations' => [ + // task.Operations.settings apply to all tasks in + // any *.Tass.Operations namespace. + 'settings' => [ + 'dir' => '/base/dir', + ], + 'Frobulate' => [ + // task.Operations.Frobulate.settings applies only + // the Frobulate task. + 'settings' => [ + 'object' => 'fire truck', + ], + ], + ], + ], + ]; + + $this->config = new Config($data); + } + + public function testDotNotation() + { + // Test the test + $this->assertEquals('baz', $this->config->get('command.my.foo.options.name')); + } + + public function testFallback() + { + $fooFallback = new ConfigFallback($this->config, 'my.foo', 'command.', '.options.'); + $barFallback = new ConfigFallback($this->config, 'my.bar', 'command.', '.options.'); + + $this->assertEquals(null, $barFallback->get('name')); + $this->assertEquals('baz', $fooFallback->get('name')); + $this->assertEquals('high', $barFallback->get('priority')); + + $this->assertEquals('normal', $fooFallback->get('priority')); + $this->assertEquals('/etc/common', $barFallback->get('path')); + $this->assertEquals('/etc/common', $fooFallback->get('path')); + } + + public function testMerge() + { + $frobulateMerge = new ConfigMerge($this->config, 'Operations.Frobulate', 'task.'); + + $settings = $frobulateMerge->get('settings'); + $this->assertEquals('fire truck', $settings['object']); + $this->assertEquals('/base/dir', $settings['dir']); + $keys = array_keys($settings); + sort($keys); + $this->assertEquals('dir,object', implode(',', $keys)); + } +} + diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigLoaderTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigLoaderTest.php new file mode 100644 index 00000000..6dedb1f3 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigLoaderTest.php @@ -0,0 +1,29 @@ +assertTrue(file_exists($path)); + + $loader->load($path); + + $configFile = basename($loader->getSourceName()); + $this->assertEquals('config-1.yml', $configFile); + + // Make sure that the data we loaded contained the expected keys + $keys = $loader->keys(); + sort($keys); + $keysString = implode(',', $keys); + $this->assertEquals('c,m', $keysString); + + $configData = $loader->export(); + $this->assertEquals('foo', $configData['c']); + $this->assertEquals('1', $configData['m'][0]); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigOverlayTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigOverlayTest.php new file mode 100644 index 00000000..f7faf748 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigOverlayTest.php @@ -0,0 +1,168 @@ +import([ + 'hidden-by-a' => 'alias hidden-by-a', + 'hidden-by-process' => 'alias hidden-by-process', + 'options' =>[ + 'a-a' => 'alias-a', + ], + 'command' => [ + 'foo' => [ + 'bar' => [ + 'command' => [ + 'options' => [ + 'a-b' => 'alias-b', + ], + ], + ], + ], + ], + ]); + + $configFileContext = new Config(); + $configFileContext->import([ + 'hidden-by-cf' => 'config-file hidden-by-cf', + 'hidden-by-a' => 'config-file hidden-by-a', + 'hidden-by-process' => 'config-file hidden-by-process', + 'options' =>[ + 'cf-a' => 'config-file-a', + ], + 'command' => [ + 'foo' => [ + 'bar' => [ + 'command' => [ + 'options' => [ + 'cf-b' => 'config-file-b', + ], + ], + ], + ], + ], + ]); + + $this->overlay = new ConfigOverlay(); + $this->overlay->set('hidden-by-process', 'process-h'); + $this->overlay->addContext('cf', $configFileContext); + $this->overlay->addContext('a', $aliasContext); + $this->overlay->setDefault('df-a', 'default'); + $this->overlay->setDefault('hidden-by-a', 'default hidden-by-a'); + $this->overlay->setDefault('hidden-by-cf', 'default hidden-by-cf'); + $this->overlay->setDefault('hidden-by-process', 'default hidden-by-process'); + } + + public function testGetPriority() + { + $this->assertEquals('process-h', $this->overlay->get('hidden-by-process')); + $this->assertEquals('config-file hidden-by-cf', $this->overlay->get('hidden-by-cf')); + $this->assertEquals('alias hidden-by-a', $this->overlay->get('hidden-by-a')); + } + + public function testDefault() + { + $this->assertEquals('alias-a', $this->overlay->get('options.a-a')); + $this->assertEquals('alias-a', $this->overlay->get('options.a-a', 'ignored')); + $this->assertEquals('default', $this->overlay->getDefault('df-a', 'ignored')); + $this->assertEquals('nsv', $this->overlay->getDefault('a-a', 'nsv')); + + $this->overlay->setDefault('df-a', 'new value'); + $this->assertEquals('new value', $this->overlay->getDefault('df-a', 'ignored')); + } + + public function testExport() + { + $data = $this->overlay->export(); + + $this->assertEquals('config-file-a', $data['options']['cf-a']); + $this->assertEquals('alias-a', $data['options']['a-a']); + } + + /** + * @expectedException Exception + */ + public function testImport() + { + $data = $this->overlay->import(['a' => 'value']); + } + + public function testMaintainPriority() + { + // Get and re-add the 'cf' context. Its priority should not change. + $configFileContext = $this->overlay->getContext('cf'); + $this->overlay->addContext('cf', $configFileContext); + + // These asserts are the same as in testGetPriority + $this->assertEquals('process-h', $this->overlay->get('hidden-by-process')); + $this->assertEquals('config-file hidden-by-cf', $this->overlay->get('hidden-by-cf')); + $this->assertEquals('alias hidden-by-a', $this->overlay->get('hidden-by-a')); + } + + public function testChangePriority() + { + // Increase the priority of the 'cf' context. Now, it should have a higher + // priority than the 'alias' context, but should still have a lower + // priority than the 'process' context. + $this->overlay->increasePriority('cf'); + + // These asserts are the same as in testGetPriority + $this->assertEquals('process-h', $this->overlay->get('hidden-by-process')); + $this->assertEquals('config-file hidden-by-cf', $this->overlay->get('hidden-by-cf')); + + // This one has changed: the config-file value is now found instead + // of the alias value. + $this->assertEquals('config-file hidden-by-a', $this->overlay->get('hidden-by-a')); + } + + public function testPlaceholder() + { + $this->overlay->addPlaceholder('lower'); + + $higherContext = new Config(); + $higherContext->import(['priority-test' => 'higher']); + + $lowerContext = new Config(); + $lowerContext->import(['priority-test' => 'lower']); + + // Usually 'lower' would have the highest priority, since it is + // added last. However, our earlier call to 'addPlaceholder' reserves + // a spot for it, so the 'higher' context will end up with a higher + // priority. + $this->overlay->addContext('higher', $higherContext); + $this->overlay->addContext('lower', $lowerContext); + $this->assertEquals('higher', $this->overlay->get('priority-test', 'neither')); + + // Test to see that we can change the value of the 'higher' context, + // and the change will be reflected in the overlay. + $higherContext->set('priority-test', 'changed'); + $this->assertEquals('changed', $this->overlay->get('priority-test', 'neither')); + + // Test to see that the 'process' context still has the highest priority. + $this->overlay->set('priority-test', 'process'); + $higherContext->set('priority-test', 'ignored'); + $this->assertEquals('process', $this->overlay->get('priority-test', 'neither')); + } + + public function testDoesNotHave() + { + $context = $this->overlay->getContext('no-such-context'); + $data = $context->export(); + $this->assertEquals('[]', json_encode($data)); + + $this->assertTrue(!$this->overlay->has('no-such-key')); + $this->assertTrue(!$this->overlay->hasDefault('no-such-default')); + + $this->assertEquals('no-such-value', $this->overlay->get('no-such-key', 'no-such-value')); + + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigProcessorTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigProcessorTest.php new file mode 100644 index 00000000..ac645a28 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigProcessorTest.php @@ -0,0 +1,152 @@ + 'foo', + 'm' => [1], + ]; + $config2 = [ + 'b' => '${c}bar', + 'm' => [2], + ]; + $config3 = [ + 'a' => '${b}baz', + 'm' => [3], + ]; + + $processor = new ConfigProcessor(); + $processor->add($config1); + $processor->add($config2); + $processor->add($config3); + + $data = $processor->export(); + $this->assertEquals('foo', $data['c']); + $this->assertEquals('foobar', $data['b']); + $this->assertEquals('foobarbaz', $data['a']); + } + + public function processorForConfigMergeTest($provideSourceNames) + { + $config1 = [ + 'm' => [ + 'x' => 'x-1', + 'y' => [ + 'r' => 'r-1', + 's' => 's-1', + 't' => 't-1', + ], + 'z' => 'z-1', + ], + ]; + $config2 = [ + 'm' => [ + 'w' => 'w-2', + 'y' => [ + 'q' => 'q-2', + 's' => 's-2', + ], + 'z' => 'z-2', + ], + ]; + $config3 = [ + 'm' => [ + 'v' => 'v-3', + 'y' => [ + 't' => 't-3', + 'u' => 'u-3', + ], + 'z' => 'z-3', + ], + ]; + + $processor = new ConfigProcessor(); + $testLoader = new TestLoader(); + + $testLoader->set($config1); + $testLoader->setSourceName($provideSourceNames ? 'c-1' : ''); + $processor->extend($testLoader); + + $testLoader->set($config2); + $testLoader->setSourceName($provideSourceNames ? 'c-2' : ''); + $processor->extend($testLoader); + + $testLoader->set($config3); + $testLoader->setSourceName($provideSourceNames ? 'c-3' : ''); + $processor->extend($testLoader); + + return $processor; + } + + public function testConfigProcessorMergeAssociative() + { + $processor = $this->processorForConfigMergeTest(false); + $data = $processor->export(); + $this->assertEquals('{"m":{"x":"x-1","y":{"r":"r-1","s":"s-2","t":"t-3","q":"q-2","u":"u-3"},"z":"z-3","w":"w-2","v":"v-3"}}', json_encode($data)); + } + + public function testConfigProcessorMergeAssociativeWithSourceNames() + { + $processor = $this->processorForConfigMergeTest(true); + $sources = $processor->sources(); + $data = $processor->export(); + $this->assertEquals('{"m":{"x":"x-1","y":{"r":"r-1","s":"s-2","t":"t-3","q":"q-2","u":"u-3"},"z":"z-3","w":"w-2","v":"v-3"}}', json_encode($data)); + $this->assertEquals('c-1', $sources['m']['x']); + $this->assertEquals('c-1', $sources['m']['y']['r']); + $this->assertEquals('c-2', $sources['m']['w']); + $this->assertEquals('c-2', $sources['m']['y']['s']); + $this->assertEquals('c-3', $sources['m']['z']); + $this->assertEquals('c-3', $sources['m']['y']['u']); + } + + public function testConfiProcessorSources() + { + $processor = new ConfigProcessor(); + $loader = new YamlConfigLoader(); + $processor->extend($loader->load(__DIR__ . '/data/config-1.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-2.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-3.yml')); + + $sources = $processor->sources(); + + $data = $processor->export(); + $this->assertEquals('foo', $data['c']); + $this->assertEquals('foobar', $data['b']); + $this->assertEquals('foobarbaz', $data['a']); + + $this->assertEquals('3', $data['m'][0]); + + $this->assertEquals( __DIR__ . '/data/config-3.yml', $sources['a']); + $this->assertEquals( __DIR__ . '/data/config-2.yml', $sources['b']); + $this->assertEquals( __DIR__ . '/data/config-1.yml', $sources['c']); + $this->assertEquals( __DIR__ . '/data/config-3.yml', $sources['m']); + } + + public function testConfiProcessorSourcesLoadInReverseOrder() + { + $processor = new ConfigProcessor(); + $loader = new YamlConfigLoader(); + $processor->extend($loader->load(__DIR__ . '/data/config-3.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-2.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-1.yml')); + + $sources = $processor->sources(); + + $data = $processor->export(); + $this->assertEquals('foo', $data['c']); + $this->assertEquals('foobar', $data['b']); + $this->assertEquals('foobarbaz', $data['a']); + + $this->assertEquals('1', $data['m'][0]); + + $this->assertEquals( __DIR__ . '/data/config-3.yml', $sources['a']); + $this->assertEquals( __DIR__ . '/data/config-2.yml', $sources['b']); + $this->assertEquals( __DIR__ . '/data/config-1.yml', $sources['c']); + $this->assertEquals( __DIR__ . '/data/config-1.yml', $sources['m']); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigTest.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigTest.php new file mode 100644 index 00000000..f2ace0ce --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/ConfigTest.php @@ -0,0 +1,140 @@ +set('foo', 'bar'); + $data = $config->export(); + $this->assertEquals('{"foo":"bar"}', json_encode($data)); + } + + public function testCombine() + { + // Pointless tests just to ensure everything is covered. + $config = new Config(); + $config->set('foo', 'bar'); + $config->set('baz', 'boz'); + $config2 = new Config(); + $config2->set('foo', 'fu'); + $config2->set('new', 'blue'); + $config->combine($config2->export()); + $this->assertEquals('fu', $config->get('foo')); + $this->assertEquals('boz', $config->get('baz')); + $this->assertEquals('blue', $config->get('new')); + } + + public function testDefault() + { + $data = [ + 'a' => 'foo', + 'b' => 'bar', + 'c' => 'boz', + ]; + + $foo = ["foo" => "bar"]; + + $config = new Config($data); + + $config->setDefault('c', 'other'); + $config->setDefault('d', 'other'); + $config->setDefault('f', $foo); + + $this->assertEquals('foo', $config->get('a')); + $this->assertEquals('boz', $config->get('c')); + $this->assertEquals('other', $config->get('d')); + $this->assertEquals('other', $config->getDefault('c')); + $this->assertEquals('', $config->get('e')); + $this->assertEquals('bar', $config->get('f.foo')); + $this->assertEquals('{"foo":"bar"}', json_encode($config->get('f'))); + } + + public function testDefaultsArray() + { + $data = ['a' => 'foo', 'b' => 'bar', 'c' => 'boz',]; + $defaults = ['d' => 'foo', 'e' => 'bar', 'f' => 'boz',]; + + // Create reflection class to test private methods + $configClass = new \ReflectionClass("Consolidation\Config\Config"); + + // $defaults + $defaultsProperty = $configClass->getProperty("defaults"); + $defaultsProperty->setAccessible(true); + + // $getDefaults + $getDefaultsMethod = $configClass->getMethod("getDefaults"); + $getDefaultsMethod->setAccessible(true); + + // Test the config class + $config = new Config($data); + + // Set $config::defaults to an array to test getter and setter + $defaultsProperty->setValue($config, $defaults); + $this->assertTrue(is_array($defaultsProperty->getValue($config))); + $this->assertInstanceOf('Dflydev\DotAccessData\Data', + $getDefaultsMethod->invoke($config)); + + // Set $config::defaults to a string to test exception + $defaultsProperty->setValue($config, "foo.bar"); + $this->setExpectedException("Exception"); + $getDefaultsMethod->invoke($config); + } + + public function testConfigurationWithCrossFileReferences() + { + $config = new Config(); + $processor = new ConfigProcessor(); + $loader = new YamlConfigLoader(); + $processor->extend($loader->load(__DIR__ . '/data/config-1.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-2.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-3.yml')); + + // Does not fail if configuration file cannot be found + $processor->extend($loader->load(__DIR__ . '/data/no-such-file.yml')); + + // We must capture the sources before exporting, as export + // dumps this information. + $sources = $processor->sources(); + + $config->import($processor->export()); + + $this->assertEquals(implode(',', $config->get('m')), '3'); + $this->assertEquals($config->get('a'), 'foobarbaz'); + + $this->assertEquals($sources['a'], __DIR__ . '/data/config-3.yml'); + $this->assertEquals($sources['b'], __DIR__ . '/data/config-2.yml'); + $this->assertEquals($sources['c'], __DIR__ . '/data/config-1.yml'); + } + + public function testConfigurationWithReverseOrderCrossFileReferences() + { + $config = new Config(); + $processor = new ConfigProcessor(); + $loader = new YamlConfigLoader(); + $processor->extend($loader->load(__DIR__ . '/data/config-3.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-2.yml')); + $processor->extend($loader->load(__DIR__ . '/data/config-1.yml')); + + $sources = $processor->sources(); + $config->import($processor->export()); + + $this->assertEquals(implode(',', $config->get('m')), '1'); + + if (strpos($config->get('a'), '$') !== false) { + throw new \PHPUnit_Framework_SkippedTestError( + 'Evaluation of cross-file references in reverse order not supported.' + ); + } + $this->assertEquals($config->get('a'), 'foobarbaz'); + + $this->assertEquals($sources['a'], __DIR__ . '/data/config-3.yml'); + $this->assertEquals($sources['b'], __DIR__ . '/data/config-2.yml'); + $this->assertEquals($sources['c'], __DIR__ . '/data/config-1.yml'); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-1.yml b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-1.yml new file mode 100644 index 00000000..e8f55a9d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-1.yml @@ -0,0 +1,3 @@ +c: foo +m: + - 1 diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-2.yml b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-2.yml new file mode 100644 index 00000000..baa7e63f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-2.yml @@ -0,0 +1,3 @@ +b: ${c}bar +m: + - 2 diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-3.yml b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-3.yml new file mode 100644 index 00000000..d5895642 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/data/config-3.yml @@ -0,0 +1,3 @@ +a: ${b}baz +m: + - 3 diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/install-scenario b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/install-scenario new file mode 100755 index 00000000..d77d57d0 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/install-scenario @@ -0,0 +1,23 @@ +#!/bin/bash + +SCENARIO=$1 +ACTION=${2-install} + +dir=dependencies/${SCENARIO} +if [ -z "$SCENARIO" ] ; then + SCENARIO=default + dir=. +fi + + +if [ ! -d "$dir" ] ; then + echo "Requested scenario '${SCENARIO}' does not exist." + exit 1 +fi + +echo "Switch to ${SCENARIO} scenario" + +set -ex + +composer -n --working-dir=$dir ${ACTION} --prefer-dist --no-scripts +composer -n --working-dir=$dir info diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/prep-dependencies b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/prep-dependencies new file mode 100755 index 00000000..d1898440 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/prep-dependencies @@ -0,0 +1,66 @@ +#!/bin/bash + +# +# This script is called automatically on every `composer update`. +# See "post-update-cmd" in the "scripts" section of composer.json. +# +# This script will create a derived composer.json / composer.lock +# pair for every test scenario. Test scenarios are defined in the +# "scenarios" file, which should be customized to suit the needs +# of the project. +# + +SELF_DIRNAME="`dirname -- "$0"`" +source ${SELF_DIRNAME}/scenarios + +echo +echo "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" +echo "::" +echo ":: Update dependencies for the following scenarios:" +echo "::" +echo ":: ${SCENARIOS}" +echo "::" +echo "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" +echo + +set -ex + +for SCENARIO in ${SCENARIOS} ; do + + dir=dependencies/${SCENARIO} + + # Define indirect variable names + stability_variable="stability_${SCENARIO}" + requirement_variable="requirement_${SCENARIO}" + platform_php_variable="platform_php_${SCENARIO}" + + echo "### Create $dir/composer.json for ${SCENARIO} scenario" + mkdir -p $dir + cp composer.json $dir + + # Then set our own platform php version if applicable (otherwise unset it) + composer -n --working-dir=$dir config platform.php "${!platform_php_variable---unset}" + + # Temporarily set our vendor directory to 'vendor' + composer -n --working-dir=$dir config vendor-dir vendor + + # Set an appropriate minimum stability for this version of Symfony + composer -n --working-dir=$dir config minimum-stability "${!stability_variable-stable}" + + # Add a constraint to limit the Symfony version + composer -n --working-dir=$dir require --dev --no-update "${!requirement_variable}" + + # Create the composer.lock file. Ignore the vendor directory created. + composer -n --working-dir=$dir update --no-scripts + + # Set the vendor directory to its final desired location. + composer -n --working-dir=$dir config vendor-dir '../../vendor' + + # The 'autoload' section specifies directory paths that are relative + # to the composer.json file. We will drop in some symlinks so that + # these paths will resolve as if the composer.json were in the root. + for target in $AUTOLOAD_DIRECTORIES ; do + ln -s -f ../../$target $dir + done + +done diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/scenarios b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/scenarios new file mode 100755 index 00000000..6a8f81b2 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/scripts/scenarios @@ -0,0 +1,12 @@ +#!/bin/bash + +SCENARIOS="symfony2 symfony3 symfony4" + +AUTOLOAD_DIRECTORIES='src tests' + +platform_php_symfony2='5.4' +platform_php_symfony3='5.6' + +requirement_symfony2='symfony/console:^2.8' +requirement_symfony3='symfony/console:^3' +requirement_symfony4='symfony/console:^4' diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/ApplyConfigTestTarget.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/ApplyConfigTestTarget.php new file mode 100644 index 00000000..6dace2be --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/ApplyConfigTestTarget.php @@ -0,0 +1,43 @@ +dir = $dir; + return $this; + } + + /** + * A getter for the 'dir' property that we will use to + * determine if the setter was called. + */ + public function getDir() + { + return $this->dir; + } + + /** + * A bad setter that does not return $this. + */ + public function bad($value) + { + $this->value = $value; + } + + /** + * A getter for the bad setter. + */ + public function getBad() + { + return $this->value; + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/MyFooCommand.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/MyFooCommand.php new file mode 100644 index 00000000..0487a024 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/MyFooCommand.php @@ -0,0 +1,47 @@ +setName('my:foo') + ->setDescription('My foo command.') + ->setHelp('This command tests command option injection by echoing its options') + ->addOption( + 'other', + null, + InputOption::VALUE_REQUIRED, + 'Some other option', + 'fish' + ) + ->addOption( + 'name', + null, + InputOption::VALUE_REQUIRED, + 'What is the name of the thing we are naming', + 'George' + ) + ->addOption( + 'dir', + null, + InputOption::VALUE_REQUIRED, + 'What is the base directory to use for this command', + '/default/path' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $output->writeln('Enter my:foo'); + $output->writeln('dir: ' . $input->getOption('dir')); + $output->writeln('name: ' . $input->getOption('name')); + $output->writeln('other: ' . $input->getOption('other')); + } +} diff --git a/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/TestLoader.php b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/TestLoader.php new file mode 100644 index 00000000..241e5120 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/config/scenarios/symfony4/tests/src/TestLoader.php @@ -0,0 +1,36 @@ +data = $data; + } + + public function setSourceName($name) + { + $this->sourceName = $name; + } + + public function export() + { + return $this->data; + } + + public function keys() + { + return array_keys($this->data); + } + + public function getSourceName() + { + return $this->sourceName; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src deleted file mode 120000 index 929cb3dc..00000000 --- a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src +++ /dev/null @@ -1 +0,0 @@ -../../src \ No newline at end of file diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Application.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Application.php new file mode 100644 index 00000000..19d4725f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Application.php @@ -0,0 +1,73 @@ +getDefinition() + ->addOption( + new InputOption('--simulate', null, InputOption::VALUE_NONE, 'Run in simulated mode (show what would have happened).') + ); + $this->getDefinition() + ->addOption( + new InputOption('--progress-delay', null, InputOption::VALUE_REQUIRED, 'Number of seconds before progress bar is displayed in long-running task collections. Default: 2s.', Config::DEFAULT_PROGRESS_DELAY) + ); + + $this->getDefinition() + ->addOption( + new InputOption('--define', '-D', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Define a configuration item value.', []) + ); + } + + /** + * @param string $roboFile + * @param string $roboClass + */ + public function addInitRoboFileCommand($roboFile, $roboClass) + { + $createRoboFile = new Command('init'); + $createRoboFile->setDescription("Intitalizes basic RoboFile in current dir"); + $createRoboFile->setCode(function () use ($roboClass, $roboFile) { + $output = Robo::output(); + $output->writeln(" ~~~ Welcome to Robo! ~~~~ "); + $output->writeln(" ". basename($roboFile) ." will be created in the current directory "); + file_put_contents( + $roboFile, + 'writeln(" Edit this file to add your commands! "); + }); + $this->add($createRoboFile); + } + + /** + * Add self update command, do nothing if null is provided + * + * @param string $repository GitHub Repository for self update + */ + public function addSelfUpdateCommand($repository = null) + { + if (!$repository) { + return; + } + $selfUpdateCommand = new SelfUpdateCommand($this->getName(), $this->getVersion(), $repository); + $this->add($selfUpdateCommand); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CallableTask.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CallableTask.php new file mode 100644 index 00000000..ae9c54fc --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CallableTask.php @@ -0,0 +1,62 @@ +fn = $fn; + $this->reference = $reference; + } + + /** + * @return \Robo\Result + */ + public function run() + { + $result = call_user_func($this->fn, $this->getState()); + // If the function returns no result, then count it + // as a success. + if (!isset($result)) { + $result = Result::success($this->reference); + } + // If the function returns a result, it must either return + // a \Robo\Result or an exit code. In the later case, we + // convert it to a \Robo\Result. + if (!$result instanceof Result) { + $result = new Result($this->reference, $result); + } + + return $result; + } + + public function getState() + { + if ($this->reference instanceof StateAwareInterface) { + return $this->reference->getState(); + } + return new Data(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Collection.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Collection.php new file mode 100644 index 00000000..607435a4 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Collection.php @@ -0,0 +1,769 @@ +resetState(); + } + + public function setProgressBarAutoDisplayInterval($interval) + { + if (!$this->progressIndicator) { + return; + } + return $this->progressIndicator->setProgressBarAutoDisplayInterval($interval); + } + + /** + * {@inheritdoc} + */ + public function add(TaskInterface $task, $name = self::UNNAMEDTASK) + { + $task = new CompletionWrapper($this, $task); + $this->addToTaskList($name, $task); + return $this; + } + + /** + * {@inheritdoc} + */ + public function addCode(callable $code, $name = self::UNNAMEDTASK) + { + return $this->add(new CallableTask($code, $this), $name); + } + + /** + * {@inheritdoc} + */ + public function addIterable($iterable, callable $code) + { + $callbackTask = (new IterationTask($iterable, $code, $this))->inflect($this); + return $this->add($callbackTask); + } + + /** + * {@inheritdoc} + */ + public function rollback(TaskInterface $rollbackTask) + { + // Rollback tasks always try as hard as they can, and never report failures. + $rollbackTask = $this->ignoreErrorsTaskWrapper($rollbackTask); + return $this->wrapAndRegisterRollback($rollbackTask); + } + + /** + * {@inheritdoc} + */ + public function rollbackCode(callable $rollbackCode) + { + // Rollback tasks always try as hard as they can, and never report failures. + $rollbackTask = $this->ignoreErrorsCodeWrapper($rollbackCode); + return $this->wrapAndRegisterRollback($rollbackTask); + } + + /** + * {@inheritdoc} + */ + public function completion(TaskInterface $completionTask) + { + $collection = $this; + $completionRegistrationTask = new CallableTask( + function () use ($collection, $completionTask) { + + $collection->registerCompletion($completionTask); + }, + $this + ); + $this->addToTaskList(self::UNNAMEDTASK, $completionRegistrationTask); + return $this; + } + + /** + * {@inheritdoc} + */ + public function completionCode(callable $completionTask) + { + $completionTask = new CallableTask($completionTask, $this); + return $this->completion($completionTask); + } + + /** + * {@inheritdoc} + */ + public function before($name, $task, $nameOfTaskToAdd = self::UNNAMEDTASK) + { + return $this->addBeforeOrAfter(__FUNCTION__, $name, $task, $nameOfTaskToAdd); + } + + /** + * {@inheritdoc} + */ + public function after($name, $task, $nameOfTaskToAdd = self::UNNAMEDTASK) + { + return $this->addBeforeOrAfter(__FUNCTION__, $name, $task, $nameOfTaskToAdd); + } + + /** + * {@inheritdoc} + */ + public function progressMessage($text, $context = [], $level = LogLevel::NOTICE) + { + $context += ['name' => 'Progress']; + $context += TaskInfo::getTaskContext($this); + return $this->addCode( + function () use ($level, $text, $context) { + $context += $this->getState()->getData(); + $this->printTaskOutput($level, $text, $context); + } + ); + } + + /** + * @param \Robo\Contract\TaskInterface $rollbackTask + * + * @return $this + */ + protected function wrapAndRegisterRollback(TaskInterface $rollbackTask) + { + $collection = $this; + $rollbackRegistrationTask = new CallableTask( + function () use ($collection, $rollbackTask) { + $collection->registerRollback($rollbackTask); + }, + $this + ); + $this->addToTaskList(self::UNNAMEDTASK, $rollbackRegistrationTask); + return $this; + } + + /** + * Add either a 'before' or 'after' function or task. + * + * @param string $method + * @param string $name + * @param callable|TaskInterface $task + * @param string $nameOfTaskToAdd + * + * @return $this + */ + protected function addBeforeOrAfter($method, $name, $task, $nameOfTaskToAdd) + { + if (is_callable($task)) { + $task = new CallableTask($task, $this); + } + $existingTask = $this->namedTask($name); + $fn = [$existingTask, $method]; + call_user_func($fn, $task, $nameOfTaskToAdd); + return $this; + } + + /** + * Wrap the provided task in a wrapper that will ignore + * any errors or exceptions that may be produced. This + * is useful, for example, in adding optional cleanup tasks + * at the beginning of a task collection, to remove previous + * results which may or may not exist. + * + * TODO: Provide some way to specify which sort of errors + * are ignored, so that 'file not found' may be ignored, + * but 'permission denied' reported? + * + * @param \Robo\Contract\TaskInterface $task + * + * @return \Robo\Collection\CallableTask + */ + public function ignoreErrorsTaskWrapper(TaskInterface $task) + { + // If the task is a stack-based task, then tell it + // to try to run all of its operations, even if some + // of them fail. + if ($task instanceof StackBasedTask) { + $task->stopOnFail(false); + } + $ignoreErrorsInTask = function () use ($task) { + $data = []; + try { + $result = $this->runSubtask($task); + $message = $result->getMessage(); + $data = $result->getData(); + $data['exitcode'] = $result->getExitCode(); + } catch (\Exception $e) { + $message = $e->getMessage(); + } + + return Result::success($task, $message, $data); + }; + // Wrap our ignore errors callable in a task. + return new CallableTask($ignoreErrorsInTask, $this); + } + + /** + * @param callable $task + * + * @return \Robo\Collection\CallableTask + */ + public function ignoreErrorsCodeWrapper(callable $task) + { + return $this->ignoreErrorsTaskWrapper(new CallableTask($task, $this)); + } + + /** + * Return the list of task names added to this collection. + * + * @return array + */ + public function taskNames() + { + return array_keys($this->taskList); + } + + /** + * Test to see if a specified task name exists. + * n.b. before() and after() require that the named + * task exist; use this function to test first, if + * unsure. + * + * @param string $name + * + * @return bool + */ + public function hasTask($name) + { + return array_key_exists($name, $this->taskList); + } + + /** + * Find an existing named task. + * + * @param string $name + * The name of the task to insert before. The named task MUST exist. + * + * @return Element + * The task group for the named task. Generally this is only + * used to call 'before()' and 'after()'. + */ + protected function namedTask($name) + { + if (!$this->hasTask($name)) { + throw new \RuntimeException("Could not find task named $name"); + } + return $this->taskList[$name]; + } + + /** + * Add a list of tasks to our task collection. + * + * @param TaskInterface[] $tasks + * An array of tasks to run with rollback protection + * + * @return $this + */ + public function addTaskList(array $tasks) + { + foreach ($tasks as $name => $task) { + $this->add($task, $name); + } + return $this; + } + + /** + * Add the provided task to our task list. + * + * @param string $name + * @param \Robo\Contract\TaskInterface $task + * + * @return \Robo\Collection\Collection + */ + protected function addToTaskList($name, TaskInterface $task) + { + // All tasks are stored in a task group so that we have a place + // to hang 'before' and 'after' tasks. + $taskGroup = new Element($task); + return $this->addCollectionElementToTaskList($name, $taskGroup); + } + + /** + * @param int|string $name + * @param \Robo\Collection\Element $taskGroup + * + * @return $this + */ + protected function addCollectionElementToTaskList($name, Element $taskGroup) + { + // If a task name is not provided, then we'll let php pick + // the array index. + if (Result::isUnnamed($name)) { + $this->taskList[] = $taskGroup; + return $this; + } + // If we are replacing an existing task with the + // same name, ensure that our new task is added to + // the end. + $this->taskList[$name] = $taskGroup; + return $this; + } + + /** + * Set the parent collection. This is necessary so that nested + * collections' rollback and completion tasks can be added to the + * top-level collection, ensuring that the rollbacks for a collection + * will run if any later task fails. + * + * @param \Robo\Collection\NestedCollectionInterface $parentCollection + * + * @return $this + */ + public function setParentCollection(NestedCollectionInterface $parentCollection) + { + $this->parentCollection = $parentCollection; + return $this; + } + + /** + * Get the appropriate parent collection to use + * + * @return CollectionInterface + */ + public function getParentCollection() + { + return $this->parentCollection ? $this->parentCollection : $this; + } + + /** + * Register a rollback task to run if there is any failure. + * + * Clients are free to add tasks to the rollback stack as + * desired; however, usually it is preferable to call + * Collection::rollback() instead. With that function, + * the rollback function will only be called if all of the + * tasks added before it complete successfully, AND some later + * task fails. + * + * One example of a good use-case for registering a callback + * function directly is to add a task that sends notification + * when a task fails. + * + * @param TaskInterface $rollbackTask + * The rollback task to run on failure. + */ + public function registerRollback(TaskInterface $rollbackTask) + { + if ($this->parentCollection) { + return $this->parentCollection->registerRollback($rollbackTask); + } + if ($rollbackTask) { + $this->rollbackStack[] = $rollbackTask; + } + } + + /** + * Register a completion task to run once all other tasks finish. + * Completion tasks run whether or not a rollback operation was + * triggered. They do not trigger rollbacks if they fail. + * + * The typical use-case for a completion function is to clean up + * temporary objects (e.g. temporary folders). The preferred + * way to do that, though, is to use Temporary::wrap(). + * + * On failures, completion tasks will run after all rollback tasks. + * If one task collection is nested inside another task collection, + * then the nested collection's completion tasks will run as soon as + * the nested task completes; they are not deferred to the end of + * the containing collection's execution. + * + * @param TaskInterface $completionTask + * The completion task to run at the end of all other operations. + */ + public function registerCompletion(TaskInterface $completionTask) + { + if ($this->parentCollection) { + return $this->parentCollection->registerCompletion($completionTask); + } + if ($completionTask) { + // Completion tasks always try as hard as they can, and never report failures. + $completionTask = $this->ignoreErrorsTaskWrapper($completionTask); + $this->completionStack[] = $completionTask; + } + } + + /** + * Return the count of steps in this collection + * + * @return int + */ + public function progressIndicatorSteps() + { + $steps = 0; + foreach ($this->taskList as $name => $taskGroup) { + $steps += $taskGroup->progressIndicatorSteps(); + } + return $steps; + } + + /** + * A Collection of tasks can provide a command via `getCommand()` + * if it contains a single task, and that task implements CommandInterface. + * + * @return string + * + * @throws \Robo\Exception\TaskException + */ + public function getCommand() + { + if (empty($this->taskList)) { + return ''; + } + + if (count($this->taskList) > 1) { + // TODO: We could potentially iterate over the items in the collection + // and concatenate the result of getCommand() from each one, and fail + // only if we encounter a command that is not a CommandInterface. + throw new TaskException($this, "getCommand() does not work on arbitrary collections of tasks."); + } + + $taskElement = reset($this->taskList); + $task = $taskElement->getTask(); + $task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + if ($task instanceof CommandInterface) { + return $task->getCommand(); + } + + throw new TaskException($task, get_class($task) . " does not implement CommandInterface, so can't be used to provide a command"); + } + + /** + * Run our tasks, and roll back if necessary. + * + * @return \Robo\Result + */ + public function run() + { + $result = $this->runWithoutCompletion(); + $this->complete(); + return $result; + } + + /** + * @return \Robo\Result + */ + private function runWithoutCompletion() + { + $result = Result::success($this); + + if (empty($this->taskList)) { + return $result; + } + + $this->startProgressIndicator(); + if ($result->wasSuccessful()) { + foreach ($this->taskList as $name => $taskGroup) { + $taskList = $taskGroup->getTaskList(); + $result = $this->runTaskList($name, $taskList, $result); + if (!$result->wasSuccessful()) { + $this->fail(); + return $result; + } + } + $this->taskList = []; + } + $this->stopProgressIndicator(); + $result['time'] = $this->getExecutionTime(); + + return $result; + } + + /** + * Run every task in a list, but only up to the first failure. + * Return the failing result, or success if all tasks run. + * + * @param string $name + * @param TaskInterface[] $taskList + * @param \Robo\Result $result + * + * @return \Robo\Result + * + * @throws \Robo\Exception\TaskExitException + */ + private function runTaskList($name, array $taskList, Result $result) + { + try { + foreach ($taskList as $taskName => $task) { + $taskResult = $this->runSubtask($task); + $this->advanceProgressIndicator(); + // If the current task returns an error code, then stop + // execution and signal a rollback. + if (!$taskResult->wasSuccessful()) { + return $taskResult; + } + // We accumulate our results into a field so that tasks that + // have a reference to the collection may examine and modify + // the incremental results, if they wish. + $key = Result::isUnnamed($taskName) ? $name : $taskName; + $result->accumulate($key, $taskResult); + // The result message will be the message of the last task executed. + $result->setMessage($taskResult->getMessage()); + } + } catch (TaskExitException $exitException) { + $this->fail(); + throw $exitException; + } catch (\Exception $e) { + // Tasks typically should not throw, but if one does, we will + // convert it into an error and roll back. + return Result::fromException($task, $e, $result->getData()); + } + return $result; + } + + /** + * Force the rollback functions to run + * + * @return $this + */ + public function fail() + { + $this->disableProgressIndicator(); + $this->runRollbackTasks(); + $this->complete(); + return $this; + } + + /** + * Force the completion functions to run + * + * @return $this + */ + public function complete() + { + $this->detatchProgressIndicator(); + $this->runTaskListIgnoringFailures($this->completionStack); + $this->reset(); + return $this; + } + + /** + * Reset this collection, removing all tasks. + * + * @return $this + */ + public function reset() + { + $this->taskList = []; + $this->completionStack = []; + $this->rollbackStack = []; + return $this; + } + + /** + * Run all of our rollback tasks. + * + * Note that Collection does not implement RollbackInterface, but + * it may still be used as a task inside another task collection + * (i.e. you can nest task collections, if desired). + */ + protected function runRollbackTasks() + { + $this->runTaskListIgnoringFailures($this->rollbackStack); + // Erase our rollback stack once we have finished rolling + // everything back. This will allow us to potentially use + // a command collection more than once (e.g. to retry a + // failed operation after doing some error recovery). + $this->rollbackStack = []; + } + + /** + * @param TaskInterface|NestedCollectionInterface|WrappedTaskInterface $task + * + * @return \Robo\Result + */ + protected function runSubtask($task) + { + $original = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + $this->setParentCollectionForTask($original, $this->getParentCollection()); + if ($original instanceof InflectionInterface) { + $original->inflect($this); + } + if ($original instanceof StateAwareInterface) { + $original->setState($this->getState()); + } + $this->doDeferredInitialization($original); + $taskResult = $task->run(); + $taskResult = Result::ensureResult($task, $taskResult); + $this->doStateUpdates($original, $taskResult); + return $taskResult; + } + + protected function doStateUpdates($task, Data $taskResult) + { + $this->updateState($taskResult); + $key = spl_object_hash($task); + if (array_key_exists($key, $this->messageStoreKeys)) { + $state = $this->getState(); + list($stateKey, $sourceKey) = $this->messageStoreKeys[$key]; + $value = empty($sourceKey) ? $taskResult->getMessage() : $taskResult[$sourceKey]; + $state[$stateKey] = $value; + } + } + + public function storeState($task, $key, $source = '') + { + $this->messageStoreKeys[spl_object_hash($task)] = [$key, $source]; + + return $this; + } + + public function deferTaskConfiguration($task, $functionName, $stateKey) + { + return $this->defer( + $task, + function ($task, $state) use ($functionName, $stateKey) { + $fn = [$task, $functionName]; + $value = $state[$stateKey]; + $fn($value); + } + ); + } + + /** + * Defer execution of a callback function until just before a task + * runs. Use this time to provide more settings for the task, e.g. from + * the collection's shared state, which is populated with the results + * of previous test runs. + */ + public function defer($task, $callback) + { + $this->deferredCallbacks[spl_object_hash($task)][] = $callback; + + return $this; + } + + protected function doDeferredInitialization($task) + { + // If the task is a state consumer, then call its receiveState method + if ($task instanceof \Robo\State\Consumer) { + $task->receiveState($this->getState()); + } + + // Check and see if there are any deferred callbacks for this task. + $key = spl_object_hash($task); + if (!array_key_exists($key, $this->deferredCallbacks)) { + return; + } + + // Call all of the deferred callbacks + foreach ($this->deferredCallbacks[$key] as $fn) { + $fn($task, $this->getState()); + } + } + + /** + * @param TaskInterface|NestedCollectionInterface|WrappedTaskInterface $task + * @param $parentCollection + */ + protected function setParentCollectionForTask($task, $parentCollection) + { + if ($task instanceof NestedCollectionInterface) { + $task->setParentCollection($parentCollection); + } + } + + /** + * Run all of the tasks in a provided list, ignoring failures. + * This is used to roll back or complete. + * + * @param TaskInterface[] $taskList + */ + protected function runTaskListIgnoringFailures(array $taskList) + { + foreach ($taskList as $task) { + try { + $this->runSubtask($task); + } catch (\Exception $e) { + // Ignore rollback failures. + } + } + } + + /** + * Give all of our tasks to the provided collection builder. + * + * @param CollectionBuilder $builder + */ + public function transferTasks($builder) + { + foreach ($this->taskList as $name => $taskGroup) { + // TODO: We are abandoning all of our before and after tasks here. + // At the moment, transferTasks is only called under conditions where + // there will be none of these, but care should be taken if that changes. + $task = $taskGroup->getTask(); + $builder->addTaskToCollection($task); + } + $this->reset(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionBuilder.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionBuilder.php new file mode 100644 index 00000000..3e037b01 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionBuilder.php @@ -0,0 +1,571 @@ +collectionBuilder() + * ->taskFilesystemStack() + * ->mkdir('g') + * ->touch('g/g.txt') + * ->rollback( + * $this->taskDeleteDir('g') + * ) + * ->taskFilesystemStack() + * ->mkdir('g/h') + * ->touch('g/h/h.txt') + * ->taskFilesystemStack() + * ->mkdir('g/h/i/c') + * ->touch('g/h/i/i.txt') + * ->run() + * ?> + * + * In the example above, the `taskDeleteDir` will be called if + * ``` + */ +class CollectionBuilder extends BaseTask implements NestedCollectionInterface, WrappedTaskInterface, CommandInterface, StateAwareInterface +{ + use StateAwareTrait; + + /** + * @var \Robo\Tasks + */ + protected $commandFile; + + /** + * @var CollectionInterface + */ + protected $collection; + + /** + * @var TaskInterface + */ + protected $currentTask; + + /** + * @var bool + */ + protected $simulated; + + /** + * @param \Robo\Tasks $commandFile + */ + public function __construct($commandFile) + { + $this->commandFile = $commandFile; + $this->resetState(); + } + + public static function create($container, $commandFile) + { + $builder = new self($commandFile); + + $builder->setLogger($container->get('logger')); + $builder->setProgressIndicator($container->get('progressIndicator')); + $builder->setConfig($container->get('config')); + $builder->setOutputAdapter($container->get('outputAdapter')); + + return $builder; + } + + /** + * @param bool $simulated + * + * @return $this + */ + public function simulated($simulated = true) + { + $this->simulated = $simulated; + return $this; + } + + /** + * @return bool + */ + public function isSimulated() + { + if (!isset($this->simulated)) { + $this->simulated = $this->getConfig()->get(Config::SIMULATE); + } + return $this->simulated; + } + + /** + * Create a temporary directory to work in. When the collection + * completes or rolls back, the temporary directory will be deleted. + * Returns the path to the location where the directory will be + * created. + * + * @param string $prefix + * @param string $base + * @param bool $includeRandomPart + * + * @return string + */ + public function tmpDir($prefix = 'tmp', $base = '', $includeRandomPart = true) + { + // n.b. Any task that the builder is asked to create is + // automatically added to the builder's collection, and + // wrapped in the builder object. Therefore, the result + // of any call to `taskFoo()` from within the builder will + // always be `$this`. + return $this->taskTmpDir($prefix, $base, $includeRandomPart)->getPath(); + } + + /** + * Create a working directory to hold results. A temporary directory + * is first created to hold the intermediate results. After the + * builder finishes, the work directory is moved into its final location; + * any results already in place will be moved out of the way and + * then deleted. + * + * @param string $finalDestination The path where the working directory + * will be moved once the task collection completes. + * + * @return string + */ + public function workDir($finalDestination) + { + // Creating the work dir task in this context adds it to our task collection. + return $this->taskWorkDir($finalDestination)->getPath(); + } + + public function addTask(TaskInterface $task) + { + $this->getCollection()->add($task); + return $this; + } + + /** + * Add arbitrary code to execute as a task. + * + * @see \Robo\Collection\CollectionInterface::addCode + * + * @param callable $code + * @param int|string $name + * @return $this + */ + public function addCode(callable $code, $name = \Robo\Collection\CollectionInterface::UNNAMEDTASK) + { + $this->getCollection()->addCode($code, $name); + return $this; + } + + /** + * Add a list of tasks to our task collection. + * + * @param TaskInterface[] $tasks + * An array of tasks to run with rollback protection + * + * @return $this + */ + public function addTaskList(array $tasks) + { + $this->getCollection()->addTaskList($tasks); + return $this; + } + + public function rollback(TaskInterface $task) + { + // Ensure that we have a collection if we are going to add + // a rollback function. + $this->getCollection()->rollback($task); + return $this; + } + + public function rollbackCode(callable $rollbackCode) + { + $this->getCollection()->rollbackCode($rollbackCode); + return $this; + } + + public function completion(TaskInterface $task) + { + $this->getCollection()->completion($task); + return $this; + } + + public function completionCode(callable $completionCode) + { + $this->getCollection()->completionCode($completionCode); + return $this; + } + + /** + * @param string $text + * @param array $context + * @param string $level + * + * @return $this + */ + public function progressMessage($text, $context = [], $level = LogLevel::NOTICE) + { + $this->getCollection()->progressMessage($text, $context, $level); + return $this; + } + + /** + * @param \Robo\Collection\NestedCollectionInterface $parentCollection + * + * @return $this + */ + public function setParentCollection(NestedCollectionInterface $parentCollection) + { + $this->getCollection()->setParentCollection($parentCollection); + return $this; + } + + /** + * Called by the factory method of each task; adds the current + * task to the task builder. + * + * TODO: protected + * + * @param TaskInterface $task + * + * @return $this + */ + public function addTaskToCollection($task) + { + // Postpone creation of the collection until the second time + // we are called. At that time, $this->currentTask will already + // be populated. We call 'getCollection()' so that it will + // create the collection and add the current task to it. + // Note, however, that if our only tasks implements NestedCollectionInterface, + // then we should force this builder to use a collection. + if (!$this->collection && (isset($this->currentTask) || ($task instanceof NestedCollectionInterface))) { + $this->getCollection(); + } + $this->currentTask = $task; + if ($this->collection) { + $this->collection->add($task); + } + return $this; + } + + public function getState() + { + $collection = $this->getCollection(); + return $collection->getState(); + } + + public function storeState($key, $source = '') + { + return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); + } + + public function deferTaskConfiguration($functionName, $stateKey) + { + return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); + } + + public function defer($callback) + { + return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); + } + + protected function callCollectionStateFuntion($functionName, $args) + { + $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; + + array_unshift($args, $currentTask); + $collection = $this->getCollection(); + $fn = [$collection, $functionName]; + + call_user_func_array($fn, $args); + return $this; + } + + public function setVerbosityThreshold($verbosityThreshold) + { + $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; + if ($currentTask) { + $currentTask->setVerbosityThreshold($verbosityThreshold); + return $this; + } + parent::setVerbosityThreshold($verbosityThreshold); + return $this; + } + + + /** + * Return the current task for this collection builder. + * TODO: Not needed? + * + * @return \Robo\Contract\TaskInterface + */ + public function getCollectionBuilderCurrentTask() + { + return $this->currentTask; + } + + /** + * Create a new builder with its own task collection + * + * @return CollectionBuilder + */ + public function newBuilder() + { + $collectionBuilder = new self($this->commandFile); + $collectionBuilder->inflect($this); + $collectionBuilder->simulated($this->isSimulated()); + $collectionBuilder->setVerbosityThreshold($this->verbosityThreshold()); + $collectionBuilder->setState($this->getState()); + + return $collectionBuilder; + } + + /** + * Calling the task builder with methods of the current + * task calls through to that method of the task. + * + * There is extra complexity in this function that could be + * simplified if we attached the 'LoadAllTasks' and custom tasks + * to the collection builder instead of the RoboFile. While that + * change would be a better design overall, it would require that + * the user do a lot more work to set up and use custom tasks. + * We therefore take on some additional complexity here in order + * to allow users to maintain their tasks in their RoboFile, which + * is much more convenient. + * + * Calls to $this->collectionBuilder()->taskFoo() cannot be made + * directly because all of the task methods are protected. These + * calls will therefore end up here. If the method name begins + * with 'task', then it is eligible to be used with the builder. + * + * When we call getBuiltTask, below, it will use the builder attached + * to the commandfile to build the task. However, this is not what we + * want: the task needs to be built from THIS collection builder, so that + * it will be affected by whatever state is active in this builder. + * To do this, we have two choices: 1) save and restore the builder + * in the commandfile, or 2) clone the commandfile and set this builder + * on the copy. 1) is vulnerable to failure in multithreaded environments + * (currently not supported), while 2) might cause confusion if there + * is shared state maintained in the commandfile, which is in the + * domain of the user. + * + * Note that even though we are setting up the commandFile to + * use this builder, getBuiltTask always creates a new builder + * (which is constructed using all of the settings from the + * commandFile's builder), and the new task is added to that. + * We therefore need to transfer the newly built task into this + * builder. The temporary builder is discarded. + * + * @param string $fn + * @param array $args + * + * @return $this|mixed + */ + public function __call($fn, $args) + { + if (preg_match('#^task[A-Z]#', $fn) && (method_exists($this->commandFile, 'getBuiltTask'))) { + $saveBuilder = $this->commandFile->getBuilder(); + $this->commandFile->setBuilder($this); + $temporaryBuilder = $this->commandFile->getBuiltTask($fn, $args); + $this->commandFile->setBuilder($saveBuilder); + if (!$temporaryBuilder) { + throw new \BadMethodCallException("No such method $fn: task does not exist in " . get_class($this->commandFile)); + } + $temporaryBuilder->getCollection()->transferTasks($this); + return $this; + } + if (!isset($this->currentTask)) { + throw new \BadMethodCallException("No such method $fn: current task undefined in collection builder."); + } + // If the method called is a method of the current task, + // then call through to the current task's setter method. + $result = call_user_func_array([$this->currentTask, $fn], $args); + + // If something other than a setter method is called, then return its result. + $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; + if (isset($result) && ($result !== $currentTask)) { + return $result; + } + + return $this; + } + + /** + * Construct the desired task and add it to this builder. + * + * @param string|object $name + * @param array $args + * + * @return \Robo\Collection\CollectionBuilder + */ + public function build($name, $args) + { + $reflection = new ReflectionClass($name); + $task = $reflection->newInstanceArgs($args); + if (!$task) { + throw new RuntimeException("Can not construct task $name"); + } + $task = $this->fixTask($task, $args); + $this->configureTask($name, $task); + return $this->addTaskToCollection($task); + } + + /** + * @param InflectionInterface $task + * @param array $args + * + * @return \Robo\Collection\CompletionWrapper|\Robo\Task\Simulator + */ + protected function fixTask($task, $args) + { + if ($task instanceof InflectionInterface) { + $task->inflect($this); + } + if ($task instanceof BuilderAwareInterface) { + $task->setBuilder($this); + } + if ($task instanceof VerbosityThresholdInterface) { + $task->setVerbosityThreshold($this->verbosityThreshold()); + } + + // Do not wrap our wrappers. + if ($task instanceof CompletionWrapper || $task instanceof Simulator) { + return $task; + } + + // Remember whether or not this is a task before + // it gets wrapped in any decorator. + $isTask = $task instanceof TaskInterface; + $isCollection = $task instanceof NestedCollectionInterface; + + // If the task implements CompletionInterface, ensure + // that its 'complete' method is called when the application + // terminates -- but only if its 'run' method is called + // first. If the task is added to a collection, then the + // task will be unwrapped via its `original` method, and + // it will be re-wrapped with a new completion wrapper for + // its new collection. + if ($task instanceof CompletionInterface) { + $task = new CompletionWrapper(Temporary::getCollection(), $task); + } + + // If we are in simulated mode, then wrap any task in + // a TaskSimulator. + if ($isTask && !$isCollection && ($this->isSimulated())) { + $task = new \Robo\Task\Simulator($task, $args); + $task->inflect($this); + } + + return $task; + } + + /** + * Check to see if there are any setter methods defined in configuration + * for this task. + */ + protected function configureTask($taskClass, $task) + { + $taskClass = static::configClassIdentifier($taskClass); + $configurationApplier = new ConfigForSetters($this->getConfig(), $taskClass, 'task.'); + $configurationApplier->apply($task, 'settings'); + + // TODO: If we counted each instance of $taskClass that was called from + // this builder, then we could also apply configuration from + // "task.{$taskClass}[$N].settings" + + // TODO: If the builder knew what the current command name was, + // then we could also search for task configuration under + // command-specific keys such as "command.{$commandname}.task.{$taskClass}.settings". + } + + /** + * When we run the collection builder, run everything in the collection. + * + * @return \Robo\Result + */ + public function run() + { + $this->startTimer(); + $result = $this->runTasks(); + $this->stopTimer(); + $result['time'] = $this->getExecutionTime(); + $result->mergeData($this->getState()->getData()); + return $result; + } + + /** + * If there is a single task, run it; if there is a collection, run + * all of its tasks. + * + * @return \Robo\Result + */ + protected function runTasks() + { + if (!$this->collection && $this->currentTask) { + $result = $this->currentTask->run(); + return Result::ensureResult($this->currentTask, $result); + } + return $this->getCollection()->run(); + } + + /** + * @return string + */ + public function getCommand() + { + if (!$this->collection && $this->currentTask) { + $task = $this->currentTask; + $task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + if ($task instanceof CommandInterface) { + return $task->getCommand(); + } + } + + return $this->getCollection()->getCommand(); + } + + /** + * @return \Robo\Collection\Collection + */ + public function original() + { + return $this->getCollection(); + } + + /** + * Return the collection of tasks associated with this builder. + * + * @return CollectionInterface + */ + public function getCollection() + { + if (!isset($this->collection)) { + $this->collection = new Collection(); + $this->collection->inflect($this); + $this->collection->setState($this->getState()); + $this->collection->setProgressBarAutoDisplayInterval($this->getConfig()->get(Config::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL)); + + if (isset($this->currentTask)) { + $this->collection->add($this->currentTask); + } + } + return $this->collection; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionInterface.php new file mode 100644 index 00000000..173ca169 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CollectionInterface.php @@ -0,0 +1,151 @@ +run(); + } catch (\Exception $e) { + return Result::fromException($result, $e); + } + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CompletionWrapper.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CompletionWrapper.php new file mode 100644 index 00000000..3e81bd91 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/CompletionWrapper.php @@ -0,0 +1,106 @@ +collection = $collection; + $this->task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + $this->rollbackTask = $rollbackTask; + } + + /** + * {@inheritdoc} + */ + public function original() + { + return $this->task; + } + + /** + * Before running this task, register its rollback and completion + * handlers on its collection. The reason this class exists is to + * defer registration of rollback and completion tasks until 'run()' time. + * + * @return \Robo\Result + */ + public function run() + { + if ($this->rollbackTask) { + $this->collection->registerRollback($this->rollbackTask); + } + if ($this->task instanceof RollbackInterface) { + $this->collection->registerRollback(new CallableTask([$this->task, 'rollback'], $this->task)); + } + if ($this->task instanceof CompletionInterface) { + $this->collection->registerCompletion(new CallableTask([$this->task, 'complete'], $this->task)); + } + + return $this->task->run(); + } + + /** + * Make this wrapper object act like the class it wraps. + * + * @param string $function + * @param array $args + * + * @return mixed + */ + public function __call($function, $args) + { + return call_user_func_array(array($this->task, $function), $args); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Element.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Element.php new file mode 100644 index 00000000..b67b56bb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Element.php @@ -0,0 +1,116 @@ +task = $task; + } + + /** + * @param mixed $before + * @param string $name + */ + public function before($before, $name) + { + if ($name) { + $this->before[$name] = $before; + } else { + $this->before[] = $before; + } + } + + /** + * @param mixed $after + * @param string $name + */ + public function after($after, $name) + { + if ($name) { + $this->after[$name] = $after; + } else { + $this->after[] = $after; + } + } + + /** + * @return array + */ + public function getBefore() + { + return $this->before; + } + + /** + * @return array + */ + public function getAfter() + { + return $this->after; + } + + /** + * @return \Robo\Contract\TaskInterface + */ + public function getTask() + { + return $this->task; + } + + /** + * @return array + */ + public function getTaskList() + { + return array_merge($this->getBefore(), [$this->getTask()], $this->getAfter()); + } + + /** + * @return int + */ + public function progressIndicatorSteps() + { + $steps = 0; + foreach ($this->getTaskList() as $task) { + if ($task instanceof WrappedTaskInterface) { + $task = $task->original(); + } + // If the task is a ProgressIndicatorAwareInterface, then it + // will advance the progress indicator a number of times. + if ($task instanceof ProgressIndicatorAwareInterface) { + $steps += $task->progressIndicatorSteps(); + } + // We also advance the progress indicator once regardless + // of whether it is progress-indicator aware or not. + $steps++; + } + return $steps; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/NestedCollectionInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/NestedCollectionInterface.php new file mode 100644 index 00000000..5e32cf37 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/NestedCollectionInterface.php @@ -0,0 +1,12 @@ +iterable = $iterable; + } + + /** + * @param string $message + * @param array $context + * + * @return $this + */ + public function iterationMessage($message, $context = []) + { + $this->message = $message; + $this->context = $context + ['name' => 'Progress']; + return $this; + } + + /** + * @param int|string $key + * @param mixed $value + */ + protected function showIterationMessage($key, $value) + { + if ($this->message) { + $context = ['key' => $key, 'value' => $value]; + $context += $this->context; + $context += TaskInfo::getTaskContext($this); + $this->printTaskInfo($this->message, $context); + } + } + + /** + * @param callable $fn + * + * @return $this + */ + public function withEachKeyValueCall(callable $fn) + { + $this->functionStack[] = $fn; + return $this; + } + + /** + * @param callable $fn + * + * @return \Robo\Collection\TaskForEach + */ + public function call(callable $fn) + { + return $this->withEachKeyValueCall( + function ($key, $value) use ($fn) { + return call_user_func($fn, $value); + } + ); + } + + /** + * @param callable $fn + * + * @return \Robo\Collection\TaskForEach + */ + public function withBuilder(callable $fn) + { + $this->countingStack[] = + function ($key, $value) use ($fn) { + // Create a new builder for every iteration + $builder = $this->collectionBuilder(); + // The user function should build task operations using + // the $key / $value parameters; we will call run() on + // the builder thus constructed. + call_user_func($fn, $builder, $key, $value); + return $builder->getCollection()->progressIndicatorSteps(); + }; + return $this->withEachKeyValueCall( + function ($key, $value) use ($fn) { + // Create a new builder for every iteration + $builder = $this->collectionBuilder() + ->setParentCollection($this->parentCollection); + // The user function should build task operations using + // the $key / $value parameters; we will call run() on + // the builder thus constructed. + call_user_func($fn, $builder, $key, $value); + return $builder->run(); + } + ); + } + + /** + * {@inheritdoc} + */ + public function setParentCollection(NestedCollectionInterface $parentCollection) + { + $this->parentCollection = $parentCollection; + return $this; + } + + /** + * {@inheritdoc} + */ + public function progressIndicatorSteps() + { + $multiplier = count($this->functionStack); + if (!empty($this->countingStack)) { + $value = reset($this->iterable); + $key = key($this->iterable); + foreach ($this->countingStack as $fn) { + $multiplier += call_user_func($fn, $key, $value); + } + } + return count($this->iterable) * $multiplier; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $finalResult = Result::success($this); + $this->startProgressIndicator(); + foreach ($this->iterable as $key => $value) { + $this->showIterationMessage($key, $value); + try { + foreach ($this->functionStack as $fn) { + $result = call_user_func($fn, $key, $value); + $this->advanceProgressIndicator(); + if (!isset($result)) { + $result = Result::success($this); + } + // If the function returns a result, it must either return + // a \Robo\Result or an exit code. In the later case, we + // convert it to a \Robo\Result. + if (!$result instanceof Result) { + $result = new Result($this, $result); + } + if (!$result->wasSuccessful()) { + return $result; + } + $finalResult = $result->merge($finalResult); + } + } catch (\Exception $e) { + return Result::fromException($result, $e); + } + } + $this->stopProgressIndicator(); + return $finalResult; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Temporary.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Temporary.php new file mode 100644 index 00000000..dad25e34 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/Temporary.php @@ -0,0 +1,57 @@ +get('collection'); + register_shutdown_function(function () { + static::complete(); + }); + } + + return static::$collection; + } + + /** + * Call the complete method of all of the registered objects. + */ + public static function complete() + { + // Run the collection of tasks. This will also run the + // completion tasks. + $collection = static::getCollection(); + $collection->run(); + // Make sure that our completion functions do not run twice. + $collection->reset(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/loadTasks.php new file mode 100644 index 00000000..03f68823 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Collection/loadTasks.php @@ -0,0 +1,17 @@ +task(TaskForEach::class, $collection); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/BuilderAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/BuilderAwareTrait.php new file mode 100644 index 00000000..915ff008 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/BuilderAwareTrait.php @@ -0,0 +1,45 @@ +builder = $builder; + + return $this; + } + + /** + * @see \Robo\Contract\BuilderAwareInterface::getBuilder() + * + * @return \Robo\Collection\CollectionBuilder + */ + public function getBuilder() + { + return $this->builder; + } + + /** + * @return \Robo\Collection\CollectionBuilder + */ + protected function collectionBuilder() + { + return $this->getBuilder()->newBuilder(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/CommandArguments.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/CommandArguments.php new file mode 100644 index 00000000..12c2e89f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/CommandArguments.php @@ -0,0 +1,130 @@ +args($arg); + } + + /** + * Pass methods parameters as arguments to executable. Argument values + * are automatically escaped. + * + * @param string|string[] $args + * + * @return $this + */ + public function args($args) + { + if (!is_array($args)) { + $args = func_get_args(); + } + $this->arguments .= ' ' . implode(' ', array_map('static::escape', $args)); + return $this; + } + + /** + * Pass the provided string in its raw (as provided) form as an argument to executable. + * + * @param string $arg + * + * @return $this + */ + public function rawArg($arg) + { + $this->arguments .= " $arg"; + + return $this; + } + + /** + * Escape the provided value, unless it contains only alphanumeric + * plus a few other basic characters. + * + * @param string $value + * + * @return string + */ + public static function escape($value) + { + if (preg_match('/^[a-zA-Z0-9\/\.@~_-]+$/', $value)) { + return $value; + } + return ProcessUtils::escapeArgument($value); + } + + /** + * Pass option to executable. Options are prefixed with `--` , value can be provided in second parameter. + * Option values are automatically escaped. + * + * @param string $option + * @param string $value + * @param string $separator + * + * @return $this + */ + public function option($option, $value = null, $separator = ' ') + { + if ($option !== null and strpos($option, '-') !== 0) { + $option = "--$option"; + } + $this->arguments .= null == $option ? '' : " " . $option; + $this->arguments .= null == $value ? '' : $separator . static::escape($value); + return $this; + } + + /** + * Pass multiple options to executable. The associative array contains + * the key:value pairs that become `--key value`, for each item in the array. + * Values are automatically escaped. + */ + public function options(array $options, $separator = ' ') + { + foreach ($options as $option => $value) { + $this->option($option, $value, $separator); + } + return $this; + } + + /** + * Pass an option with multiple values to executable. Value can be a string or array. + * Option values are automatically escaped. + * + * @param string $option + * @param string|array $value + * @param string $separator + * + * @return $this + */ + public function optionList($option, $value = array(), $separator = ' ') + { + if (is_array($value)) { + foreach ($value as $item) { + $this->optionList($option, $item, $separator); + } + } else { + $this->option($option, $value, $separator); + } + + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/CommandReceiver.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/CommandReceiver.php new file mode 100644 index 00000000..03b20fce --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/CommandReceiver.php @@ -0,0 +1,30 @@ +getCommand(); + } else { + throw new TaskException($this, get_class($command) . " does not implement CommandInterface, so can't be passed into this task"); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ConfigAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ConfigAwareTrait.php new file mode 100644 index 00000000..d6d45788 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ConfigAwareTrait.php @@ -0,0 +1,109 @@ +config = $config; + + return $this; + } + + /** + * Get the config management object. + * + * @return ConfigInterface + * + * @see \Robo\Contract\ConfigAwareInterface::getConfig() + */ + public function getConfig() + { + return $this->config; + } + + /** + * Any class that uses ConfigAwareTrait SHOULD override this method + * , and define a prefix for its configuration items. This is usually + * done in a base class. When used, this method should return a string + * that ends with a "."; see BaseTask::configPrefix(). + * + * @return string + */ + protected static function configPrefix() + { + return ''; + } + + protected static function configClassIdentifier($classname) + { + $configIdentifier = strtr($classname, '\\', '.'); + $configIdentifier = preg_replace('#^(.*\.Task\.|\.)#', '', $configIdentifier); + + return $configIdentifier; + } + + protected static function configPostfix() + { + return ''; + } + + /** + * @param string $key + * + * @return string + */ + private static function getClassKey($key) + { + $configPrefix = static::configPrefix(); // task. + $configClass = static::configClassIdentifier(get_called_class()); // PARTIAL_NAMESPACE.CLASSNAME + $configPostFix = static::configPostfix(); // .settings + + return sprintf('%s%s%s.%s', $configPrefix, $configClass, $configPostFix, $key); + } + + /** + * @param string $key + * @param mixed $value + * @param Config|null $config + */ + public static function configure($key, $value, $config = null) + { + if (!$config) { + $config = Robo::config(); + } + $config->setDefault(static::getClassKey($key), $value); + } + + /** + * @param string $key + * @param mixed|null $default + * + * @return mixed|null + */ + protected function getConfigValue($key, $default = null) + { + if (!$this->getConfig()) { + return $default; + } + return $this->getConfig()->get(static::getClassKey($key), $default); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/DynamicParams.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/DynamicParams.php new file mode 100644 index 00000000..28a1d150 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/DynamicParams.php @@ -0,0 +1,45 @@ +$property))) { + $this->$property = !$this->$property; + return $this; + } + + // append item to array + if (is_array($this->$property)) { + if (is_array($args[0])) { + $this->$property = $args[0]; + } else { + array_push($this->$property, $args[0]); + } + return $this; + } + + $this->$property = $args[0]; + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecCommand.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecCommand.php new file mode 100644 index 00000000..c3e6c3af --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecCommand.php @@ -0,0 +1,148 @@ +execTimer)) { + $this->execTimer = new TimeKeeper(); + } + return $this->execTimer; + } + + /** + * Look for a "{$cmd}.phar" in the current working + * directory; return a string to exec it if it is + * found. Otherwise, look for an executable command + * of the same name via findExecutable. + * + * @param string $cmd + * + * @return bool|string + */ + protected function findExecutablePhar($cmd) + { + if (file_exists("{$cmd}.phar")) { + return "php {$cmd}.phar"; + } + return $this->findExecutable($cmd); + } + + /** + * Return the best path to the executable program + * with the provided name. Favor vendor/bin in the + * current project. If not found there, use + * whatever is on the $PATH. + * + * @param string $cmd + * + * @return bool|string + */ + protected function findExecutable($cmd) + { + $pathToCmd = $this->searchForExecutable($cmd); + if ($pathToCmd) { + return $this->useCallOnWindows($pathToCmd); + } + return false; + } + + /** + * @param string $cmd + * + * @return string + */ + private function searchForExecutable($cmd) + { + $projectBin = $this->findProjectBin(); + + $localComposerInstallation = $projectBin . DIRECTORY_SEPARATOR . $cmd; + if (file_exists($localComposerInstallation)) { + return $localComposerInstallation; + } + $finder = new ExecutableFinder(); + return $finder->find($cmd, null, []); + } + + /** + * @return bool|string + */ + protected function findProjectBin() + { + $cwd = getcwd(); + $candidates = [ __DIR__ . '/../../vendor/bin', __DIR__ . '/../../bin', $cwd . '/vendor/bin' ]; + + // If this project is inside a vendor directory, give highest priority + // to that directory. + $vendorDirContainingUs = realpath(__DIR__ . '/../../../..'); + if (is_dir($vendorDirContainingUs) && (basename($vendorDirContainingUs) == 'vendor')) { + array_unshift($candidates, $vendorDirContainingUs . '/bin'); + } + + foreach ($candidates as $dir) { + if (is_dir("$dir")) { + return realpath($dir); + } + } + return false; + } + + /** + * Wrap Windows executables in 'call' per 7a88757d + * + * @param string $cmd + * + * @return string + */ + protected function useCallOnWindows($cmd) + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + if (file_exists("{$cmd}.bat")) { + $cmd = "{$cmd}.bat"; + } + return "call $cmd"; + } + return $cmd; + } + + protected function getCommandDescription() + { + return $this->process->getCommandLine(); + } + + /** + * @param string $command + * + * @return \Robo\Result + */ + protected function executeCommand($command) + { + // TODO: Symfony 4 requires that we supply the working directory. + $result_data = $this->execute(new Process($command, getcwd())); + return new Result( + $this, + $result_data->getExitCode(), + $result_data->getMessage(), + $result_data->getData() + ); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecOneCommand.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecOneCommand.php new file mode 100644 index 00000000..60137514 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ExecOneCommand.php @@ -0,0 +1,12 @@ +interactive() based on posix_isatty(). + * + * @return $this + */ + public function detectInteractive() + { + // If the caller did not explicity set the 'interactive' mode, + // and output should be produced by this task (verbosityMeetsThreshold), + // then we will automatically set interactive mode based on whether + // or not output was redirected when robo was executed. + if (!isset($this->interactive) && function_exists('posix_isatty') && $this->verbosityMeetsThreshold()) { + $this->interactive = posix_isatty(STDOUT); + } + + return $this; + } + + /** + * Executes command in background mode (asynchronously) + * + * @return $this + */ + public function background($arg = true) + { + $this->background = $arg; + return $this; + } + + /** + * Stop command if it runs longer then $timeout in seconds + * + * @param int $timeout + * + * @return $this + */ + public function timeout($timeout) + { + $this->timeout = $timeout; + return $this; + } + + /** + * Stops command if it does not output something for a while + * + * @param int $timeout + * + * @return $this + */ + public function idleTimeout($timeout) + { + $this->idleTimeout = $timeout; + return $this; + } + + /** + * Set a single environment variable, or multiple. + */ + public function env($env, $value = null) + { + if (!is_array($env)) { + $env = [$env => ($value ? $value : true)]; + } + return $this->envVars($env); + } + + /** + * Sets the environment variables for the command + * + * @param array $env + * + * @return $this + */ + public function envVars(array $env) + { + $this->env = $env; + return $this; + } + + /** + * Pass an input to the process. Can be resource created with fopen() or string + * + * @param resource|string $input + * + * @return $this + */ + public function setInput($input) + { + $this->input = $input; + return $this; + } + + /** + * Attach tty to process for interactive input + * + * @param $interactive bool + * + * @return $this + */ + public function interactive($interactive = true) + { + $this->interactive = $interactive; + return $this; + } + + + /** + * Is command printing its output to screen + * + * @return bool + */ + public function getPrinted() + { + return $this->isPrinted; + } + + /** + * Changes working directory of command + * + * @param string $dir + * + * @return $this + */ + public function dir($dir) + { + $this->workingDirectory = $dir; + return $this; + } + + /** + * Shortcut for setting isPrinted() and isMetadataPrinted() to false. + * + * @param bool $arg + * + * @return $this + */ + public function silent($arg) + { + if (is_bool($arg)) { + $this->isPrinted = !$arg; + $this->isMetadataPrinted = !$arg; + } + return $this; + } + + /** + * Should command output be printed + * + * @param bool $arg + * + * @return $this + * + * @deprecated + */ + public function printed($arg) + { + $this->logger->warning("printed() is deprecated. Please use printOutput()."); + return $this->printOutput($arg); + } + + /** + * Should command output be printed + * + * @param bool $arg + * + * @return $this + */ + public function printOutput($arg) + { + if (is_bool($arg)) { + $this->isPrinted = $arg; + } + return $this; + } + + /** + * Should command metadata be printed. I,e., command and timer. + * + * @param bool $arg + * + * @return $this + */ + public function printMetadata($arg) + { + if (is_bool($arg)) { + $this->isMetadataPrinted = $arg; + } + return $this; + } + + /** + * @param Process $process + * @param callable $output_callback + * + * @return \Robo\ResultData + */ + protected function execute($process, $output_callback = null) + { + $this->process = $process; + + if (!$output_callback) { + $output_callback = function ($type, $buffer) { + $progressWasVisible = $this->hideTaskProgress(); + $this->writeMessage($buffer); + $this->showTaskProgress($progressWasVisible); + }; + } + + $this->detectInteractive(); + + if ($this->isMetadataPrinted) { + $this->printAction(); + } + $this->process->setTimeout($this->timeout); + $this->process->setIdleTimeout($this->idleTimeout); + if ($this->workingDirectory) { + $this->process->setWorkingDirectory($this->workingDirectory); + } + if ($this->input) { + $this->process->setInput($this->input); + } + + if ($this->interactive && $this->isPrinted) { + $this->process->setTty(true); + } + + if (isset($this->env)) { + $this->process->setEnv($this->env); + } + + if (!$this->background && !$this->isPrinted) { + $this->startTimer(); + $this->process->run(); + $this->stopTimer(); + $output = rtrim($this->process->getOutput()); + return new ResultData( + $this->process->getExitCode(), + $output, + $this->getResultData() + ); + } + + if (!$this->background && $this->isPrinted) { + $this->startTimer(); + $this->process->run($output_callback); + $this->stopTimer(); + return new ResultData( + $this->process->getExitCode(), + $this->process->getOutput(), + $this->getResultData() + ); + } + + try { + $this->process->start(); + } catch (\Exception $e) { + return new ResultData( + $this->process->getExitCode(), + $e->getMessage(), + $this->getResultData() + ); + } + return new ResultData($this->process->getExitCode()); + } + + /** + * + */ + protected function stop() + { + if ($this->background && isset($this->process) && $this->process->isRunning()) { + $this->process->stop(); + $this->printTaskInfo( + "Stopped {command}", + ['command' => $this->getCommandDescription()] + ); + } + } + + /** + * @param array $context + */ + protected function printAction($context = []) + { + $command = $this->getCommandDescription(); + $formatted_command = $this->formatCommandDisplay($command); + + $dir = $this->workingDirectory ? " in {dir}" : ""; + $this->printTaskInfo("Running {command}$dir", [ + 'command' => $formatted_command, + 'dir' => $this->workingDirectory + ] + $context); + } + + /** + * @param $command + * + * @return mixed + */ + protected function formatCommandDisplay($command) + { + $formatted_command = str_replace("&&", "&&\n", $command); + $formatted_command = str_replace("||", "||\n", $formatted_command); + + return $formatted_command; + } + + /** + * Gets the data array to be passed to Result(). + * + * @return array + * The data array passed to Result(). + */ + protected function getResultData() + { + if ($this->isMetadataPrinted) { + return ['time' => $this->getExecutionTime()]; + } + + return []; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/IO.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/IO.php new file mode 100644 index 00000000..d6c77bff --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/IO.php @@ -0,0 +1,171 @@ +io) { + $this->io = new SymfonyStyle($this->input(), $this->output()); + } + return $this->io; + } + + /** + * @param string $nonDecorated + * @param string $decorated + * + * @return string + */ + protected function decorationCharacter($nonDecorated, $decorated) + { + if (!$this->output()->isDecorated() || (strncasecmp(PHP_OS, 'WIN', 3) == 0)) { + return $nonDecorated; + } + return $decorated; + } + + /** + * @param string $text + */ + protected function say($text) + { + $char = $this->decorationCharacter('>', 'âžœ'); + $this->writeln("$char $text"); + } + + /** + * @param string $text + * @param int $length + * @param string $color + */ + protected function yell($text, $length = 40, $color = 'green') + { + $char = $this->decorationCharacter(' ', 'âžœ'); + $format = "$char %s"; + $this->formattedOutput($text, $length, $format); + } + + /** + * @param string $text + * @param int $length + * @param string $format + */ + protected function formattedOutput($text, $length, $format) + { + $lines = explode("\n", trim($text, "\n")); + $maxLineLength = array_reduce(array_map('strlen', $lines), 'max'); + $length = max($length, $maxLineLength); + $len = $length + 2; + $space = str_repeat(' ', $len); + $this->writeln(sprintf($format, $space)); + foreach ($lines as $line) { + $line = str_pad($line, $length, ' ', STR_PAD_BOTH); + $this->writeln(sprintf($format, " $line ")); + } + $this->writeln(sprintf($format, $space)); + } + + /** + * @param string $question + * @param bool $hideAnswer + * + * @return string + */ + protected function ask($question, $hideAnswer = false) + { + if ($hideAnswer) { + return $this->askHidden($question); + } + return $this->doAsk(new Question($this->formatQuestion($question))); + } + + /** + * @param string $question + * + * @return string + */ + protected function askHidden($question) + { + $question = new Question($this->formatQuestion($question)); + $question->setHidden(true); + return $this->doAsk($question); + } + + /** + * @param string $question + * @param string $default + * + * @return string + */ + protected function askDefault($question, $default) + { + return $this->doAsk(new Question($this->formatQuestion("$question [$default]"), $default)); + } + + /** + * @param string $question + * + * @return string + */ + protected function confirm($question) + { + return $this->doAsk(new ConfirmationQuestion($this->formatQuestion($question . ' (y/n)'), false)); + } + + /** + * @param \Symfony\Component\Console\Question\Question $question + * + * @return string + */ + protected function doAsk(Question $question) + { + return $this->getDialog()->ask($this->input(), $this->output(), $question); + } + + /** + * @param string $message + * + * @return string + */ + protected function formatQuestion($message) + { + return "? $message "; + } + + /** + * @return \Symfony\Component\Console\Helper\QuestionHelper + */ + protected function getDialog() + { + return new QuestionHelper(); + } + + /** + * @param $text + */ + protected function writeln($text) + { + $this->output()->writeln($text); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/InflectionTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/InflectionTrait.php new file mode 100644 index 00000000..8bc4e831 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/InflectionTrait.php @@ -0,0 +1,21 @@ +injectDependencies($this); + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/InputAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/InputAwareTrait.php new file mode 100644 index 00000000..bae58c17 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/InputAwareTrait.php @@ -0,0 +1,51 @@ +input = $input; + + return $this; + } + + /** + * @return \Symfony\Component\Console\Input\InputInterface + */ + protected function input() + { + if (!isset($this->input)) { + $this->setInput(new ArgvInput()); + } + return $this->input; + } + + /** + * Backwards compatibility. + * + * @return \Symfony\Component\Console\Input\InputInterface + * + * @deprecated + */ + protected function getInput() + { + return $this->input(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/OutputAdapter.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/OutputAdapter.php new file mode 100644 index 00000000..b8e795f2 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/OutputAdapter.php @@ -0,0 +1,38 @@ + OutputInterface::VERBOSITY_NORMAL, + VerbosityThresholdInterface::VERBOSITY_VERBOSE => OutputInterface::VERBOSITY_VERBOSE, + VerbosityThresholdInterface::VERBOSITY_VERY_VERBOSE => OutputInterface::VERBOSITY_VERY_VERBOSE, + VerbosityThresholdInterface::VERBOSITY_DEBUG => OutputInterface::VERBOSITY_DEBUG, + ]; + + public function verbosityMeetsThreshold($verbosityThreshold) + { + if (!isset($this->verbosityMap[$verbosityThreshold])) { + return true; + } + $verbosityThreshold = $this->verbosityMap[$verbosityThreshold]; + $verbosity = $this->output()->getVerbosity(); + + return $verbosity >= $verbosityThreshold; + } + + public function writeMessage($message) + { + $this->output()->write($message); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/OutputAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/OutputAwareTrait.php new file mode 100644 index 00000000..48082cb3 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/OutputAwareTrait.php @@ -0,0 +1,51 @@ +output = $output; + + return $this; + } + + /** + * @return \Symfony\Component\Console\Output\OutputInterface + */ + protected function output() + { + if (!isset($this->output)) { + $this->setOutput(new NullOutput()); + } + return $this->output; + } + + /** + * Backwards compatibility + * + * @return \Symfony\Component\Console\Output\OutputInterface + * + * @deprecated + */ + protected function getOutput() + { + return $this->output(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProcessExecutor.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProcessExecutor.php new file mode 100644 index 00000000..f78a4775 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProcessExecutor.php @@ -0,0 +1,51 @@ +process = $process; + } + + public static function create($container, $process) + { + $processExecutor = new self($process); + + $processExecutor->setLogger($container->get('logger')); + $processExecutor->setProgressIndicator($container->get('progressIndicator')); + $processExecutor->setConfig($container->get('config')); + $processExecutor->setOutputAdapter($container->get('outputAdapter')); + + return $processExecutor; + } + + /** + * @return string + */ + protected function getCommandDescription() + { + return $this->process->getCommandLine(); + } + + public function run() + { + return $this->execute($this->process); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProcessUtils.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProcessUtils.php new file mode 100644 index 00000000..7dc4e553 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProcessUtils.php @@ -0,0 +1,79 @@ + + */ + +namespace Robo\Common; + +use Symfony\Component\Process\Exception\InvalidArgumentException; + +/** + * ProcessUtils is a bunch of utility methods. We want to allow Robo 1.x + * to work with Symfony 4.x while remaining backwards compatibility. This + * requires us to replace some deprecated functionality removed in Symfony. + */ +class ProcessUtils +{ + /** + * This class should not be instantiated. + */ + private function __construct() + { + } + + /** + * Escapes a string to be used as a shell argument. + * + * @param string $argument The argument that will be escaped + * + * @return string The escaped argument + * + * @deprecated since version 3.3, to be removed in 4.0. Use a command line array or give env vars to the `Process::start/run()` method instead. + */ + public static function escapeArgument($argument) + { + @trigger_error('The '.__METHOD__.'() method is a copy of a method that was deprecated by Symfony 3.3 and removed in Symfony 4; it will be removed in Robo 2.0.', E_USER_DEPRECATED); + + //Fix for PHP bug #43784 escapeshellarg removes % from given string + //Fix for PHP bug #49446 escapeshellarg doesn't work on Windows + //@see https://bugs.php.net/bug.php?id=43784 + //@see https://bugs.php.net/bug.php?id=49446 + if ('\\' === DIRECTORY_SEPARATOR) { + if ('' === $argument) { + return escapeshellarg($argument); + } + + $escapedArgument = ''; + $quote = false; + foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) { + if ('"' === $part) { + $escapedArgument .= '\\"'; + } elseif (self::isSurroundedBy($part, '%')) { + // Avoid environment variable expansion + $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%'; + } else { + // escape trailing backslash + if ('\\' === substr($part, -1)) { + $part .= '\\'; + } + $quote = true; + $escapedArgument .= $part; + } + } + if ($quote) { + $escapedArgument = '"'.$escapedArgument.'"'; + } + + return $escapedArgument; + } + + return "'".str_replace("'", "'\\''", $argument)."'"; + } + + private static function isSurroundedBy($arg, $char) + { + return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1]; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProgressIndicator.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProgressIndicator.php new file mode 100644 index 00000000..050250e5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProgressIndicator.php @@ -0,0 +1,201 @@ +progressBar = $progressBar; + $this->output = $output; + } + + /** + * @param int $interval + */ + public function setProgressBarAutoDisplayInterval($interval) + { + if ($this->progressIndicatorRunning) { + return; + } + $this->autoDisplayInterval = $interval; + } + + /** + * @return bool + */ + public function hideProgressIndicator() + { + $result = $this->progressBarDisplayed; + if ($this->progressIndicatorRunning && $this->progressBarDisplayed) { + $this->progressBar->clear(); + // Hack: progress indicator does not reset cursor to beginning of line on 'clear' + $this->output->write("\x0D"); + $this->progressBarDisplayed = false; + } + return $result; + } + + public function showProgressIndicator() + { + if ($this->progressIndicatorRunning && !$this->progressBarDisplayed && isset($this->progressBar)) { + $this->progressBar->display(); + $this->progressBarDisplayed = true; + $this->advanceProgressIndicatorCachedSteps(); + } + } + + /** + * @param bool $visible + */ + public function restoreProgressIndicator($visible) + { + if ($visible) { + $this->showProgressIndicator(); + } + } + + /** + * @param int $totalSteps + * @param \Robo\Contract\TaskInterface $owner + */ + public function startProgressIndicator($totalSteps, $owner) + { + if (!isset($this->progressBar)) { + return; + } + + $this->progressIndicatorRunning = true; + if (!isset($this->owner)) { + $this->owner = $owner; + $this->startTimer(); + $this->totalSteps = $totalSteps; + $this->autoShowProgressIndicator(); + } + } + + public function autoShowProgressIndicator() + { + if (($this->autoDisplayInterval < 0) || !isset($this->progressBar) || !$this->output->isDecorated()) { + return; + } + if ($this->autoDisplayInterval <= $this->getExecutionTime()) { + $this->autoDisplayInterval = -1; + $this->progressBar->start($this->totalSteps); + $this->showProgressIndicator(); + } + } + + /** + * @return bool + */ + public function inProgress() + { + return $this->progressIndicatorRunning; + } + + /** + * @param \Robo\Contract\TaskInterface $owner + */ + public function stopProgressIndicator($owner) + { + if ($this->progressIndicatorRunning && ($this->owner === $owner)) { + $this->cleanup(); + } + } + + protected function cleanup() + { + $this->progressIndicatorRunning = false; + $this->owner = null; + if ($this->progressBarDisplayed) { + $this->progressBar->finish(); + // Hack: progress indicator does not always finish cleanly + $this->output->writeln(''); + $this->progressBarDisplayed = false; + } + $this->stopTimer(); + } + + /** + * Erase progress indicator and ensure it never returns. Used + * only during error handlers. + */ + public function disableProgressIndicator() + { + $this->cleanup(); + // ProgressIndicator is shared, so this permanently removes + // the program's ability to display progress bars. + $this->progressBar = null; + } + + /** + * @param int $steps + */ + public function advanceProgressIndicator($steps = 1) + { + $this->cachedSteps += $steps; + if ($this->progressIndicatorRunning) { + $this->autoShowProgressIndicator(); + // We only want to call `advance` if the progress bar is visible, + // because it always displays itself when it is advanced. + if ($this->progressBarDisplayed) { + return $this->advanceProgressIndicatorCachedSteps(); + } + } + } + + protected function advanceProgressIndicatorCachedSteps() + { + $this->progressBar->advance($this->cachedSteps); + $this->cachedSteps = 0; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProgressIndicatorAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProgressIndicatorAwareTrait.php new file mode 100644 index 00000000..060e039a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ProgressIndicatorAwareTrait.php @@ -0,0 +1,135 @@ +progressIndicator = $progressIndicator; + + return $this; + } + + /** + * @return null|bool + */ + protected function hideProgressIndicator() + { + if (!$this->progressIndicator) { + return; + } + return $this->progressIndicator->hideProgressIndicator(); + } + + protected function showProgressIndicator() + { + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->showProgressIndicator(); + } + + /** + * @param bool $visible + */ + protected function restoreProgressIndicator($visible) + { + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->restoreProgressIndicator($visible); + } + + /** + * @return int + */ + protected function getTotalExecutionTime() + { + if (!$this->progressIndicator) { + return 0; + } + return $this->progressIndicator->getExecutionTime(); + } + + protected function startProgressIndicator() + { + $this->startTimer(); + if ($this instanceof VerbosityThresholdInterface + && !$this->verbosityMeetsThreshold()) { + return; + } + if (!$this->progressIndicator) { + return; + } + $totalSteps = $this->progressIndicatorSteps(); + $this->progressIndicator->startProgressIndicator($totalSteps, $this); + } + + /** + * @return bool + */ + protected function inProgress() + { + if (!$this->progressIndicator) { + return false; + } + return $this->progressIndicator->inProgress(); + } + + protected function stopProgressIndicator() + { + $this->stopTimer(); + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->stopProgressIndicator($this); + } + + protected function disableProgressIndicator() + { + $this->stopTimer(); + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->disableProgressIndicator(); + } + + protected function detatchProgressIndicator() + { + $this->setProgressIndicator(null); + } + + /** + * @param int $steps + */ + protected function advanceProgressIndicator($steps = 1) + { + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->advanceProgressIndicator($steps); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ResourceExistenceChecker.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ResourceExistenceChecker.php new file mode 100644 index 00000000..233f90a9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/ResourceExistenceChecker.php @@ -0,0 +1,116 @@ +printTaskError(sprintf('Invalid glob "%s"!', $resource), $this); + $success = false; + continue; + } + foreach ($glob as $resource) { + if (!$this->checkResource($resource, $type)) { + $success = false; + } + } + } + return $success; + } + + /** + * Checks a single resource, file or directory. + * + * It will print an error as well on the console. + * + * @param string $resource File or folder. + * @param string $type "file", "dir", "fileAndDir" + * + * @return bool + */ + protected function checkResource($resource, $type) + { + switch ($type) { + case 'file': + if (!$this->isFile($resource)) { + $this->printTaskError(sprintf('File "%s" does not exist!', $resource), $this); + return false; + } + return true; + case 'dir': + if (!$this->isDir($resource)) { + $this->printTaskError(sprintf('Directory "%s" does not exist!', $resource), $this); + return false; + } + return true; + case 'fileAndDir': + if (!$this->isDir($resource) && !$this->isFile($resource)) { + $this->printTaskError(sprintf('File or directory "%s" does not exist!', $resource), $this); + return false; + } + return true; + } + } + + /** + * Convenience method to check the often uses "source => target" file / folder arrays. + * + * @param string|array $resources + */ + protected function checkSourceAndTargetResource($resources) + { + if (is_string($resources)) { + $resources = [$resources]; + } + $sources = []; + $targets = []; + foreach ($resources as $source => $target) { + $sources[] = $source; + $target[] = $target; + } + $this->checkResources($sources); + $this->checkResources($targets); + } + + /** + * Wrapper method around phps is_dir() + * + * @param string $directory + * + * @return bool + */ + protected function isDir($directory) + { + return is_dir($directory); + } + + /** + * Wrapper method around phps file_exists() + * + * @param string $file + * + * @return bool + */ + protected function isFile($file) + { + return file_exists($file); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/TaskIO.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/TaskIO.php new file mode 100644 index 00000000..49b5ccd8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/TaskIO.php @@ -0,0 +1,237 @@ +logger should always be set in Robo core tasks. + if ($this->logger) { + return $this->logger; + } + + // TODO: Remove call to Robo::logger() once maintaining backwards + // compatibility with legacy external Robo tasks is no longer desired. + if (!Robo::logger()) { + return null; + } + + static $gaveDeprecationWarning = false; + if (!$gaveDeprecationWarning) { + trigger_error('No logger set for ' . get_class($this) . '. Use $this->task(Foo::class) rather than new Foo() in loadTasks to ensure the builder can initialize task the task, or use $this->collectionBuilder()->taskFoo() if creating one task from within another.', E_USER_DEPRECATED); + $gaveDeprecationWarning = true; + } + return Robo::logger(); + } + + /** + * Print information about a task in progress. + * + * With the Symfony Console logger, NOTICE is displayed at VERBOSITY_VERBOSE + * and INFO is displayed at VERBOSITY_VERY_VERBOSE. + * + * Robo overrides the default such that NOTICE is displayed at + * VERBOSITY_NORMAL and INFO is displayed at VERBOSITY_VERBOSE. + * + * n.b. We should probably have printTaskNotice for our ordinary + * output, and use printTaskInfo for less interesting messages. + * + * @param string $text + * @param null|array $context + */ + protected function printTaskInfo($text, $context = null) + { + // The 'note' style is used for both 'notice' and 'info' log levels; + // However, 'notice' is printed at VERBOSITY_NORMAL, whereas 'info' + // is only printed at VERBOSITY_VERBOSE. + $this->printTaskOutput(LogLevel::NOTICE, $text, $this->getTaskContext($context)); + } + + /** + * Provide notification that some part of the task succeeded. + * + * With the Symfony Console logger, success messages are remapped to NOTICE, + * and displayed in VERBOSITY_VERBOSE. When used with the Robo logger, + * success messages are displayed at VERBOSITY_NORMAL. + * + * @param string $text + * @param null|array $context + */ + protected function printTaskSuccess($text, $context = null) + { + // Not all loggers will recognize ConsoleLogLevel::SUCCESS. + // We therefore log as LogLevel::NOTICE, and apply a '_level' + // override in the context so that this message will be + // logged as SUCCESS if that log level is recognized. + $context['_level'] = ConsoleLogLevel::SUCCESS; + $this->printTaskOutput(LogLevel::NOTICE, $text, $this->getTaskContext($context)); + } + + /** + * Provide notification that there is something wrong, but + * execution can continue. + * + * Warning messages are displayed at VERBOSITY_NORMAL. + * + * @param string $text + * @param null|array $context + */ + protected function printTaskWarning($text, $context = null) + { + $this->printTaskOutput(LogLevel::WARNING, $text, $this->getTaskContext($context)); + } + + /** + * Provide notification that some operation in the task failed, + * and the task cannot continue. + * + * Error messages are displayed at VERBOSITY_NORMAL. + * + * @param string $text + * @param null|array $context + */ + protected function printTaskError($text, $context = null) + { + $this->printTaskOutput(LogLevel::ERROR, $text, $this->getTaskContext($context)); + } + + /** + * Provide debugging notification. These messages are only + * displayed if the log level is VERBOSITY_DEBUG. + * + * @param string$text + * @param null|array $context + */ + protected function printTaskDebug($text, $context = null) + { + $this->printTaskOutput(LogLevel::DEBUG, $text, $this->getTaskContext($context)); + } + + /** + * @param string $level + * One of the \Psr\Log\LogLevel constant + * @param string $text + * @param null|array $context + */ + protected function printTaskOutput($level, $text, $context) + { + if (!$this->verbosityMeetsThreshold()) { + return; + } + $logger = $this->logger(); + if (!$logger) { + return; + } + // Hide the progress indicator, if it is visible. + $inProgress = $this->hideTaskProgress(); + $logger->log($level, $text, $this->getTaskContext($context)); + // After we have printed our log message, redraw the progress indicator. + $this->showTaskProgress($inProgress); + } + + /** + * @return bool + */ + protected function hideTaskProgress() + { + $inProgress = false; + if ($this instanceof ProgressIndicatorAwareInterface) { + $inProgress = $this->inProgress(); + } + + // If a progress indicator is running on this task, then we mush + // hide it before we print anything, or its display will be overwritten. + if ($inProgress) { + $inProgress = $this->hideProgressIndicator(); + } + return $inProgress; + } + + /** + * @param $inProgress + */ + protected function showTaskProgress($inProgress) + { + if ($inProgress) { + $this->restoreProgressIndicator($inProgress); + } + } + + /** + * Format a quantity of bytes. + * + * @param int $size + * @param int $precision + * + * @return string + */ + protected function formatBytes($size, $precision = 2) + { + if ($size === 0) { + return 0; + } + $base = log($size, 1024); + $suffixes = array('', 'k', 'M', 'G', 'T'); + return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)]; + } + + /** + * Get the formatted task name for use in task output. + * This is placed in the task context under 'name', and + * used as the log label by Robo\Common\RoboLogStyle, + * which is inserted at the head of log messages by + * Robo\Common\CustomLogStyle::formatMessage(). + * + * @param null|object $task + * + * @return string + */ + protected function getPrintedTaskName($task = null) + { + if (!$task) { + $task = $this; + } + return TaskInfo::formatTaskName($task); + } + + /** + * @param null|array $context + * + * @return array with context information + */ + protected function getTaskContext($context = null) + { + if (!$context) { + $context = []; + } + if (!is_array($context)) { + $context = ['task' => $context]; + } + if (!array_key_exists('task', $context)) { + $context['task'] = $this; + } + + return $context + TaskInfo::getTaskContext($context['task']); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/TimeKeeper.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/TimeKeeper.php new file mode 100644 index 00000000..1cd3e334 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/TimeKeeper.php @@ -0,0 +1,69 @@ +startedAt) { + return; + } + // Get time in seconds as a float, accurate to the microsecond. + $this->startedAt = microtime(true); + } + + public function stop() + { + $this->finishedAt = microtime(true); + } + + /** + * @return float|null + */ + public function elapsed() + { + $finished = $this->finishedAt ? $this->finishedAt : microtime(true); + if ($finished - $this->startedAt <= 0) { + return null; + } + return $finished - $this->startedAt; + } + + /** + * Format a duration into a human-readable time + * + * @param float $duration Duration in seconds, with fractional component + * + * @return string + */ + public static function formatDuration($duration) + { + if ($duration >= self::DAY * 2) { + return gmdate('z \d\a\y\s H:i:s', $duration); + } + if ($duration > self::DAY) { + return gmdate('\1 \d\a\y H:i:s', $duration); + } + if ($duration > self::HOUR) { + return gmdate("H:i:s", $duration); + } + if ($duration > self::MINUTE) { + return gmdate("i:s", $duration); + } + return round($duration, 3).'s'; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/Timer.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/Timer.php new file mode 100644 index 00000000..955eb5bb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/Timer.php @@ -0,0 +1,37 @@ +timer)) { + $this->timer = new TimeKeeper(); + } + $this->timer->start(); + } + + protected function stopTimer() + { + if (!isset($this->timer)) { + return; + } + $this->timer->stop(); + } + + /** + * @return float|null + */ + protected function getExecutionTime() + { + if (!isset($this->timer)) { + return null; + } + return $this->timer->elapsed(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/VerbosityThresholdTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/VerbosityThresholdTrait.php new file mode 100644 index 00000000..2fc51c22 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Common/VerbosityThresholdTrait.php @@ -0,0 +1,79 @@ +verbosityThreshold = $verbosityThreshold; + return $this; + } + + public function verbosityThreshold() + { + return $this->verbosityThreshold; + } + + public function setOutputAdapter(OutputAdapterInterface $outputAdapter) + { + $this->outputAdapter = $outputAdapter; + } + + /** + * @return OutputAdapterInterface + */ + public function outputAdapter() + { + return $this->outputAdapter; + } + + public function hasOutputAdapter() + { + return isset($this->outputAdapter); + } + + public function verbosityMeetsThreshold() + { + if ($this->hasOutputAdapter()) { + return $this->outputAdapter()->verbosityMeetsThreshold($this->verbosityThreshold()); + } + return true; + } + + /** + * Print a message if the selected verbosity level is over this task's + * verbosity threshhold. + */ + public function writeMessage($message) + { + if (!$this->verbosityMeetsThreshold()) { + return; + } + $this->outputAdapter()->writeMessage($message); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config.php new file mode 100644 index 00000000..9e9370d8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config.php @@ -0,0 +1,9 @@ +defaults = $this->getGlobalOptionDefaultValues(); + } + + /** + * Return an associative array containing all of the global configuration + * options and their default values. + * + * @return array + */ + public function getGlobalOptionDefaultValues() + { + $globalOptions = + [ + self::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL => self::DEFAULT_PROGRESS_DELAY, + self::SIMULATE => false, + ]; + return $this->trimPrefixFromGlobalOptions($globalOptions); + } + + /** + * Remove the 'options.' prefix from the global options list. + */ + protected function trimPrefixFromGlobalOptions($globalOptions) + { + $result = []; + foreach ($globalOptions as $option => $value) { + $option = str_replace('options.', '', $option); + $result[$option] = $value; + } + return $result; + } + + /** + * @deprecated Use $config->get(Config::SIMULATE) + * + * @return bool + */ + public function isSimulated() + { + return $this->get(self::SIMULATE); + } + + /** + * @deprecated Use $config->set(Config::SIMULATE, true) + * + * @param bool $simulated + * + * @return $this + */ + public function setSimulated($simulated = true) + { + return $this->set(self::SIMULATE, $simulated); + } + + /** + * @deprecated Use $config->get(Config::INTERACTIVE) + * + * @return bool + */ + public function isInteractive() + { + return $this->get(self::INTERACTIVE); + } + + /** + * @deprecated Use $config->set(Config::INTERACTIVE, true) + * + * @param bool $interactive + * + * @return $this + */ + public function setInteractive($interactive = true) + { + return $this->set(self::INTERACTIVE, $interactive); + } + + /** + * @deprecated Use $config->get(Config::DECORATED) + * + * @return bool + */ + public function isDecorated() + { + return $this->get(self::DECORATED); + } + + /** + * @deprecated Use $config->set(Config::DECORATED, true) + * + * @param bool $decorated + * + * @return $this + */ + public function setDecorated($decorated = true) + { + return $this->set(self::DECORATED, $decorated); + } + + /** + * @deprecated Use $config->set(Config::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL, $interval) + * + * @param int $interval + * + * @return $this + */ + public function setProgressBarAutoDisplayInterval($interval) + { + return $this->set(self::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL, $interval); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config/GlobalOptionDefaultValuesInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config/GlobalOptionDefaultValuesInterface.php new file mode 100644 index 00000000..f7639455 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Config/GlobalOptionDefaultValuesInterface.php @@ -0,0 +1,17 @@ +inflect($this) + * ->initializer() + * ->... + * + * Instead of: + * + * (new SomeTask($args)) + * ->setLogger($this->logger) + * ->initializer() + * ->... + * + * The reason `inflect` is better than the more explicit alternative is + * that subclasses of BaseTask that implement a new FooAwareInterface + * can override injectDependencies() as explained below, and add more + * dependencies that can be injected as needed. + * + * @param \Robo\Contract\InflectionInterface $parent + */ + public function inflect(InflectionInterface $parent); + + /** + * Take all dependencies availble to this task and inject any that are + * needed into the provided task. The general pattern is that, for every + * FooAwareInterface that this class implements, it should test to see + * if the child also implements the same interface, and if so, should call + * $child->setFoo($this->foo). + * + * The benefits of this are pretty large. Any time an object that implements + * InflectionInterface is created, just call `$child->inflect($this)`, and + * any available optional dependencies will be hooked up via setter injection. + * + * The required dependencies of an object should be provided via constructor + * injection, not inflection. + * + * @param InflectionInterface $child An object created by this class that + * should have its dependencies injected. + * + * @see https://mwop.net/blog/2016-04-26-on-locators.html + */ + public function injectDependencies(InflectionInterface $child); +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/OutputAdapterInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/OutputAdapterInterface.php new file mode 100644 index 00000000..948d384c --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Contract/OutputAdapterInterface.php @@ -0,0 +1,11 @@ +prefix = 'options'; + } + + /** + * Add a reference to the Symfony Console application object. + */ + public function setApplication($application) + { + $this->application = $application; + return $this; + } + + /** + * Stipulate the prefix to use for option injection. + * @param string $prefix + */ + public function setGlobalOptionsPrefix($prefix) + { + $this->prefix = $prefix; + return $this; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ConsoleEvents::COMMAND => 'handleCommandEvent']; + } + + /** + * Run all of our individual operations when a command event is received. + */ + public function handleCommandEvent(ConsoleCommandEvent $event) + { + $this->setGlobalOptions($event); + $this->setConfigurationValues($event); + } + + /** + * Before a Console command runs, examine the global + * commandline options from the event Input, and set + * configuration values as appropriate. + * + * @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event + */ + public function setGlobalOptions(ConsoleCommandEvent $event) + { + $config = $this->getConfig(); + $input = $event->getInput(); + + $globalOptions = $config->get($this->prefix, []); + if ($config instanceof \Consolidation\Config\GlobalOptionDefaultValuesInterface) { + $globalOptions += $config->getGlobalOptionDefaultValues(); + } + + $globalOptions += $this->applicationOptionDefaultValues(); + + // Set any config value that has a defined global option (e.g. --simulate) + foreach ($globalOptions as $option => $default) { + $value = $input->hasOption($option) ? $input->getOption($option) : null; + // Unfortunately, the `?:` operator does not differentate between `0` and `null` + if (!isset($value)) { + $value = $default; + } + $config->set($this->prefix . '.' . $option, $value); + } + } + + /** + * Examine the commandline --define / -D options, and apply the provided + * values to the active configuration. + * + * @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event + */ + public function setConfigurationValues(ConsoleCommandEvent $event) + { + $config = $this->getConfig(); + $input = $event->getInput(); + + // Also set any `-D config.key=value` options from the commandline. + if ($input->hasOption('define')) { + $configDefinitions = $input->getOption('define'); + foreach ($configDefinitions as $value) { + list($key, $value) = $this->splitConfigKeyValue($value); + $config->set($key, $value); + } + } + } + + /** + * Split up the key=value config setting into its component parts. If + * the input string contains no '=' character, then the value will be 'true'. + * + * @param string $value + * @return array + */ + protected function splitConfigKeyValue($value) + { + $parts = explode('=', $value, 2); + $parts[] = true; + return $parts; + } + + /** + * Get default option values from the Symfony Console application, if + * it is available. + */ + protected function applicationOptionDefaultValues() + { + if (!$this->application) { + return []; + } + + $result = []; + foreach ($this->application->getDefinition()->getOptions() as $key => $option) { + $result[$key] = $option->acceptValue() ? $option->getDefault() : null; + } + return $result; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/LoadAllTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/LoadAllTasks.php new file mode 100644 index 00000000..3183d5b6 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/LoadAllTasks.php @@ -0,0 +1,39 @@ +getTask(); + if ($task instanceof VerbosityThresholdInterface && !$task->verbosityMeetsThreshold()) { + return; + } + if (!$result->wasSuccessful()) { + return $this->printError($result); + } else { + return $this->printSuccess($result); + } + } + + /** + * Log that we are about to abort due to an error being encountered + * in 'stop on fail' mode. + * + * @param \Robo\Result $result + */ + public function printStopOnFail($result) + { + $this->printMessage(LogLevel::NOTICE, 'Stopping on fail. Exiting....'); + $this->printMessage(LogLevel::ERROR, 'Exit Code: {code}', ['code' => $result->getExitCode()]); + } + + /** + * Log the result of a Robo task that returned an error. + * + * @param \Robo\Result $result + * + * @return bool + */ + protected function printError(Result $result) + { + $task = $result->getTask(); + $context = $result->getContext() + ['timer-label' => 'Time', '_style' => []]; + $context['_style']['message'] = ''; + + $printOutput = true; + if ($task instanceof PrintedInterface) { + $printOutput = !$task->getPrinted(); + } + if ($printOutput) { + $this->printMessage(LogLevel::ERROR, "{message}", $context); + } + $this->printMessage(LogLevel::ERROR, 'Exit code {code}', $context); + return true; + } + + /** + * Log the result of a Robo task that was successful. + * + * @param \Robo\Result $result + * + * @return bool + */ + protected function printSuccess(Result $result) + { + $task = $result->getTask(); + $context = $result->getContext() + ['timer-label' => 'in']; + $time = $result->getExecutionTime(); + if ($time) { + $this->printMessage(ConsoleLogLevel::SUCCESS, 'Done', $context); + } + return false; + } + + /** + * @param string $level + * @param string $message + * @param array $context + */ + protected function printMessage($level, $message, $context = []) + { + $inProgress = $this->hideProgressIndicator(); + $this->logger->log($level, $message, $context); + if ($inProgress) { + $this->restoreProgressIndicator($inProgress); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogLevel.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogLevel.php new file mode 100644 index 00000000..d7d5eb0a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogLevel.php @@ -0,0 +1,11 @@ +labelStyles += [ + RoboLogLevel::SIMULATED_ACTION => self::TASK_STYLE_SIMULATED, + ]; + $this->messageStyles += [ + RoboLogLevel::SIMULATED_ACTION => '', + ]; + } + + /** + * Log style customization for Robo: replace the log level with + * the task name. + * + * @param string $level + * @param string $message + * @param array $context + * + * @return string + */ + protected function formatMessageByLevel($level, $message, $context) + { + $label = $level; + if (array_key_exists('name', $context)) { + $label = $context['name']; + } + return $this->formatMessage($label, $message, $context, $this->labelStyles[$level], $this->messageStyles[$level]); + } + + /** + * Log style customization for Robo: add the time indicator to the + * end of the log message if it exists in the context. + * + * @param string $label + * @param string $message + * @param array $context + * @param string $taskNameStyle + * @param string $messageStyle + * + * @return string + */ + protected function formatMessage($label, $message, $context, $taskNameStyle, $messageStyle = '') + { + $message = parent::formatMessage($label, $message, $context, $taskNameStyle, $messageStyle); + + if (array_key_exists('time', $context) && !empty($context['time']) && array_key_exists('timer-label', $context)) { + $duration = TimeKeeper::formatDuration($context['time']); + $message .= ' ' . $context['timer-label'] . ' ' . $this->wrapFormatString($duration, 'fg=yellow'); + } + + return $message; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogger.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogger.php new file mode 100644 index 00000000..75cf23f7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Log/RoboLogger.php @@ -0,0 +1,29 @@ + OutputInterface::VERBOSITY_NORMAL, // Default is "verbose" + LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL, // Default is "verbose" + LogLevel::INFO => OutputInterface::VERBOSITY_VERBOSE, // Default is "very verbose" + ]; + parent::__construct($output, $roboVerbosityOverrides); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Result.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Result.php new file mode 100644 index 00000000..7d779352 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Result.php @@ -0,0 +1,258 @@ +task = $task; + $this->printResult(); + + if (self::$stopOnFail) { + $this->stopOnFail(); + } + } + + /** + * Tasks should always return a Result. However, they are also + * allowed to return NULL or an array to indicate success. + */ + public static function ensureResult($task, $result) + { + if ($result instanceof Result) { + return $result; + } + if (!isset($result)) { + return static::success($task); + } + if ($result instanceof Data) { + return static::success($task, $result->getMessage(), $result->getData()); + } + if ($result instanceof ResultData) { + return new Result($task, $result->getExitCode(), $result->getMessage(), $result->getData()); + } + if (is_array($result)) { + return static::success($task, '', $result); + } + throw new \Exception(sprintf('Task %s returned a %s instead of a \Robo\Result.', get_class($task), get_class($result))); + } + + protected function printResult() + { + // For historic reasons, the Result constructor is responsible + // for printing task results. + // TODO: Make IO the responsibility of some other class. Maintaining + // existing behavior for backwards compatibility. This is undesirable + // in the long run, though, as it can result in unwanted repeated input + // in task collections et. al. + $resultPrinter = Robo::resultPrinter(); + if ($resultPrinter) { + if ($resultPrinter->printResult($this)) { + $this->alreadyPrinted(); + } + } + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param string $extension + * @param string $service + * + * @return \Robo\Result + */ + public static function errorMissingExtension(TaskInterface $task, $extension, $service) + { + $messageTpl = 'PHP extension required for %s. Please enable %s'; + $message = sprintf($messageTpl, $service, $extension); + + return self::error($task, $message); + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param string $class + * @param string $package + * + * @return \Robo\Result + */ + public static function errorMissingPackage(TaskInterface $task, $class, $package) + { + $messageTpl = 'Class %s not found. Please install %s Composer package'; + $message = sprintf($messageTpl, $class, $package); + + return self::error($task, $message); + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param string $message + * @param array $data + * + * @return \Robo\Result + */ + public static function error(TaskInterface $task, $message, $data = []) + { + return new self($task, self::EXITCODE_ERROR, $message, $data); + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param \Exception $e + * @param array $data + * + * @return \Robo\Result + */ + public static function fromException(TaskInterface $task, \Exception $e, $data = []) + { + $exitCode = $e->getCode(); + if (!$exitCode) { + $exitCode = self::EXITCODE_ERROR; + } + return new self($task, $exitCode, $e->getMessage(), $data); + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param string $message + * @param array $data + * + * @return \Robo\Result + */ + public static function success(TaskInterface $task, $message = '', $data = []) + { + return new self($task, self::EXITCODE_OK, $message, $data); + } + + /** + * Return a context useful for logging messages. + * + * @return array + */ + public function getContext() + { + $task = $this->getTask(); + + return TaskInfo::getTaskContext($task) + [ + 'code' => $this->getExitCode(), + 'data' => $this->getArrayCopy(), + 'time' => $this->getExecutionTime(), + 'message' => $this->getMessage(), + ]; + } + + /** + * Add the results from the most recent task to the accumulated + * results from all tasks that have run so far, merging data + * as necessary. + * + * @param int|string $key + * @param \Robo\Result $taskResult + */ + public function accumulate($key, Result $taskResult) + { + // If the task is unnamed, then all of its data elements + // just get merged in at the top-level of the final Result object. + if (static::isUnnamed($key)) { + $this->merge($taskResult); + } elseif (isset($this[$key])) { + // There can only be one task with a given name; however, if + // there are tasks added 'before' or 'after' the named task, + // then the results from these will be stored under the same + // name unless they are given a name of their own when added. + $current = $this[$key]; + $this[$key] = $taskResult->merge($current); + } else { + $this[$key] = $taskResult; + } + } + + /** + * We assume that named values (e.g. for associative array keys) + * are non-numeric; numeric keys are presumed to simply be the + * index of an array, and therefore insignificant. + * + * @param int|string $key + * + * @return bool + */ + public static function isUnnamed($key) + { + return is_numeric($key); + } + + /** + * @return \Robo\Contract\TaskInterface + */ + public function getTask() + { + return $this->task; + } + + /** + * @return \Robo\Contract\TaskInterface + */ + public function cloneTask() + { + $reflect = new \ReflectionClass(get_class($this->task)); + return $reflect->newInstanceArgs(func_get_args()); + } + + /** + * @return bool + * + * @deprecated since 1.0. + * + * @see wasSuccessful() + */ + public function __invoke() + { + trigger_error(__METHOD__ . ' is deprecated: use wasSuccessful() instead.', E_USER_DEPRECATED); + return $this->wasSuccessful(); + } + + /** + * @return $this + */ + public function stopOnFail() + { + if (!$this->wasSuccessful()) { + $resultPrinter = Robo::resultPrinter(); + if ($resultPrinter) { + $resultPrinter->printStopOnFail($this); + } + $this->exitEarly($this->getExitCode()); + } + return $this; + } + + /** + * @param int $status + * + * @throws \Robo\Exception\TaskExitException + */ + private function exitEarly($status) + { + throw new TaskExitException($this->getTask(), $this->getMessage(), $status); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/ResultData.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/ResultData.php new file mode 100644 index 00000000..90baf6e9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/ResultData.php @@ -0,0 +1,110 @@ +exitCode = $exitCode; + parent::__construct($message, $data); + } + + /** + * @param string $message + * @param array $data + * + * @return \Robo\ResultData + */ + public static function message($message, $data = []) + { + return new self(self::EXITCODE_OK, $message, $data); + } + + /** + * @param string $message + * @param array $data + * + * @return \Robo\ResultData + */ + public static function cancelled($message = '', $data = []) + { + return new ResultData(self::EXITCODE_USER_CANCEL, $message, $data); + } + + /** + * @return int + */ + public function getExitCode() + { + return $this->exitCode; + } + + /** + * @return null|string + */ + public function getOutputData() + { + if (!empty($this->message) && !isset($this['already-printed']) && isset($this['provide-outputdata'])) { + return $this->message; + } + } + + /** + * Indicate that the message in this data has already been displayed. + */ + public function alreadyPrinted() + { + $this['already-printed'] = true; + } + + /** + * Opt-in to providing the result message as the output data + */ + public function provideOutputdata() + { + $this['provide-outputdata'] = true; + } + + /** + * @return bool + */ + public function wasSuccessful() + { + return $this->exitCode === self::EXITCODE_OK; + } + + /** + * @return bool + */ + public function wasCancelled() + { + return $this->exitCode == self::EXITCODE_USER_CANCEL; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Robo.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Robo.php new file mode 100644 index 00000000..0f427707 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Robo.php @@ -0,0 +1,394 @@ +setSelfUpdateRepository($repository); + $statusCode = $runner->execute($argv, $appName, $appVersion, $output); + return $statusCode; + } + + /** + * Sets a new global container. + * + * @param ContainerInterface $container + * A new container instance to replace the current. + */ + public static function setContainer(ContainerInterface $container) + { + static::$container = $container; + } + + /** + * Unsets the global container. + */ + public static function unsetContainer() + { + static::$container = null; + } + + /** + * Returns the currently active global container. + * + * @return \League\Container\ContainerInterface + * + * @throws \RuntimeException + */ + public static function getContainer() + { + if (static::$container === null) { + throw new \RuntimeException('container is not initialized yet. \Robo\Robo::setContainer() must be called with a real container.'); + } + return static::$container; + } + + /** + * Returns TRUE if the container has been initialized, FALSE otherwise. + * + * @return bool + */ + public static function hasContainer() + { + return static::$container !== null; + } + + /** + * Create a config object and load it from the provided paths. + */ + public static function createConfiguration($paths) + { + $config = new \Robo\Config\Config(); + static::loadConfiguration($paths, $config); + return $config; + } + + /** + * Use a simple config loader to load configuration values from specified paths + */ + public static function loadConfiguration($paths, $config = null) + { + if ($config == null) { + $config = static::config(); + } + $loader = new YamlConfigLoader(); + $processor = new ConfigProcessor(); + $processor->add($config->export()); + foreach ($paths as $path) { + $processor->extend($loader->load($path)); + } + $config->import($processor->export()); + } + + /** + * Create a container and initiailze it. If you wish to *change* + * anything defined in the container, then you should call + * \Robo::configureContainer() instead of this function. + * + * @param null|\Symfony\Component\Console\Input\InputInterface $input + * @param null|\Symfony\Component\Console\Output\OutputInterface $output + * @param null|\Robo\Application $app + * @param null|ConfigInterface $config + * + * @return \League\Container\Container|\League\Container\ContainerInterface + */ + public static function createDefaultContainer($input = null, $output = null, $app = null, $config = null) + { + // Do not allow this function to be called more than once. + if (static::hasContainer()) { + return static::getContainer(); + } + + if (!$app) { + $app = static::createDefaultApplication(); + } + + if (!$config) { + $config = new \Robo\Config\Config(); + } + + // Set up our dependency injection container. + $container = new Container(); + static::configureContainer($container, $app, $config, $input, $output); + + // Set the application dispatcher + $app->setDispatcher($container->get('eventDispatcher')); + + return $container; + } + + /** + * Initialize a container with all of the default Robo services. + * IMPORTANT: after calling this method, clients MUST call: + * + * $dispatcher = $container->get('eventDispatcher'); + * $app->setDispatcher($dispatcher); + * + * Any modification to the container should be done prior to fetching + * objects from it. + * + * It is recommended to use \Robo::createDefaultContainer() + * instead, which does all required setup for the caller, but has + * the limitation that the container it creates can only be + * extended, not modified. + * + * @param \League\Container\ContainerInterface $container + * @param \Symfony\Component\Console\Application $app + * @param ConfigInterface $config + * @param null|\Symfony\Component\Console\Input\InputInterface $input + * @param null|\Symfony\Component\Console\Output\OutputInterface $output + */ + public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, ConfigInterface $config, $input = null, $output = null) + { + // Self-referential container refernce for the inflector + $container->add('container', $container); + static::setContainer($container); + + // Create default input and output objects if they were not provided + if (!$input) { + $input = new StringInput(''); + } + if (!$output) { + $output = new \Symfony\Component\Console\Output\ConsoleOutput(); + } + $config->set(Config::DECORATED, $output->isDecorated()); + $config->set(Config::INTERACTIVE, $input->isInteractive()); + + $container->share('application', $app); + $container->share('config', $config); + $container->share('input', $input); + $container->share('output', $output); + $container->share('outputAdapter', \Robo\Common\OutputAdapter::class); + + // Register logging and related services. + $container->share('logStyler', \Robo\Log\RoboLogStyle::class); + $container->share('logger', \Robo\Log\RoboLogger::class) + ->withArgument('output') + ->withMethodCall('setLogOutputStyler', ['logStyler']); + $container->add('progressBar', \Symfony\Component\Console\Helper\ProgressBar::class) + ->withArgument('output'); + $container->share('progressIndicator', \Robo\Common\ProgressIndicator::class) + ->withArgument('progressBar') + ->withArgument('output'); + $container->share('resultPrinter', \Robo\Log\ResultPrinter::class); + $container->add('simulator', \Robo\Task\Simulator::class); + $container->share('globalOptionsEventListener', \Robo\GlobalOptionsEventListener::class) + ->withMethodCall('setApplication', ['application']); + $container->share('injectConfigEventListener', \Consolidation\Config\Inject\ConfigForCommand::class) + ->withArgument('config') + ->withMethodCall('setApplication', ['application']); + $container->share('collectionProcessHook', \Robo\Collection\CollectionProcessHook::class); + $container->share('alterOptionsCommandEvent', \Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent::class) + ->withArgument('application'); + $container->share('hookManager', \Consolidation\AnnotatedCommand\Hooks\HookManager::class) + ->withMethodCall('addCommandEvent', ['alterOptionsCommandEvent']) + ->withMethodCall('addCommandEvent', ['injectConfigEventListener']) + ->withMethodCall('addCommandEvent', ['globalOptionsEventListener']) + ->withMethodCall('addResultProcessor', ['collectionProcessHook', '*']); + $container->share('eventDispatcher', \Symfony\Component\EventDispatcher\EventDispatcher::class) + ->withMethodCall('addSubscriber', ['hookManager']); + $container->share('formatterManager', \Consolidation\OutputFormatters\FormatterManager::class) + ->withMethodCall('addDefaultFormatters', []) + ->withMethodCall('addDefaultSimplifiers', []); + $container->share('prepareTerminalWidthOption', \Consolidation\AnnotatedCommand\Options\PrepareTerminalWidthOption::class) + ->withMethodCall('setApplication', ['application']); + $container->share('commandProcessor', \Consolidation\AnnotatedCommand\CommandProcessor::class) + ->withArgument('hookManager') + ->withMethodCall('setFormatterManager', ['formatterManager']) + ->withMethodCall('addPrepareFormatter', ['prepareTerminalWidthOption']) + ->withMethodCall( + 'setDisplayErrorFunction', + [ + function ($output, $message) use ($container) { + $logger = $container->get('logger'); + $logger->error($message); + } + ] + ); + $container->share('commandFactory', \Consolidation\AnnotatedCommand\AnnotatedCommandFactory::class) + ->withMethodCall('setCommandProcessor', ['commandProcessor']); + + // Deprecated: favor using collection builders to direct use of collections. + $container->add('collection', \Robo\Collection\Collection::class); + // Deprecated: use CollectionBuilder::create() instead -- or, better + // yet, BuilderAwareInterface::collectionBuilder() if available. + $container->add('collectionBuilder', \Robo\Collection\CollectionBuilder::class); + + static::addInflectors($container); + + // Make sure the application is appropriately initialized. + $app->setAutoExit(false); + } + + /** + * @param null|string $appName + * @param null|string $appVersion + * + * @return \Robo\Application + */ + public static function createDefaultApplication($appName = null, $appVersion = null) + { + $appName = $appName ?: self::APPLICATION_NAME; + $appVersion = $appVersion ?: self::VERSION; + + $app = new \Robo\Application($appName, $appVersion); + $app->setAutoExit(false); + return $app; + } + + /** + * Add the Robo League\Container inflectors to the container + * + * @param \League\Container\ContainerInterface $container + */ + public static function addInflectors($container) + { + // Register our various inflectors. + $container->inflector(\Robo\Contract\ConfigAwareInterface::class) + ->invokeMethod('setConfig', ['config']); + $container->inflector(\Psr\Log\LoggerAwareInterface::class) + ->invokeMethod('setLogger', ['logger']); + $container->inflector(\League\Container\ContainerAwareInterface::class) + ->invokeMethod('setContainer', ['container']); + $container->inflector(\Symfony\Component\Console\Input\InputAwareInterface::class) + ->invokeMethod('setInput', ['input']); + $container->inflector(\Robo\Contract\OutputAwareInterface::class) + ->invokeMethod('setOutput', ['output']); + $container->inflector(\Robo\Contract\ProgressIndicatorAwareInterface::class) + ->invokeMethod('setProgressIndicator', ['progressIndicator']); + $container->inflector(\Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface::class) + ->invokeMethod('setHookManager', ['hookManager']); + $container->inflector(\Robo\Contract\VerbosityThresholdInterface::class) + ->invokeMethod('setOutputAdapter', ['outputAdapter']); + } + + /** + * Retrieves a service from the container. + * + * Use this method if the desired service is not one of those with a dedicated + * accessor method below. If it is listed below, those methods are preferred + * as they can return useful type hints. + * + * @param string $id + * The ID of the service to retrieve. + * + * @return mixed + * The specified service. + */ + public static function service($id) + { + return static::getContainer()->get($id); + } + + /** + * Indicates if a service is defined in the container. + * + * @param string $id + * The ID of the service to check. + * + * @return bool + * TRUE if the specified service exists, FALSE otherwise. + */ + public static function hasService($id) + { + // Check hasContainer() first in order to always return a Boolean. + return static::hasContainer() && static::getContainer()->has($id); + } + + /** + * Return the result printer object. + * + * @return \Robo\Log\ResultPrinter + */ + public static function resultPrinter() + { + return static::service('resultPrinter'); + } + + /** + * @return ConfigInterface + */ + public static function config() + { + return static::service('config'); + } + + /** + * @return \Consolidation\Log\Logger + */ + public static function logger() + { + return static::service('logger'); + } + + /** + * @return \Robo\Application + */ + public static function application() + { + return static::service('application'); + } + + /** + * Return the output object. + * + * @return \Symfony\Component\Console\Output\OutputInterface + */ + public static function output() + { + return static::service('output'); + } + + /** + * Return the input object. + * + * @return \Symfony\Component\Console\Input\InputInterface + */ + public static function input() + { + return static::service('input'); + } + + public static function process(Process $process) + { + return ProcessExecutor::create(static::getContainer(), $process); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Runner.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Runner.php new file mode 100644 index 00000000..800ad281 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Runner.php @@ -0,0 +1,465 @@ +roboClass = $roboClass ? $roboClass : self::ROBOCLASS ; + $this->roboFile = $roboFile ? $roboFile : self::ROBOFILE; + $this->dir = getcwd(); + } + + protected function errorCondtion($msg, $errorType) + { + $this->errorConditions[$msg] = $errorType; + } + + /** + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return bool + */ + protected function loadRoboFile($output) + { + // If we have not been provided an output object, make a temporary one. + if (!$output) { + $output = new \Symfony\Component\Console\Output\ConsoleOutput(); + } + + // If $this->roboClass is a single class that has not already + // been loaded, then we will try to obtain it from $this->roboFile. + // If $this->roboClass is an array, we presume all classes requested + // are available via the autoloader. + if (is_array($this->roboClass) || class_exists($this->roboClass)) { + return true; + } + if (!file_exists($this->dir)) { + $this->errorCondtion("Path `{$this->dir}` is invalid; please provide a valid absolute path to the Robofile to load.", 'red'); + return false; + } + + $realDir = realpath($this->dir); + + $roboFilePath = $realDir . DIRECTORY_SEPARATOR . $this->roboFile; + if (!file_exists($roboFilePath)) { + $requestedRoboFilePath = $this->dir . DIRECTORY_SEPARATOR . $this->roboFile; + $this->errorCondtion("Requested RoboFile `$requestedRoboFilePath` is invalid, please provide valid absolute path to load Robofile.", 'red'); + return false; + } + require_once $roboFilePath; + + if (!class_exists($this->roboClass)) { + $this->errorCondtion("Class {$this->roboClass} was not loaded.", 'red'); + return false; + } + return true; + } + + /** + * @param array $argv + * @param null|string $appName + * @param null|string $appVersion + * @param null|\Symfony\Component\Console\Output\OutputInterface $output + * + * @return int + */ + public function execute($argv, $appName = null, $appVersion = null, $output = null) + { + $argv = $this->shebang($argv); + $argv = $this->processRoboOptions($argv); + $app = null; + if ($appName && $appVersion) { + $app = Robo::createDefaultApplication($appName, $appVersion); + } + $commandFiles = $this->getRoboFileCommands($output); + return $this->run($argv, $output, $app, $commandFiles); + } + + /** + * @param null|\Symfony\Component\Console\Input\InputInterface $input + * @param null|\Symfony\Component\Console\Output\OutputInterface $output + * @param null|\Robo\Application $app + * @param array[] $commandFiles + * + * @return int + */ + public function run($input = null, $output = null, $app = null, $commandFiles = []) + { + // Create default input and output objects if they were not provided + if (!$input) { + $input = new StringInput(''); + } + if (is_array($input)) { + $input = new ArgvInput($input); + } + if (!$output) { + $output = new \Symfony\Component\Console\Output\ConsoleOutput(); + } + $this->setInput($input); + $this->setOutput($output); + + // If we were not provided a container, then create one + if (!$this->getContainer()) { + $userConfig = 'robo.yml'; + $roboAppConfig = dirname(__DIR__) . '/robo.yml'; + $config = Robo::createConfiguration([$userConfig, $roboAppConfig]); + $container = Robo::createDefaultContainer($input, $output, $app, $config); + $this->setContainer($container); + // Automatically register a shutdown function and + // an error handler when we provide the container. + $this->installRoboHandlers(); + } + + if (!$app) { + $app = Robo::application(); + } + if ($app instanceof \Robo\Application) { + $app->addSelfUpdateCommand($this->getSelfUpdateRepository()); + if (!isset($commandFiles)) { + $this->errorCondtion("Robo is not initialized here. Please run `robo init` to create a new RoboFile.", 'yellow'); + $app->addInitRoboFileCommand($this->roboFile, $this->roboClass); + $commandFiles = []; + } + } + $this->registerCommandClasses($app, $commandFiles); + + try { + $statusCode = $app->run($input, $output); + } catch (TaskExitException $e) { + $statusCode = $e->getCode() ?: 1; + } + + // If there were any error conditions in bootstrapping Robo, + // print them only if the requested command did not complete + // successfully. + if ($statusCode) { + foreach ($this->errorConditions as $msg => $color) { + $this->yell($msg, 40, $color); + } + } + return $statusCode; + } + + /** + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return null|string + */ + protected function getRoboFileCommands($output) + { + if (!$this->loadRoboFile($output)) { + return; + } + return $this->roboClass; + } + + /** + * @param \Robo\Application $app + * @param array $commandClasses + */ + public function registerCommandClasses($app, $commandClasses) + { + foreach ((array)$commandClasses as $commandClass) { + $this->registerCommandClass($app, $commandClass); + } + } + + /** + * @param \Robo\Application $app + * @param string|BuilderAwareInterface|ContainerAwareInterface $commandClass + * + * @return mixed|void + */ + public function registerCommandClass($app, $commandClass) + { + $container = Robo::getContainer(); + $roboCommandFileInstance = $this->instantiateCommandClass($commandClass); + if (!$roboCommandFileInstance) { + return; + } + + // Register commands for all of the public methods in the RoboFile. + $commandFactory = $container->get('commandFactory'); + $commandList = $commandFactory->createCommandsFromClass($roboCommandFileInstance); + foreach ($commandList as $command) { + $app->add($command); + } + return $roboCommandFileInstance; + } + + /** + * @param string|BuilderAwareInterface|ContainerAwareInterface $commandClass + * + * @return null|object + */ + protected function instantiateCommandClass($commandClass) + { + $container = Robo::getContainer(); + + // Register the RoboFile with the container and then immediately + // fetch it; this ensures that all of the inflectors will run. + // If the command class is already an instantiated object, then + // just use it exactly as it was provided to us. + if (is_string($commandClass)) { + if (!class_exists($commandClass)) { + return; + } + $reflectionClass = new \ReflectionClass($commandClass); + if ($reflectionClass->isAbstract()) { + return; + } + + $commandFileName = "{$commandClass}Commands"; + $container->share($commandFileName, $commandClass); + $commandClass = $container->get($commandFileName); + } + // If the command class is a Builder Aware Interface, then + // ensure that it has a builder. Every command class needs + // its own collection builder, as they have references to each other. + if ($commandClass instanceof BuilderAwareInterface) { + $builder = CollectionBuilder::create($container, $commandClass); + $commandClass->setBuilder($builder); + } + if ($commandClass instanceof ContainerAwareInterface) { + $commandClass->setContainer($container); + } + return $commandClass; + } + + public function installRoboHandlers() + { + register_shutdown_function(array($this, 'shutdown')); + set_error_handler(array($this, 'handleError')); + } + + /** + * Process a shebang script, if one was used to launch this Runner. + * + * @param array $args + * + * @return array $args with shebang script removed + */ + protected function shebang($args) + { + // Option 1: Shebang line names Robo, but includes no parameters. + // #!/bin/env robo + // The robo class may contain multiple commands; the user may + // select which one to run, or even get a list of commands or + // run 'help' on any of the available commands as usual. + if ((count($args) > 1) && $this->isShebangFile($args[1])) { + return array_merge([$args[0]], array_slice($args, 2)); + } + // Option 2: Shebang line stipulates which command to run. + // #!/bin/env robo mycommand + // The robo class must contain a public method named 'mycommand'. + // This command will be executed every time. Arguments and options + // may be provided on the commandline as usual. + if ((count($args) > 2) && $this->isShebangFile($args[2])) { + return array_merge([$args[0]], explode(' ', $args[1]), array_slice($args, 3)); + } + return $args; + } + + /** + * Determine if the specified argument is a path to a shebang script. + * If so, load it. + * + * @param string $filepath file to check + * + * @return bool Returns TRUE if shebang script was processed + */ + protected function isShebangFile($filepath) + { + if (!is_file($filepath)) { + return false; + } + $fp = fopen($filepath, "r"); + if ($fp === false) { + return false; + } + $line = fgets($fp); + $result = $this->isShebangLine($line); + if ($result) { + while ($line = fgets($fp)) { + $line = trim($line); + if ($line == 'roboClass = $matches[1]; + eval($script); + $result = true; + } + } + } + } + fclose($fp); + + return $result; + } + + /** + * Test to see if the provided line is a robo 'shebang' line. + * + * @param string $line + * + * @return bool + */ + protected function isShebangLine($line) + { + return ((substr($line, 0, 2) == '#!') && (strstr($line, 'robo') !== false)); + } + + /** + * Check for Robo-specific arguments such as --load-from, process them, + * and remove them from the array. We have to process --load-from before + * we set up Symfony Console. + * + * @param array $argv + * + * @return array + */ + protected function processRoboOptions($argv) + { + // loading from other directory + $pos = $this->arraySearchBeginsWith('--load-from', $argv) ?: array_search('-f', $argv); + if ($pos === false) { + return $argv; + } + + $passThru = array_search('--', $argv); + if (($passThru !== false) && ($passThru < $pos)) { + return $argv; + } + + if (substr($argv[$pos], 0, 12) == '--load-from=') { + $this->dir = substr($argv[$pos], 12); + } elseif (isset($argv[$pos +1])) { + $this->dir = $argv[$pos +1]; + unset($argv[$pos +1]); + } + unset($argv[$pos]); + // Make adjustments if '--load-from' points at a file. + if (is_file($this->dir) || (substr($this->dir, -4) == '.php')) { + $this->roboFile = basename($this->dir); + $this->dir = dirname($this->dir); + $className = basename($this->roboFile, '.php'); + if ($className != $this->roboFile) { + $this->roboClass = $className; + } + } + // Convert directory to a real path, but only if the + // path exists. We do not want to lose the original + // directory if the user supplied a bad value. + $realDir = realpath($this->dir); + if ($realDir) { + chdir($realDir); + $this->dir = $realDir; + } + + return $argv; + } + + /** + * @param string $needle + * @param string[] $haystack + * + * @return bool|int + */ + protected function arraySearchBeginsWith($needle, $haystack) + { + for ($i = 0; $i < count($haystack); ++$i) { + if (substr($haystack[$i], 0, strlen($needle)) == $needle) { + return $i; + } + } + return false; + } + + public function shutdown() + { + $error = error_get_last(); + if (!is_array($error)) { + return; + } + $this->writeln(sprintf("ERROR: %s \nin %s:%d\n", $error['message'], $error['file'], $error['line'])); + } + + /** + * This is just a proxy error handler that checks the current error_reporting level. + * In case error_reporting is disabled the error is marked as handled, otherwise + * the normal internal error handling resumes. + * + * @return bool + */ + public function handleError() + { + if (error_reporting() === 0) { + return true; + } + return false; + } + + /** + * @return string + */ + public function getSelfUpdateRepository() + { + return $this->selfUpdateRepository; + } + + /** + * @param string $selfUpdateRepository + */ + public function setSelfUpdateRepository($selfUpdateRepository) + { + $this->selfUpdateRepository = $selfUpdateRepository; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/SelfUpdateCommand.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/SelfUpdateCommand.php new file mode 100644 index 00000000..d07ee71f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/SelfUpdateCommand.php @@ -0,0 +1,152 @@ + + */ +class SelfUpdateCommand extends Command +{ + const SELF_UPDATE_COMMAND_NAME = 'self:update'; + + protected $gitHubRepository; + + protected $currentVersion; + + protected $applicationName; + + public function __construct($applicationName = null, $currentVersion = null, $gitHubRepository = null) + { + parent::__construct(self::SELF_UPDATE_COMMAND_NAME); + + $this->applicationName = $applicationName; + $this->currentVersion = $currentVersion; + $this->gitHubRepository = $gitHubRepository; + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setAliases(array('update')) + ->setDescription('Updates the robo.phar to the latest version.') + ->setHelp( + <<self-update command checks github for newer +versions of robo and if found, installs the latest. +EOT + ); + } + + protected function getLatestReleaseFromGithub() + { + $opts = [ + 'http' => [ + 'method' => 'GET', + 'header' => [ + 'User-Agent: ' . $this->applicationName . ' (' . $this->gitHubRepository . ')' . ' Self-Update (PHP)' + ] + ] + ]; + + $context = stream_context_create($opts); + + $releases = file_get_contents('https://api.github.com/repos/' . $this->gitHubRepository . '/releases', false, $context); + $releases = json_decode($releases); + + if (! isset($releases[0])) { + throw new \Exception('API error - no release found at GitHub repository ' . $this->gitHubRepository); + } + + $version = $releases[0]->tag_name; + $url = $releases[0]->assets[0]->browser_download_url; + + return [ $version, $url ]; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (empty(\Phar::running())) { + throw new \Exception(self::SELF_UPDATE_COMMAND_NAME . ' only works when running the phar version of ' . $this->applicationName . '.'); + } + + $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; + $programName = basename($localFilename); + $tempFilename = dirname($localFilename) . '/' . basename($localFilename, '.phar') . '-temp.phar'; + + // check for permissions in local filesystem before start connection process + if (! is_writable($tempDirectory = dirname($tempFilename))) { + throw new \Exception( + $programName . ' update failed: the "' . $tempDirectory . + '" directory used to download the temp file could not be written' + ); + } + + if (! is_writable($localFilename)) { + throw new \Exception( + $programName . ' update failed: the "' . $localFilename . '" file could not be written (execute with sudo)' + ); + } + + list( $latest, $downloadUrl ) = $this->getLatestReleaseFromGithub(); + + + if ($this->currentVersion == $latest) { + $output->writeln('No update available'); + return; + } + + $fs = new sfFilesystem(); + + $output->writeln('Downloading ' . $this->applicationName . ' (' . $this->gitHubRepository . ') ' . $latest); + + $fs->copy($downloadUrl, $tempFilename); + + $output->writeln('Download finished'); + + try { + \error_reporting(E_ALL); // supress notices + + @chmod($tempFilename, 0777 & ~umask()); + // test the phar validity + $phar = new \Phar($tempFilename); + // free the variable to unlock the file + unset($phar); + @rename($tempFilename, $localFilename); + $output->writeln('Successfully updated ' . $programName . ''); + $this->_exit(); + } catch (\Exception $e) { + @unlink($tempFilename); + if (! $e instanceof \UnexpectedValueException && ! $e instanceof \PharException) { + throw $e; + } + $output->writeln('The download is corrupted (' . $e->getMessage() . ').'); + $output->writeln('Please re-run the self-update command to try again.'); + } + } + + /** + * Stop execution + * + * This is a workaround to prevent warning of dispatcher after replacing + * the phar file. + * + * @return void + */ + protected function _exit() + { + exit; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/Consumer.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/Consumer.php new file mode 100644 index 00000000..ab9c0e27 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/Consumer.php @@ -0,0 +1,12 @@ +message = $message; + parent::__construct($data); + } + + /** + * @return array + */ + public function getData() + { + return $this->getArrayCopy(); + } + + /** + * @return string + */ + public function getMessage() + { + return $this->message; + } + + /** + * @param string message + */ + public function setMessage($message) + { + $this->message = $message; + } + + /** + * Merge another result into this result. Data already + * existing in this result takes precedence over the + * data in the Result being merged. + * + * @param \Robo\ResultData $result + * + * @return $this + */ + public function merge(Data $result) + { + $mergedData = $this->getArrayCopy() + $result->getArrayCopy(); + $this->exchangeArray($mergedData); + return $this; + } + + /** + * Update the current data with the data provided in the parameter. + * Provided data takes precedence. + * + * @param \ArrayObject $update + * + * @return $this + */ + public function update(\ArrayObject $update) + { + $iterator = $update->getIterator(); + + while ($iterator->valid()) { + $this[$iterator->key()] = $iterator->current(); + $iterator->next(); + } + + return $this; + } + + /** + * Merge another result into this result. Data already + * existing in this result takes precedence over the + * data in the Result being merged. + * + * $data['message'] is handled specially, and is appended + * to $this->message if set. + * + * @param array $data + * + * @return array + */ + public function mergeData(array $data) + { + $mergedData = $this->getArrayCopy() + $data; + $this->exchangeArray($mergedData); + return $mergedData; + } + + /** + * @return bool + */ + public function hasExecutionTime() + { + return isset($this['time']); + } + + /** + * @return null|float + */ + public function getExecutionTime() + { + if (!$this->hasExecutionTime()) { + return null; + } + return $this['time']; + } + + /** + * Accumulate execution time + */ + public function accumulateExecutionTime($duration) + { + // Convert data arrays to scalar + if (is_array($duration)) { + $duration = isset($duration['time']) ? $duration['time'] : 0; + } + $this['time'] = $this->getExecutionTime() + $duration; + return $this->getExecutionTime(); + } + + /** + * Accumulate the message. + */ + public function accumulateMessage($message) + { + if (!empty($this->message)) { + $this->message .= "\n"; + } + $this->message .= $message; + return $this->getMessage(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/StateAwareInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/StateAwareInterface.php new file mode 100644 index 00000000..f86bccb8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/State/StateAwareInterface.php @@ -0,0 +1,30 @@ +state; + } + + /** + * {@inheritdoc} + */ + public function setState(Data $state) + { + $this->state = $state; + } + + /** + * {@inheritdoc} + */ + public function setStateValue($key, $value) + { + $this->state[$key] = $value; + } + + /** + * {@inheritdoc} + */ + public function updateState(Data $update) + { + $this->state->update($update); + } + + /** + * {@inheritdoc} + */ + public function resetState() + { + $this->state = new Data(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/ApiGen/ApiGen.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/ApiGen/ApiGen.php new file mode 100644 index 00000000..11ff764c --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/ApiGen/ApiGen.php @@ -0,0 +1,518 @@ +taskApiGen('./vendor/apigen/apigen.phar') + * ->config('./apigen.neon') + * ->templateConfig('vendor/apigen/apigen/templates/bootstrap/config.neon') + * ->wipeout(true) + * ->run(); + * ?> + * ``` + */ +class ApiGen extends BaseTask implements CommandInterface +{ + use \Robo\Common\ExecOneCommand; + + const BOOL_NO = 'no'; + const BOOL_YES = 'yes'; + + /** + * @var string + */ + protected $command; + protected $operation = 'generate'; + + /** + * @param null|string $pathToApiGen + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToApiGen = null) + { + $this->command = $pathToApiGen; + $command_parts = []; + preg_match('/((?:.+)?apigen(?:\.phar)?) ?( \w+)? ?(.+)?/', $this->command, $command_parts); + if (count($command_parts) === 3) { + list(, $this->command, $this->operation) = $command_parts; + } + if (count($command_parts) === 4) { + list(, $this->command, $this->operation, $arg) = $command_parts; + $this->arg($arg); + } + if (!$this->command) { + $this->command = $this->findExecutablePhar('apigen'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "No apigen installation found"); + } + } + + /** + * Pass methods parameters as arguments to executable. Argument values + * are automatically escaped. + * + * @param string|string[] $args + * + * @return $this + */ + public function args($args) + { + if (!is_array($args)) { + $args = func_get_args(); + } + $args = array_map(function ($arg) { + if (preg_match('/^\w+$/', trim($arg)) === 1) { + $this->operation = $arg; + return null; + } + return $arg; + }, $args); + $args = array_filter($args); + $this->arguments .= ' ' . implode(' ', array_map('static::escape', $args)); + return $this; + } + + /** + * @param array|Traversable|string $arg a single object or something traversable + * + * @return array|Traversable the provided argument if it was already traversable, or the given + * argument returned as a one-element array + */ + protected static function forceTraversable($arg) + { + $traversable = $arg; + if (!is_array($traversable) && !($traversable instanceof \Traversable)) { + $traversable = array($traversable); + } + return $traversable; + } + + /** + * @param array|string $arg a single argument or an array of multiple string values + * + * @return string a comma-separated string of all of the provided arguments, suitable + * as a command-line "list" type argument for ApiGen + */ + protected static function asList($arg) + { + $normalized = is_array($arg) ? $arg : array($arg); + return implode(',', $normalized); + } + + /** + * @param bool|string $val an argument to be normalized + * @param string $default one of self::BOOL_YES or self::BOOK_NO if the provided + * value could not deterministically be converted to a + * yes or no value + * + * @return string the given value as a command-line "yes|no" type of argument for ApiGen, + * or the default value if none could be determined + */ + protected static function asTextBool($val, $default) + { + if ($val === self::BOOL_YES || $val === self::BOOL_NO) { + return $val; + } + if (!$val) { + return self::BOOL_NO; + } + if ($val === true) { + return self::BOOL_YES; + } + if (is_numeric($val) && $val != 0) { + return self::BOOL_YES; + } + if (strcasecmp($val[0], 'y') === 0) { + return self::BOOL_YES; + } + if (strcasecmp($val[0], 'n') === 0) { + return self::BOOL_NO; + } + // meh, good enough, let apigen sort it out + return $default; + } + + /** + * @param string $config + * + * @return $this + */ + public function config($config) + { + $this->option('config', $config); + return $this; + } + + /** + * @param array|string|Traversable $src one or more source values + * + * @return $this + */ + public function source($src) + { + foreach (self::forceTraversable($src) as $source) { + $this->option('source', $source); + } + return $this; + } + + /** + * @param string $dest + * + * @return $this + */ + public function destination($dest) + { + $this->option('destination', $dest); + return $this; + } + + /** + * @param array|string $exts one or more extensions + * + * @return $this + */ + public function extensions($exts) + { + $this->option('extensions', self::asList($exts)); + return $this; + } + + /** + * @param array|string $exclude one or more exclusions + * + * @return $this + */ + public function exclude($exclude) + { + foreach (self::forceTraversable($exclude) as $excl) { + $this->option('exclude', $excl); + } + return $this; + } + + /** + * @param array|string|Traversable $path one or more skip-doc-path values + * + * @return $this + */ + public function skipDocPath($path) + { + foreach (self::forceTraversable($path) as $skip) { + $this->option('skip-doc-path', $skip); + } + return $this; + } + + /** + * @param array|string|Traversable $prefix one or more skip-doc-prefix values + * + * @return $this + */ + public function skipDocPrefix($prefix) + { + foreach (self::forceTraversable($prefix) as $skip) { + $this->option('skip-doc-prefix', $skip); + } + return $this; + } + + /** + * @param array|string $charset one or more charsets + * + * @return $this + */ + public function charset($charset) + { + $this->option('charset', self::asList($charset)); + return $this; + } + + /** + * @param string $name + * + * @return $this + */ + public function mainProjectNamePrefix($name) + { + $this->option('main', $name); + return $this; + } + + /** + * @param string $title + * + * @return $this + */ + public function title($title) + { + $this->option('title', $title); + return $this; + } + + /** + * @param string $baseUrl + * + * @return $this + */ + public function baseUrl($baseUrl) + { + $this->option('base-url', $baseUrl); + return $this; + } + + /** + * @param string $id + * + * @return $this + */ + public function googleCseId($id) + { + $this->option('google-cse-id', $id); + return $this; + } + + /** + * @param string $trackingCode + * + * @return $this + */ + public function googleAnalytics($trackingCode) + { + $this->option('google-analytics', $trackingCode); + return $this; + } + + /** + * @param mixed $templateConfig + * + * @return $this + */ + public function templateConfig($templateConfig) + { + $this->option('template-config', $templateConfig); + return $this; + } + + /** + * @param array|string $tags one or more supported html tags + * + * @return $this + */ + public function allowedHtml($tags) + { + $this->option('allowed-html', self::asList($tags)); + return $this; + } + + /** + * @param string $groups + * + * @return $this + */ + public function groups($groups) + { + $this->option('groups', $groups); + return $this; + } + + /** + * @param array|string $types or more supported autocomplete types + * + * @return $this + */ + public function autocomplete($types) + { + $this->option('autocomplete', self::asList($types)); + return $this; + } + + /** + * @param array|string $levels one or more access levels + * + * @return $this + */ + public function accessLevels($levels) + { + $this->option('access-levels', self::asList($levels)); + return $this; + } + + /** + * @param boolean|string $internal 'yes' or true if internal, 'no' or false if not + * + * @return $this + */ + public function internal($internal) + { + $this->option('internal', self::asTextBool($internal, self::BOOL_NO)); + return $this; + } + + /** + * @param boolean|string $php 'yes' or true to generate documentation for internal php classes, + * 'no' or false otherwise + * + * @return $this + */ + public function php($php) + { + $this->option('php', self::asTextBool($php, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $tree 'yes' or true to generate a tree view of classes, 'no' or false otherwise + * + * @return $this + */ + public function tree($tree) + { + $this->option('tree', self::asTextBool($tree, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $dep 'yes' or true to generate documentation for deprecated classes, 'no' or false otherwise + * + * @return $this + */ + public function deprecated($dep) + { + $this->option('deprecated', self::asTextBool($dep, self::BOOL_NO)); + return $this; + } + + /** + * @param bool|string $todo 'yes' or true to document tasks, 'no' or false otherwise + * + * @return $this + */ + public function todo($todo) + { + $this->option('todo', self::asTextBool($todo, self::BOOL_NO)); + return $this; + } + + /** + * @param bool|string $src 'yes' or true to generate highlighted source code, 'no' or false otherwise + * + * @return $this + */ + public function sourceCode($src) + { + $this->option('source-code', self::asTextBool($src, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $zipped 'yes' or true to generate downloadable documentation, 'no' or false otherwise + * + * @return $this + */ + public function download($zipped) + { + $this->option('download', self::asTextBool($zipped, self::BOOL_NO)); + return $this; + } + + public function report($path) + { + $this->option('report', $path); + return $this; + } + + /** + * @param bool|string $wipeout 'yes' or true to clear out the destination directory, 'no' or false otherwise + * + * @return $this + */ + public function wipeout($wipeout) + { + $this->option('wipeout', self::asTextBool($wipeout, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $quiet 'yes' or true for quiet, 'no' or false otherwise + * + * @return $this + */ + public function quiet($quiet) + { + $this->option('quiet', self::asTextBool($quiet, self::BOOL_NO)); + return $this; + } + + /** + * @param bool|string $bar 'yes' or true to display a progress bar, 'no' or false otherwise + * + * @return $this + */ + public function progressbar($bar) + { + $this->option('progressbar', self::asTextBool($bar, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $colors 'yes' or true colorize the output, 'no' or false otherwise + * + * @return $this + */ + public function colors($colors) + { + $this->option('colors', self::asTextBool($colors, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $check 'yes' or true to check for updates, 'no' or false otherwise + * + * @return $this + */ + public function updateCheck($check) + { + $this->option('update-check', self::asTextBool($check, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $debug 'yes' or true to enable debug mode, 'no' or false otherwise + * + * @return $this + */ + public function debug($debug) + { + $this->option('debug', self::asTextBool($debug, self::BOOL_NO)); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return "$this->command $this->operation$this->arguments"; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running ApiGen {args}', ['args' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/ApiGen/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/ApiGen/loadTasks.php new file mode 100644 index 00000000..e8cd372a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/ApiGen/loadTasks.php @@ -0,0 +1,15 @@ +task(ApiGen::class, $pathToApiGen); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/Extract.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/Extract.php new file mode 100644 index 00000000..a00a0baf --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/Extract.php @@ -0,0 +1,279 @@ +taskExtract($archivePath) + * ->to($destination) + * ->preserveTopDirectory(false) // the default + * ->run(); + * ?> + * ``` + */ +class Extract extends BaseTask implements BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var string + */ + protected $filename; + + /** + * @var string + */ + protected $to; + + /** + * @var bool + */ + private $preserveTopDirectory = false; + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * Location to store extracted files. + * + * @param string $to + * + * @return $this + */ + public function to($to) + { + $this->to = $to; + return $this; + } + + /** + * @param bool $preserve + * + * @return $this + */ + public function preserveTopDirectory($preserve = true) + { + $this->preserveTopDirectory = $preserve; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!file_exists($this->filename)) { + $this->printTaskError("File {filename} does not exist", ['filename' => $this->filename]); + + return false; + } + if (!($mimetype = static::archiveType($this->filename))) { + $this->printTaskError("Could not determine type of archive for {filename}", ['filename' => $this->filename]); + + return false; + } + + // We will first extract to $extractLocation and then move to $this->to + $extractLocation = static::getTmpDir(); + @mkdir($extractLocation); + @mkdir(dirname($this->to)); + + $this->startTimer(); + + $this->printTaskInfo("Extracting {filename}", ['filename' => $this->filename]); + + $result = $this->extractAppropriateType($mimetype, $extractLocation); + if ($result->wasSuccessful()) { + $this->printTaskInfo("{filename} extracted", ['filename' => $this->filename]); + // Now, we want to move the extracted files to $this->to. There + // are two possibilities that we must consider: + // + // (1) Archived files were encapsulated in a folder with an arbitrary name + // (2) There was no encapsulating folder, and all the files in the archive + // were extracted into $extractLocation + // + // In the case of (1), we want to move and rename the encapsulating folder + // to $this->to. + // + // In the case of (2), we will just move and rename $extractLocation. + $filesInExtractLocation = glob("$extractLocation/*"); + $hasEncapsulatingFolder = ((count($filesInExtractLocation) == 1) && is_dir($filesInExtractLocation[0])); + if ($hasEncapsulatingFolder && !$this->preserveTopDirectory) { + $result = (new FilesystemStack()) + ->inflect($this) + ->rename($filesInExtractLocation[0], $this->to) + ->run(); + (new DeleteDir($extractLocation)) + ->inflect($this) + ->run(); + } else { + $result = (new FilesystemStack()) + ->inflect($this) + ->rename($extractLocation, $this->to) + ->run(); + } + } + $this->stopTimer(); + $result['time'] = $this->getExecutionTime(); + + return $result; + } + + /** + * @param string $mimetype + * @param string $extractLocation + * + * @return \Robo\Result + */ + protected function extractAppropriateType($mimetype, $extractLocation) + { + // Perform the extraction of a zip file. + if (($mimetype == 'application/zip') || ($mimetype == 'application/x-zip')) { + return $this->extractZip($extractLocation); + } + return $this->extractTar($extractLocation); + } + + /** + * @param string $extractLocation + * + * @return \Robo\Result + */ + protected function extractZip($extractLocation) + { + if (!extension_loaded('zlib')) { + return Result::errorMissingExtension($this, 'zlib', 'zip extracting'); + } + + $zip = new \ZipArchive(); + if (($status = $zip->open($this->filename)) !== true) { + return Result::error($this, "Could not open zip archive {$this->filename}"); + } + if (!$zip->extractTo($extractLocation)) { + return Result::error($this, "Could not extract zip archive {$this->filename}"); + } + $zip->close(); + + return Result::success($this); + } + + /** + * @param string $extractLocation + * + * @return \Robo\Result + */ + protected function extractTar($extractLocation) + { + if (!class_exists('Archive_Tar')) { + return Result::errorMissingPackage($this, 'Archive_Tar', 'pear/archive_tar'); + } + $tar_object = new \Archive_Tar($this->filename); + if (!$tar_object->extract($extractLocation)) { + return Result::error($this, "Could not extract tar archive {$this->filename}"); + } + + return Result::success($this); + } + + /** + * @param string $filename + * + * @return bool|string + */ + protected static function archiveType($filename) + { + $content_type = false; + if (class_exists('finfo')) { + $finfo = new \finfo(FILEINFO_MIME_TYPE); + $content_type = $finfo->file($filename); + // If finfo cannot determine the content type, then we will try other methods + if ($content_type == 'application/octet-stream') { + $content_type = false; + } + } + // Examing the file's magic header bytes. + if (!$content_type) { + if ($file = fopen($filename, 'rb')) { + $first = fread($file, 2); + fclose($file); + if ($first !== false) { + // Interpret the two bytes as a little endian 16-bit unsigned int. + $data = unpack('v', $first); + switch ($data[1]) { + case 0x8b1f: + // First two bytes of gzip files are 0x1f, 0x8b (little-endian). + // See http://www.gzip.org/zlib/rfc-gzip.html#header-trailer + $content_type = 'application/x-gzip'; + break; + + case 0x4b50: + // First two bytes of zip files are 0x50, 0x4b ('PK') (little-endian). + // See http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers + $content_type = 'application/zip'; + break; + + case 0x5a42: + // First two bytes of bzip2 files are 0x5a, 0x42 ('BZ') (big-endian). + // See http://en.wikipedia.org/wiki/Bzip2#File_format + $content_type = 'application/x-bzip2'; + break; + } + } + } + } + // 3. Lastly if above methods didn't work, try to guess the mime type from + // the file extension. This is useful if the file has no identificable magic + // header bytes (for example tarballs). + if (!$content_type) { + // Remove querystring from the filename, if present. + $filename = basename(current(explode('?', $filename, 2))); + $extension_mimetype = array( + '.tar.gz' => 'application/x-gzip', + '.tgz' => 'application/x-gzip', + '.tar' => 'application/x-tar', + ); + foreach ($extension_mimetype as $extension => $ct) { + if (substr($filename, -strlen($extension)) === $extension) { + $content_type = $ct; + break; + } + } + } + + return $content_type; + } + + /** + * @return string + */ + protected static function getTmpDir() + { + return getcwd().'/tmp'.rand().time(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/Pack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/Pack.php new file mode 100644 index 00000000..0970f8e8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/Pack.php @@ -0,0 +1,257 @@ +taskPack( + * ) + * ->add('README') // Puts file 'README' in archive at the root + * ->add('project') // Puts entire contents of directory 'project' in archinve inside 'project' + * ->addFile('dir/file.txt', 'file.txt') // Takes 'file.txt' from cwd and puts it in archive inside 'dir'. + * ->run(); + * ?> + * ``` + */ +class Pack extends BaseTask implements PrintedInterface +{ + /** + * The list of items to be packed into the archive. + * + * @var array + */ + private $items = []; + + /** + * The full path to the archive to be created. + * + * @var string + */ + private $archiveFile; + + /** + * Construct the class. + * + * @param string $archiveFile The full path and name of the archive file to create. + * + * @since 1.0 + */ + public function __construct($archiveFile) + { + $this->archiveFile = $archiveFile; + } + + /** + * Satisfy the parent requirement. + * + * @return bool Always returns true. + * + * @since 1.0 + */ + public function getPrinted() + { + return true; + } + + /** + * @param string $archiveFile + * + * @return $this + */ + public function archiveFile($archiveFile) + { + $this->archiveFile = $archiveFile; + return $this; + } + + /** + * Add an item to the archive. Like file_exists(), the parameter + * may be a file or a directory. + * + * @var string + * Relative path and name of item to store in archive + * @var string + * Absolute or relative path to file or directory's location in filesystem + * + * @return $this + */ + public function addFile($placementLocation, $filesystemLocation) + { + $this->items[$placementLocation] = $filesystemLocation; + + return $this; + } + + /** + * Alias for addFile, in case anyone has angst about using + * addFile with a directory. + * + * @var string + * Relative path and name of directory to store in archive + * @var string + * Absolute or relative path to directory or directory's location in filesystem + * + * @return $this + */ + public function addDir($placementLocation, $filesystemLocation) + { + $this->addFile($placementLocation, $filesystemLocation); + + return $this; + } + + /** + * Add a file or directory, or list of same to the archive. + * + * @var string|array + * If given a string, should contain the relative filesystem path to the + * the item to store in archive; this will also be used as the item's + * path in the archive, so absolute paths should not be used here. + * If given an array, the key of each item should be the path to store + * in the archive, and the value should be the filesystem path to the + * item to store. + * @return $this + */ + public function add($item) + { + if (is_array($item)) { + $this->items = array_merge($this->items, $item); + } else { + $this->addFile($item, $item); + } + + return $this; + } + + /** + * Create a zip archive for distribution. + * + * @return \Robo\Result + * + * @since 1.0 + */ + public function run() + { + $this->startTimer(); + + // Use the file extension to determine what kind of archive to create. + $fileInfo = new \SplFileInfo($this->archiveFile); + $extension = strtolower($fileInfo->getExtension()); + if (empty($extension)) { + return Result::error($this, "Archive filename must use an extension (e.g. '.zip') to specify the kind of archive to create."); + } + + try { + // Inform the user which archive we are creating + $this->printTaskInfo("Creating archive {filename}", ['filename' => $this->archiveFile]); + if ($extension == 'zip') { + $result = $this->archiveZip($this->archiveFile, $this->items); + } else { + $result = $this->archiveTar($this->archiveFile, $this->items); + } + $this->printTaskSuccess("{filename} created.", ['filename' => $this->archiveFile]); + } catch (\Exception $e) { + $this->printTaskError("Could not create {filename}. {exception}", ['filename' => $this->archiveFile, 'exception' => $e->getMessage(), '_style' => ['exception' => '']]); + $result = Result::error($this, sprintf('Could not create %s. %s', $this->archiveFile, $e->getMessage())); + } + $this->stopTimer(); + $result['time'] = $this->getExecutionTime(); + + return $result; + } + + /** + * @param string $archiveFile + * @param array $items + * + * @return \Robo\Result + */ + protected function archiveTar($archiveFile, $items) + { + if (!class_exists('Archive_Tar')) { + return Result::errorMissingPackage($this, 'Archive_Tar', 'pear/archive_tar'); + } + + $tar_object = new \Archive_Tar($archiveFile); + foreach ($items as $placementLocation => $filesystemLocation) { + $p_remove_dir = $filesystemLocation; + $p_add_dir = $placementLocation; + if (is_file($filesystemLocation)) { + $p_remove_dir = dirname($filesystemLocation); + $p_add_dir = dirname($placementLocation); + if (basename($filesystemLocation) != basename($placementLocation)) { + return Result::error($this, "Tar archiver does not support renaming files during extraction; could not add $filesystemLocation as $placementLocation."); + } + } + + if (!$tar_object->addModify([$filesystemLocation], $p_add_dir, $p_remove_dir)) { + return Result::error($this, "Could not add $filesystemLocation to the archive."); + } + } + + return Result::success($this); + } + + /** + * @param string $archiveFile + * @param array $items + * + * @return \Robo\Result + */ + protected function archiveZip($archiveFile, $items) + { + if (!extension_loaded('zlib')) { + return Result::errorMissingExtension($this, 'zlib', 'zip packing'); + } + + $zip = new \ZipArchive($archiveFile, \ZipArchive::CREATE); + if (!$zip->open($archiveFile, \ZipArchive::CREATE)) { + return Result::error($this, "Could not create zip archive {$archiveFile}"); + } + $result = $this->addItemsToZip($zip, $items); + $zip->close(); + + return $result; + } + + /** + * @param \ZipArchive $zip + * @param array $items + * + * @return \Robo\Result + */ + protected function addItemsToZip($zip, $items) + { + foreach ($items as $placementLocation => $filesystemLocation) { + if (is_dir($filesystemLocation)) { + $finder = new Finder(); + $finder->files()->in($filesystemLocation)->ignoreDotFiles(false); + + foreach ($finder as $file) { + // Replace Windows slashes or resulting zip will have issues on *nixes. + $relativePathname = str_replace('\\', '/', $file->getRelativePathname()); + + if (!$zip->addFile($file->getRealpath(), "{$placementLocation}/{$relativePathname}")) { + return Result::error($this, "Could not add directory $filesystemLocation to the archive; error adding {$file->getRealpath()}."); + } + } + } elseif (is_file($filesystemLocation)) { + if (!$zip->addFile($filesystemLocation, $placementLocation)) { + return Result::error($this, "Could not add file $filesystemLocation to the archive."); + } + } else { + return Result::error($this, "Could not find $filesystemLocation for the archive."); + } + } + + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/loadTasks.php new file mode 100644 index 00000000..cf846fdf --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Archive/loadTasks.php @@ -0,0 +1,25 @@ +task(Pack::class, $filename); + } + + /** + * @param $filename + * + * @return Extract + */ + protected function taskExtract($filename) + { + return $this->task(Extract::class, $filename); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/CssPreprocessor.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/CssPreprocessor.php new file mode 100644 index 00000000..a15d2078 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/CssPreprocessor.php @@ -0,0 +1,214 @@ +files = $input; + + $this->setDefaultCompiler(); + } + + protected function setDefaultCompiler() + { + if (isset($this->compilers[0])) { + //set first compiler as default + $this->compiler = $this->compilers[0]; + } + } + + /** + * Sets import directories + * Alias for setImportPaths + * @see CssPreprocessor::setImportPaths + * + * @param array|string $dirs + * + * @return $this + */ + public function importDir($dirs) + { + return $this->setImportPaths($dirs); + } + + /** + * Adds import directory + * + * @param string $dir + * + * @return $this + */ + public function addImportPath($dir) + { + if (!isset($this->compilerOptions['importDirs'])) { + $this->compilerOptions['importDirs'] = []; + } + + if (!in_array($dir, $this->compilerOptions['importDirs'], true)) { + $this->compilerOptions['importDirs'][] = $dir; + } + + return $this; + } + + /** + * Sets import directories + * + * @param array|string $dirs + * + * @return $this + */ + public function setImportPaths($dirs) + { + if (!is_array($dirs)) { + $dirs = [$dirs]; + } + + $this->compilerOptions['importDirs'] = $dirs; + + return $this; + } + + /** + * @param string $formatterName + * + * @return $this + */ + public function setFormatter($formatterName) + { + $this->compilerOptions['formatter'] = $formatterName; + + return $this; + } + + /** + * Sets the compiler. + * + * @param string $compiler + * @param array $options + * + * @return $this + */ + public function compiler($compiler, array $options = []) + { + $this->compiler = $compiler; + $this->compilerOptions = array_merge($this->compilerOptions, $options); + + return $this; + } + + /** + * Compiles file + * + * @param $file + * + * @return bool|mixed + */ + protected function compile($file) + { + if (is_callable($this->compiler)) { + return call_user_func($this->compiler, $file, $this->compilerOptions); + } + + if (method_exists($this, $this->compiler)) { + return $this->{$this->compiler}($file); + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!in_array($this->compiler, $this->compilers, true) + && !is_callable($this->compiler) + ) { + $message = sprintf('Invalid ' . static::FORMAT_NAME . ' compiler %s!', $this->compiler); + + return Result::error($this, $message); + } + + foreach ($this->files as $in => $out) { + if (!file_exists($in)) { + $message = sprintf('File %s not found.', $in); + + return Result::error($this, $message); + } + if (file_exists($out) && !is_writable($out)) { + return Result::error($this, 'Destination already exists and cannot be overwritten.'); + } + } + + foreach ($this->files as $in => $out) { + $css = $this->compile($in); + + if ($css instanceof Result) { + return $css; + } elseif (false === $css) { + $message = sprintf( + ucfirst(static::FORMAT_NAME) . ' compilation failed for %s.', + $in + ); + + return Result::error($this, $message); + } + + $dst = $out . '.part'; + $write_result = file_put_contents($dst, $css); + + if (false === $write_result) { + $message = sprintf('File write failed: %s', $out); + + @unlink($dst); + return Result::error($this, $message); + } + + // Cannot be cross-volume: should always succeed + @rename($dst, $out); + + $this->printTaskSuccess('Wrote CSS to {filename}', ['filename' => $out]); + } + + return Result::success($this, 'All ' . static::FORMAT_NAME . ' files compiled.'); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/ImageMinify.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/ImageMinify.php new file mode 100644 index 00000000..1aa62593 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/ImageMinify.php @@ -0,0 +1,716 @@ +taskImageMinify('assets/images/*') + * ->to('dist/images/') + * ->run(); + * ``` + * + * This will use the following minifiers: + * + * - PNG: optipng + * - GIF: gifsicle + * - JPG, JPEG: jpegtran + * - SVG: svgo + * + * When the minifier is specified the task will use that for all the input files. In that case + * it is useful to filter the files with the extension: + * + * ```php + * $this->taskImageMinify('assets/images/*.png') + * ->to('dist/images/') + * ->minifier('pngcrush'); + * ->run(); + * ``` + * + * The task supports the following minifiers: + * + * - optipng + * - pngquant + * - advpng + * - pngout + * - zopflipng + * - pngcrush + * - gifsicle + * - jpegoptim + * - jpeg-recompress + * - jpegtran + * - svgo (only minification, no downloading) + * + * You can also specifiy extra options for the minifiers: + * + * ```php + * $this->taskImageMinify('assets/images/*.jpg') + * ->to('dist/images/') + * ->minifier('jpegtran', ['-progressive' => null, '-copy' => 'none']) + * ->run(); + * ``` + * + * This will execute as: + * `jpegtran -copy none -progressive -optimize -outfile "dist/images/test.jpg" "/var/www/test/assets/images/test.jpg"` + */ +class ImageMinify extends BaseTask +{ + /** + * Destination directory for the minified images. + * + * @var string + */ + protected $to; + + /** + * Array of the source files. + * + * @var array + */ + protected $dirs = []; + + /** + * Symfony 2 filesystem. + * + * @var sfFilesystem + */ + protected $fs; + + /** + * Target directory for the downloaded binary executables. + * + * @var string + */ + protected $executableTargetDir; + + /** + * Array for the downloaded binary executables. + * + * @var array + */ + protected $executablePaths = []; + + /** + * Array for the individual results of all the files. + * + * @var array + */ + protected $results = []; + + /** + * Default minifier to use. + * + * @var string + */ + protected $minifier; + + /** + * Array for minifier options. + * + * @var array + */ + protected $minifierOptions = []; + + /** + * Supported minifiers. + * + * @var array + */ + protected $minifiers = [ + // Default 4 + 'optipng', + 'gifsicle', + 'jpegtran', + 'svgo', + // PNG + 'pngquant', + 'advpng', + 'pngout', + 'zopflipng', + 'pngcrush', + // JPG + 'jpegoptim', + 'jpeg-recompress', + ]; + + /** + * Binary repositories of Imagemin. + * + * @link https://github.com/imagemin + * + * @var array + */ + protected $imageminRepos = [ + // PNG + 'optipng' => 'https://github.com/imagemin/optipng-bin', + 'pngquant' => 'https://github.com/imagemin/pngquant-bin', + 'advpng' => 'https://github.com/imagemin/advpng-bin', + 'pngout' => 'https://github.com/imagemin/pngout-bin', + 'zopflipng' => 'https://github.com/imagemin/zopflipng-bin', + 'pngcrush' => 'https://github.com/imagemin/pngcrush-bin', + // Gif + 'gifsicle' => 'https://github.com/imagemin/gifsicle-bin', + // JPG + 'jpegtran' => 'https://github.com/imagemin/jpegtran-bin', + 'jpegoptim' => 'https://github.com/imagemin/jpegoptim-bin', + 'cjpeg' => 'https://github.com/imagemin/mozjpeg-bin', // note: we do not support this minifier because it creates JPG from non-JPG files + 'jpeg-recompress' => 'https://github.com/imagemin/jpeg-recompress-bin', + // WebP + 'cwebp' => 'https://github.com/imagemin/cwebp-bin', // note: we do not support this minifier because it creates WebP from non-WebP files + ]; + + public function __construct($dirs) + { + is_array($dirs) + ? $this->dirs = $dirs + : $this->dirs[] = $dirs; + + $this->fs = new sfFilesystem(); + + // guess the best path for the executables based on __DIR__ + if (($pos = strpos(__DIR__, 'consolidation/robo')) !== false) { + // the executables should be stored in vendor/bin + $this->executableTargetDir = substr(__DIR__, 0, $pos).'bin'; + } + + // check if the executables are already available + foreach ($this->imageminRepos as $exec => $url) { + $path = $this->executableTargetDir.'/'.$exec; + // if this is Windows add a .exe extension + if (substr($this->getOS(), 0, 3) == 'win') { + $path .= '.exe'; + } + if (is_file($path)) { + $this->executablePaths[$exec] = $path; + } + } + } + + /** + * {@inheritdoc} + */ + public function run() + { + // find the files + $files = $this->findFiles($this->dirs); + + // minify the files + $result = $this->minify($files); + // check if there was an error + if ($result instanceof Result) { + return $result; + } + + $amount = (count($files) == 1 ? 'image' : 'images'); + $message = "Minified {filecount} out of {filetotal} $amount into {destination}"; + $context = ['filecount' => count($this->results['success']), 'filetotal' => count($files), 'destination' => $this->to]; + + if (count($this->results['success']) == count($files)) { + $this->printTaskSuccess($message, $context); + + return Result::success($this, $message, $context); + } else { + return Result::error($this, $message, $context); + } + } + + /** + * Sets the target directory where the files will be copied to. + * + * @param string $target + * + * @return $this + */ + public function to($target) + { + $this->to = rtrim($target, '/'); + + return $this; + } + + /** + * Sets the minifier. + * + * @param string $minifier + * @param array $options + * + * @return $this + */ + public function minifier($minifier, array $options = []) + { + $this->minifier = $minifier; + $this->minifierOptions = array_merge($this->minifierOptions, $options); + + return $this; + } + + /** + * @param array $dirs + * + * @return array|\Robo\Result + * + * @throws \Robo\Exception\TaskException + */ + protected function findFiles($dirs) + { + $files = array(); + + // find the files + foreach ($dirs as $k => $v) { + // reset finder + $finder = new Finder(); + + $dir = $k; + $to = $v; + // check if target was given with the to() method instead of key/value pairs + if (is_int($k)) { + $dir = $v; + if (isset($this->to)) { + $to = $this->to; + } else { + throw new TaskException($this, 'target directory is not defined'); + } + } + + try { + $finder->files()->in($dir); + } catch (\InvalidArgumentException $e) { + // if finder cannot handle it, try with in()->name() + if (strpos($dir, '/') === false) { + $dir = './'.$dir; + } + $parts = explode('/', $dir); + $new_dir = implode('/', array_slice($parts, 0, -1)); + try { + $finder->files()->in($new_dir)->name(array_pop($parts)); + } catch (\InvalidArgumentException $e) { + return Result::fromException($this, $e); + } + } + + foreach ($finder as $file) { + // store the absolute path as key and target as value in the files array + $files[$file->getRealpath()] = $this->getTarget($file->getRealPath(), $to); + } + $fileNoun = count($finder) == 1 ? ' file' : ' files'; + $this->printTaskInfo("Found {filecount} $fileNoun in {dir}", ['filecount' => count($finder), 'dir' => $dir]); + } + + return $files; + } + + /** + * @param string $file + * @param string $to + * + * @return string + */ + protected function getTarget($file, $to) + { + $target = $to.'/'.basename($file); + + return $target; + } + + /** + * @param array $files + * + * @return \Robo\Result + */ + protected function minify($files) + { + // store the individual results into the results array + $this->results = [ + 'success' => [], + 'error' => [], + ]; + + // loop through the files + foreach ($files as $from => $to) { + if (!isset($this->minifier)) { + // check filetype based on the extension + $extension = strtolower(pathinfo($from, PATHINFO_EXTENSION)); + + // set the default minifiers based on the extension + switch ($extension) { + case 'png': + $minifier = 'optipng'; + break; + case 'jpg': + case 'jpeg': + $minifier = 'jpegtran'; + break; + case 'gif': + $minifier = 'gifsicle'; + break; + case 'svg': + $minifier = 'svgo'; + break; + } + } else { + if (!in_array($this->minifier, $this->minifiers, true) + && !is_callable(strtr($this->minifier, '-', '_')) + ) { + $message = sprintf('Invalid minifier %s!', $this->minifier); + + return Result::error($this, $message); + } + $minifier = $this->minifier; + } + + // Convert minifier name to camelCase (e.g. jpeg-recompress) + $funcMinifier = $this->camelCase($minifier); + + // call the minifier method which prepares the command + if (is_callable($funcMinifier)) { + $command = call_user_func($funcMinifier, $from, $to, $this->minifierOptions); + } elseif (method_exists($this, $funcMinifier)) { + $command = $this->{$funcMinifier}($from, $to); + } else { + $message = sprintf('Minifier method %s cannot be found!', $funcMinifier); + + return Result::error($this, $message); + } + + // launch the command + $this->printTaskInfo('Minifying {filepath} with {minifier}', ['filepath' => $from, 'minifier' => $minifier]); + $result = $this->executeCommand($command); + + // check the return code + if ($result->getExitCode() == 127) { + $this->printTaskError('The {minifier} executable cannot be found', ['minifier' => $minifier]); + // try to install from imagemin repository + if (array_key_exists($minifier, $this->imageminRepos)) { + $result = $this->installFromImagemin($minifier); + if ($result instanceof Result) { + if ($result->wasSuccessful()) { + $this->printTaskSuccess($result->getMessage()); + // retry the conversion with the downloaded executable + if (is_callable($minifier)) { + $command = call_user_func($minifier, $from, $to, $minifierOptions); + } elseif (method_exists($this, $minifier)) { + $command = $this->{$minifier}($from, $to); + } + // launch the command + $this->printTaskInfo('Minifying {filepath} with {minifier}', ['filepath' => $from, 'minifier' => $minifier]); + $result = $this->executeCommand($command); + } else { + $this->printTaskError($result->getMessage()); + // the download was not successful + return $result; + } + } + } else { + return $result; + } + } + + // check the success of the conversion + if ($result->getExitCode() !== 0) { + $this->results['error'][] = $from; + } else { + $this->results['success'][] = $from; + } + } + } + + /** + * @return string + */ + protected function getOS() + { + $os = php_uname('s'); + $os .= '/'.php_uname('m'); + // replace x86_64 to x64, because the imagemin repo uses that + $os = str_replace('x86_64', 'x64', $os); + // replace i386, i686, etc to x86, because of imagemin + $os = preg_replace('/i[0-9]86/', 'x86', $os); + // turn info to lowercase, because of imagemin + $os = strtolower($os); + + return $os; + } + + /** + * @param string $command + * + * @return \Robo\Result + */ + protected function executeCommand($command) + { + // insert the options into the command + $a = explode(' ', $command); + $executable = array_shift($a); + foreach ($this->minifierOptions as $key => $value) { + // first prepend the value + if (!empty($value)) { + array_unshift($a, $value); + } + // then add the key + if (!is_numeric($key)) { + array_unshift($a, $key); + } + } + // check if the executable can be replaced with the downloaded one + if (array_key_exists($executable, $this->executablePaths)) { + $executable = $this->executablePaths[$executable]; + } + array_unshift($a, $executable); + $command = implode(' ', $a); + + // execute the command + $exec = new Exec($command); + + return $exec->inflect($this)->printed(false)->run(); + } + + /** + * @param string $executable + * + * @return \Robo\Result + */ + protected function installFromImagemin($executable) + { + // check if there is an url defined for the executable + if (!array_key_exists($executable, $this->imageminRepos)) { + $message = sprintf('The executable %s cannot be found in the defined imagemin repositories', $executable); + + return Result::error($this, $message); + } + $this->printTaskInfo('Downloading the {executable} executable from the imagemin repository', ['executable' => $executable]); + + $os = $this->getOS(); + $url = $this->imageminRepos[$executable].'/blob/master/vendor/'.$os.'/'.$executable.'?raw=true'; + if (substr($os, 0, 3) == 'win') { + // if it is win, add a .exe extension + $url = $this->imageminRepos[$executable].'/blob/master/vendor/'.$os.'/'.$executable.'.exe?raw=true'; + } + $data = @file_get_contents($url, false, null); + if ($data === false) { + // there is something wrong with the url, try it without the version info + $url = preg_replace('/x[68][64]\//', '', $url); + $data = @file_get_contents($url, false, null); + if ($data === false) { + // there is still something wrong with the url if it is win, try with win32 + if (substr($os, 0, 3) == 'win') { + $url = preg_replace('win/', 'win32/', $url); + $data = @file_get_contents($url, false, null); + if ($data === false) { + // there is nothing more we can do + $message = sprintf('Could not download the executable %s', $executable); + + return Result::error($this, $message); + } + } + // if it is not windows there is nothing we can do + $message = sprintf('Could not download the executable %s', $executable); + + return Result::error($this, $message); + } + } + // check if target directory exists + if (!is_dir($this->executableTargetDir)) { + mkdir($this->executableTargetDir); + } + // save the executable into the target dir + $path = $this->executableTargetDir.'/'.$executable; + if (substr($os, 0, 3) == 'win') { + // if it is win, add a .exe extension + $path = $this->executableTargetDir.'/'.$executable.'.exe'; + } + $result = file_put_contents($path, $data); + if ($result === false) { + $message = sprintf('Could not copy the executable %s to %s', $executable, $target_dir); + + return Result::error($this, $message); + } + // set the binary to executable + chmod($path, 0755); + + // if everything successful, store the executable path + $this->executablePaths[$executable] = $this->executableTargetDir.'/'.$executable; + // if it is win, add a .exe extension + if (substr($os, 0, 3) == 'win') { + $this->executablePaths[$executable] .= '.exe'; + } + + $message = sprintf('Executable %s successfully downloaded', $executable); + + return Result::success($this, $message); + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function optipng($from, $to) + { + $command = sprintf('optipng -quiet -out "%s" -- "%s"', $to, $from); + if ($from != $to && is_file($to)) { + // earlier versions of optipng do not overwrite the target without a backup + // http://sourceforge.net/p/optipng/bugs/37/ + unlink($to); + } + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function jpegtran($from, $to) + { + $command = sprintf('jpegtran -optimize -outfile "%s" "%s"', $to, $from); + + return $command; + } + + protected function gifsicle($from, $to) + { + $command = sprintf('gifsicle -o "%s" "%s"', $to, $from); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function svgo($from, $to) + { + $command = sprintf('svgo "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function pngquant($from, $to) + { + $command = sprintf('pngquant --force --output "%s" "%s"', $to, $from); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function advpng($from, $to) + { + // advpng does not have any output parameters, copy the file and then compress the copy + $command = sprintf('advpng --recompress --quiet "%s"', $to); + $this->fs->copy($from, $to, true); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function pngout($from, $to) + { + $command = sprintf('pngout -y -q "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function zopflipng($from, $to) + { + $command = sprintf('zopflipng -y "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function pngcrush($from, $to) + { + $command = sprintf('pngcrush -q -ow "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function jpegoptim($from, $to) + { + // jpegoptim only takes the destination directory as an argument + $command = sprintf('jpegoptim --quiet -o --dest "%s" "%s"', dirname($to), $from); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function jpegRecompress($from, $to) + { + $command = sprintf('jpeg-recompress --quiet "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $text + * + * @return string + */ + public static function camelCase($text) + { + // non-alpha and non-numeric characters become spaces + $text = preg_replace('/[^a-z0-9]+/i', ' ', $text); + $text = trim($text); + // uppercase the first character of each word + $text = ucwords($text); + $text = str_replace(" ", "", $text); + $text = lcfirst($text); + + return $text; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Less.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Less.php new file mode 100644 index 00000000..4cfa0978 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Less.php @@ -0,0 +1,108 @@ +taskLess([ + * 'less/default.less' => 'css/default.css' + * ]) + * ->run(); + * ?> + * ``` + * + * Use one of both less compilers in your project: + * + * ``` + * "leafo/lessphp": "~0.5", + * "oyejorge/less.php": "~1.5" + * ``` + * + * Specify directory (string or array) for less imports lookup: + * + * ```php + * taskLess([ + * 'less/default.less' => 'css/default.css' + * ]) + * ->importDir('less') + * ->compiler('lessphp') + * ->run(); + * ?> + * ``` + * + * You can implement additional compilers by extending this task and adding a + * method named after them and overloading the lessCompilers() method to + * inject the name there. + */ +class Less extends CssPreprocessor +{ + const FORMAT_NAME = 'less'; + + /** + * @var string[] + */ + protected $compilers = [ + 'less', // https://github.com/oyejorge/less.php + 'lessphp', //https://github.com/leafo/lessphp + ]; + + /** + * lessphp compiler + * @link https://github.com/leafo/lessphp + * + * @param string $file + * + * @return string + */ + protected function lessphp($file) + { + if (!class_exists('\lessc')) { + return Result::errorMissingPackage($this, 'lessc', 'leafo/lessphp'); + } + + $lessCode = file_get_contents($file); + + $less = new \lessc(); + if (isset($this->compilerOptions['importDirs'])) { + $less->setImportDir($this->compilerOptions['importDirs']); + } + + return $less->compile($lessCode); + } + + /** + * less compiler + * @link https://github.com/oyejorge/less.php + * + * @param string $file + * + * @return string + */ + protected function less($file) + { + if (!class_exists('\Less_Parser')) { + return Result::errorMissingPackage($this, 'Less_Parser', 'oyejorge/less.php'); + } + + $lessCode = file_get_contents($file); + + $parser = new \Less_Parser(); + $parser->SetOptions($this->compilerOptions); + if (isset($this->compilerOptions['importDirs'])) { + $importDirs = []; + foreach ($this->compilerOptions['importDirs'] as $dir) { + $importDirs[$dir] = $dir; + } + $parser->SetImportDirs($importDirs); + } + + $parser->parse($lessCode); + + return $parser->getCss(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Minify.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Minify.php new file mode 100644 index 00000000..3187714e --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Minify.php @@ -0,0 +1,297 @@ +taskMinify( 'web/assets/theme.css' ) + * ->run() + * ?> + * ``` + * Please install additional dependencies to use: + * + * ``` + * "patchwork/jsqueeze": "~1.0", + * "natxet/CssMin": "~3.0" + * ``` + */ +class Minify extends BaseTask +{ + /** + * @var array + */ + protected $types = ['css', 'js']; + + /** + * @var string + */ + protected $text; + + /** + * @var string + */ + protected $dst; + + /** + * @var string + */ + protected $type; + + /** + * @var array + */ + protected $squeezeOptions = [ + 'singleLine' => true, + 'keepImportantComments' => true, + 'specialVarRx' => false, + ]; + + /** + * Constructor. Accepts asset file path or string source. + * + * @param string $input + */ + public function __construct($input) + { + if (file_exists($input)) { + $this->fromFile($input); + return; + } + + $this->fromText($input); + } + + /** + * Sets destination. Tries to guess type from it. + * + * @param string $dst + * + * @return $this + */ + public function to($dst) + { + $this->dst = $dst; + + if (!empty($this->dst) && empty($this->type)) { + $this->type($this->getExtension($this->dst)); + } + + return $this; + } + + /** + * Sets type with validation. + * + * @param string $type css|js + * + * @return $this + */ + public function type($type) + { + $type = strtolower($type); + + if (in_array($type, $this->types)) { + $this->type = $type; + } + + return $this; + } + + /** + * Sets text from string source. + * + * @param string $text + * + * @return $this + */ + protected function fromText($text) + { + $this->text = (string)$text; + unset($this->type); + + return $this; + } + + /** + * Sets text from asset file path. Tries to guess type and set default destination. + * + * @param string $path + * + * @return $this + */ + protected function fromFile($path) + { + $this->text = file_get_contents($path); + + unset($this->type); + $this->type($this->getExtension($path)); + + if (empty($this->dst) && !empty($this->type)) { + $ext_length = strlen($this->type) + 1; + $this->dst = substr($path, 0, -$ext_length) . '.min.' . $this->type; + } + + return $this; + } + + /** + * Gets file extension from path. + * + * @param string $path + * + * @return string + */ + protected function getExtension($path) + { + return pathinfo($path, PATHINFO_EXTENSION); + } + + /** + * Minifies and returns text. + * + * @return string|bool + */ + protected function getMinifiedText() + { + switch ($this->type) { + case 'css': + if (!class_exists('\CssMin')) { + return Result::errorMissingPackage($this, 'CssMin', 'natxet/CssMin'); + } + + return \CssMin::minify($this->text); + break; + + case 'js': + if (!class_exists('\JSqueeze') && !class_exists('\Patchwork\JSqueeze')) { + return Result::errorMissingPackage($this, 'Patchwork\JSqueeze', 'patchwork/jsqueeze'); + } + + if (class_exists('\JSqueeze')) { + $jsqueeze = new \JSqueeze(); + } else { + $jsqueeze = new \Patchwork\JSqueeze(); + } + + return $jsqueeze->squeeze( + $this->text, + $this->squeezeOptions['singleLine'], + $this->squeezeOptions['keepImportantComments'], + $this->squeezeOptions['specialVarRx'] + ); + break; + } + + return false; + } + + /** + * Single line option for the JS minimisation. + * + * @param bool $singleLine + * + * @return $this + */ + public function singleLine($singleLine) + { + $this->squeezeOptions['singleLine'] = (bool)$singleLine; + return $this; + } + + /** + * keepImportantComments option for the JS minimisation. + * + * @param bool $keepImportantComments + * + * @return $this + */ + public function keepImportantComments($keepImportantComments) + { + $this->squeezeOptions['keepImportantComments'] = (bool)$keepImportantComments; + return $this; + } + + /** + * specialVarRx option for the JS minimisation. + * + * @param bool $specialVarRx + * + * @return $this ; + */ + public function specialVarRx($specialVarRx) + { + $this->squeezeOptions['specialVarRx'] = (bool)$specialVarRx; + return $this; + } + + /** + * @return string + */ + public function __toString() + { + return (string) $this->getMinifiedText(); + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (empty($this->type)) { + return Result::error($this, 'Unknown asset type.'); + } + + if (empty($this->dst)) { + return Result::error($this, 'Unknown file destination.'); + } + + if (file_exists($this->dst) && !is_writable($this->dst)) { + return Result::error($this, 'Destination already exists and cannot be overwritten.'); + } + + $size_before = strlen($this->text); + $minified = $this->getMinifiedText(); + + if ($minified instanceof Result) { + return $minified; + } elseif (false === $minified) { + return Result::error($this, 'Minification failed.'); + } + + $size_after = strlen($minified); + + // Minification did not reduce file size, so use original file. + if ($size_after > $size_before) { + $minified = $this->text; + $size_after = $size_before; + } + + $dst = $this->dst . '.part'; + $write_result = file_put_contents($dst, $minified); + + if (false === $write_result) { + @unlink($dst); + return Result::error($this, 'File write failed.'); + } + // Cannot be cross-volume; should always succeed. + @rename($dst, $this->dst); + if ($size_before === 0) { + $minified_percent = 0; + } else { + $minified_percent = number_format(100 - ($size_after / $size_before * 100), 1); + } + $this->printTaskSuccess('Wrote {filepath}', ['filepath' => $this->dst]); + $context = [ + 'bytes' => $this->formatBytes($size_after), + 'reduction' => $this->formatBytes(($size_before - $size_after)), + 'percentage' => $minified_percent, + ]; + $this->printTaskSuccess('Wrote {bytes} (reduced by {reduction} / {percentage})', $context); + return Result::success($this, 'Asset minified.'); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Scss.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Scss.php new file mode 100644 index 00000000..ffd39345 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/Scss.php @@ -0,0 +1,93 @@ +taskScss([ + * 'scss/default.scss' => 'css/default.css' + * ]) + * ->importDir('assets/styles') + * ->run(); + * ?> + * ``` + * + * Use the following scss compiler in your project: + * + * ``` + * "leafo/scssphp": "~0.1", + * ``` + * + * You can implement additional compilers by extending this task and adding a + * method named after them and overloading the scssCompilers() method to + * inject the name there. + */ +class Scss extends CssPreprocessor +{ + const FORMAT_NAME = 'scss'; + + /** + * @var string[] + */ + protected $compilers = [ + 'scssphp', // https://github.com/leafo/scssphp + ]; + + /** + * scssphp compiler + * @link https://github.com/leafo/scssphp + * + * @param string $file + * + * @return string + */ + protected function scssphp($file) + { + if (!class_exists('\Leafo\ScssPhp\Compiler')) { + return Result::errorMissingPackage($this, 'scssphp', 'leafo/scssphp'); + } + + $scssCode = file_get_contents($file); + $scss = new \Leafo\ScssPhp\Compiler(); + + // set options for the scssphp compiler + if (isset($this->compilerOptions['importDirs'])) { + $scss->setImportPaths($this->compilerOptions['importDirs']); + } + + if (isset($this->compilerOptions['formatter'])) { + $scss->setFormatter($this->compilerOptions['formatter']); + } + + return $scss->compile($scssCode); + } + + /** + * Sets the formatter for scssphp + * + * The method setFormatter($formatterName) sets the current formatter to $formatterName, + * the name of a class as a string that implements the formatting interface. See the source + * for Leafo\ScssPhp\Formatter\Expanded for an example. + * + * Five formatters are included with leafo/scssphp: + * - Leafo\ScssPhp\Formatter\Expanded + * - Leafo\ScssPhp\Formatter\Nested (default) + * - Leafo\ScssPhp\Formatter\Compressed + * - Leafo\ScssPhp\Formatter\Compact + * - Leafo\ScssPhp\Formatter\Crunched + * + * @link http://leafo.github.io/scssphp/docs/#output-formatting + * + * @param string $formatterName + * + * @return $this + */ + public function setFormatter($formatterName) + { + return parent::setFormatter($formatterName); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/loadTasks.php new file mode 100644 index 00000000..12192dd8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Assets/loadTasks.php @@ -0,0 +1,45 @@ +task(Minify::class, $input); + } + + /** + * @param string|string[] $input + * + * @return \Robo\Task\Assets\ImageMinify + */ + protected function taskImageMinify($input) + { + return $this->task(ImageMinify::class, $input); + } + + /** + * @param array $input + * + * @return \Robo\Task\Assets\Less + */ + protected function taskLess($input) + { + return $this->task(Less::class, $input); + } + + /** + * @param array $input + * + * @return \Robo\Task\Assets\Scss + */ + protected function taskScss($input) + { + return $this->task(Scss::class, $input); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/Exec.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/Exec.php new file mode 100644 index 00000000..c3e47917 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/Exec.php @@ -0,0 +1,125 @@ +taskExec('compass')->arg('watch')->run(); + * // or use shortcut + * $this->_exec('compass watch'); + * + * $this->taskExec('compass watch')->background()->run(); + * + * if ($this->taskExec('phpunit .')->run()->wasSuccessful()) { + * $this->say('tests passed'); + * } + * + * ?> + * ``` + */ +class Exec extends BaseTask implements CommandInterface, PrintedInterface, SimulatedInterface +{ + use \Robo\Common\CommandReceiver; + use \Robo\Common\ExecOneCommand; + + /** + * @var static[] + */ + protected static $instances = []; + + /** + * @var string|\Robo\Contract\CommandInterface + */ + protected $command; + + /** + * @param string|\Robo\Contract\CommandInterface $command + */ + public function __construct($command) + { + $this->command = $this->receiveCommand($command); + } + + /** + * + */ + public function __destruct() + { + $this->stop(); + } + + /** + * Executes command in background mode (asynchronously) + * + * @return $this + */ + public function background($arg = true) + { + self::$instances[] = $this; + $this->background = $arg; + return $this; + } + + /** + * {@inheritdoc} + */ + protected function getCommandDescription() + { + return $this->getCommand(); + } + /** + * {@inheritdoc} + */ + public function getCommand() + { + return trim($this->command . $this->arguments); + } + + /** + * {@inheritdoc} + */ + public function simulate($context) + { + $this->printAction($context); + } + + public static function stopRunningJobs() + { + foreach (self::$instances as $instance) { + if ($instance) { + unset($instance); + } + } + } + + /** + * {@inheritdoc} + */ + public function run() + { + // TODO: Symfony 4 requires that we supply the working directory. + $result_data = $this->execute(new Process($this->getCommand(), getcwd())); + return new Result( + $this, + $result_data->getExitCode(), + $result_data->getMessage(), + $result_data->getData() + ); + } +} + +if (function_exists('pcntl_signal')) { + pcntl_signal(SIGTERM, ['Robo\Task\Base\Exec', 'stopRunningJobs']); +} + +register_shutdown_function(['Robo\Task\Base\Exec', 'stopRunningJobs']); diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/ExecStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/ExecStack.php new file mode 100644 index 00000000..51b39ef1 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/ExecStack.php @@ -0,0 +1,23 @@ +taskExecStack() + * ->stopOnFail() + * ->exec('mkdir site') + * ->exec('cd site') + * ->run(); + * + * ?> + * ``` + */ +class ExecStack extends CommandStack +{ +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/ParallelExec.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/ParallelExec.php new file mode 100644 index 00000000..c98b7841 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/ParallelExec.php @@ -0,0 +1,199 @@ +taskParallelExec() + * ->process('php ~/demos/script.php hey') + * ->process('php ~/demos/script.php hoy') + * ->process('php ~/demos/script.php gou') + * ->run(); + * ?> + * ``` + */ +class ParallelExec extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\CommandReceiver; + + /** + * @var Process[] + */ + protected $processes = []; + + /** + * @var null|int + */ + protected $timeout = null; + + /** + * @var null|int + */ + protected $idleTimeout = null; + + /** + * @var null|int + */ + protected $waitInterval = 0; + + /** + * @var bool + */ + protected $isPrinted = false; + + /** + * {@inheritdoc} + */ + public function getPrinted() + { + return $this->isPrinted; + } + + /** + * @param bool $isPrinted + * + * @return $this + */ + public function printed($isPrinted = true) + { + $this->isPrinted = $isPrinted; + return $this; + } + + /** + * @param string|\Robo\Contract\CommandInterface $command + * + * @return $this + */ + public function process($command) + { + // TODO: Symfony 4 requires that we supply the working directory. + $this->processes[] = new Process($this->receiveCommand($command), getcwd()); + return $this; + } + + /** + * Stops process if it runs longer then `$timeout` (seconds). + * + * @param int $timeout + * + * @return $this + */ + public function timeout($timeout) + { + $this->timeout = $timeout; + return $this; + } + + /** + * Stops process if it does not output for time longer then `$timeout` (seconds). + * + * @param int $idleTimeout + * + * @return $this + */ + public function idleTimeout($idleTimeout) + { + $this->idleTimeout = $idleTimeout; + return $this; + } + + /** + * Parallel processing will wait `$waitInterval` seconds after launching each process and before + * the next one. + * + * @param int $waitInterval + * + * @return $this + */ + public function waitInterval($waitInterval) + { + $this->waitInterval = $waitInterval; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return implode(' && ', $this->processes); + } + + /** + * @return int + */ + public function progressIndicatorSteps() + { + return count($this->processes); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->startProgressIndicator(); + $running = []; + $queue = $this->processes; + $nextTime = time(); + while (true) { + if (($nextTime <= time()) && !empty($queue)) { + $process = array_shift($queue); + $process->setIdleTimeout($this->idleTimeout); + $process->setTimeout($this->timeout); + $process->start(); + $this->printTaskInfo($process->getCommandLine()); + $running[] = $process; + $nextTime = time() + $this->waitInterval; + } + foreach ($running as $k => $process) { + try { + $process->checkTimeout(); + } catch (ProcessTimedOutException $e) { + $this->printTaskWarning("Process timed out for {command}", ['command' => $process->getCommandLine(), '_style' => ['command' => 'fg=white;bg=magenta']]); + } + if (!$process->isRunning()) { + $this->advanceProgressIndicator(); + if ($this->isPrinted) { + $this->printTaskInfo("Output for {command}:\n\n{output}", ['command' => $process->getCommandLine(), 'output' => $process->getOutput(), '_style' => ['command' => 'fg=white;bg=magenta']]); + $errorOutput = $process->getErrorOutput(); + if ($errorOutput) { + $this->printTaskError(rtrim($errorOutput)); + } + } + unset($running[$k]); + } + } + if (empty($running) && empty($queue)) { + break; + } + usleep(1000); + } + $this->stopProgressIndicator(); + + $errorMessage = ''; + $exitCode = 0; + foreach ($this->processes as $p) { + if ($p->getExitCode() === 0) { + continue; + } + $errorMessage .= "'" . $p->getCommandLine() . "' exited with code ". $p->getExitCode()." \n"; + $exitCode = max($exitCode, $p->getExitCode()); + } + if (!$errorMessage) { + $this->printTaskSuccess('{process-count} processes finished running', ['process-count' => count($this->processes)]); + } + + return new Result($this, $exitCode, $errorMessage, ['time' => $this->getExecutionTime()]); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/SymfonyCommand.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/SymfonyCommand.php new file mode 100644 index 00000000..708ea845 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/SymfonyCommand.php @@ -0,0 +1,75 @@ +taskSymfonyCommand(new \Codeception\Command\Run('run')) + * ->arg('suite','acceptance') + * ->opt('debug') + * ->run(); + * + * // Artisan Command + * $this->taskSymfonyCommand(new ModelGeneratorCommand()) + * ->arg('name', 'User') + * ->run(); + * ?> + * ``` + */ +class SymfonyCommand extends BaseTask +{ + /** + * @var \Symfony\Component\Console\Command\Command + */ + protected $command; + + /** + * @var string[] + */ + protected $input; + + public function __construct(Command $command) + { + $this->command = $command; + $this->input = []; + } + + /** + * @param string $arg + * @param string $value + * + * @return $this + */ + public function arg($arg, $value) + { + $this->input[$arg] = $value; + return $this; + } + + public function opt($option, $value = null) + { + $this->input["--$option"] = $value; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running command {command}', ['command' => $this->command->getName()]); + return new Result( + $this, + $this->command->run(new ArrayInput($this->input), Robo::output()) + ); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/Watch.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/Watch.php new file mode 100644 index 00000000..d7940ac9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/Watch.php @@ -0,0 +1,89 @@ +taskWatch() + * ->monitor('composer.json', function() { + * $this->taskComposerUpdate()->run(); + * })->monitor('src', function() { + * $this->taskExec('phpunit')->run(); + * })->run(); + * ?> + * ``` + */ +class Watch extends BaseTask +{ + /** + * @var \Closure + */ + protected $closure; + + /** + * @var array + */ + protected $monitor = []; + + /** + * @var object + */ + protected $bindTo; + + /** + * @param $bindTo + */ + public function __construct($bindTo) + { + $this->bindTo = $bindTo; + } + + /** + * @param string|string[] $paths + * @param \Closure $callable + * + * @return $this + */ + public function monitor($paths, \Closure $callable) + { + if (!is_array($paths)) { + $paths = [$paths]; + } + $this->monitor[] = [$paths, $callable]; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!class_exists('Lurker\\ResourceWatcher')) { + return Result::errorMissingPackage($this, 'ResourceWatcher', 'henrikbjorn/lurker'); + } + + $watcher = new ResourceWatcher(); + + foreach ($this->monitor as $k => $monitor) { + /** @var \Closure $closure */ + $closure = $monitor[1]; + $closure->bindTo($this->bindTo); + foreach ($monitor[0] as $i => $dir) { + $watcher->track("fs.$k.$i", $dir, FilesystemEvent::MODIFY); + $this->printTaskInfo('Watching {dir} for changes...', ['dir' => $dir]); + $watcher->addListener("fs.$k.$i", $closure); + } + } + + $watcher->start(); + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/loadShortcuts.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/loadShortcuts.php new file mode 100644 index 00000000..dba0af66 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/loadShortcuts.php @@ -0,0 +1,17 @@ +taskExec($command)->run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/loadTasks.php new file mode 100644 index 00000000..ab5301bb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Base/loadTasks.php @@ -0,0 +1,48 @@ +task(Exec::class, $command); + } + + /** + * @return ExecStack + */ + protected function taskExecStack() + { + return $this->task(ExecStack::class); + } + + /** + * @return ParallelExec + */ + protected function taskParallelExec() + { + return $this->task(ParallelExec::class); + } + + /** + * @param $command + * @return SymfonyCommand + */ + protected function taskSymfonyCommand($command) + { + return $this->task(SymfonyCommand::class, $command); + } + + /** + * @return Watch + */ + protected function taskWatch() + { + return $this->task(Watch::class, $this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/BaseTask.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/BaseTask.php new file mode 100644 index 00000000..66155c09 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/BaseTask.php @@ -0,0 +1,60 @@ +logger) { + $child->setLogger($this->logger); + } + if ($child instanceof ProgressIndicatorAwareInterface && $this->progressIndicator) { + $child->setProgressIndicator($this->progressIndicator); + } + if ($child instanceof ConfigAwareInterface && $this->getConfig()) { + $child->setConfig($this->getConfig()); + } + if ($child instanceof VerbosityThresholdInterface && $this->outputAdapter()) { + $child->setOutputAdapter($this->outputAdapter()); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Base.php new file mode 100644 index 00000000..9bc614c6 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Base.php @@ -0,0 +1,88 @@ +option('allow-root'); + return $this; + } + + /** + * adds `force-latest` option to bower + * + * @return $this + */ + public function forceLatest() + { + $this->option('force-latest'); + return $this; + } + + /** + * adds `production` option to bower + * + * @return $this + */ + public function noDev() + { + $this->option('production'); + return $this; + } + + /** + * adds `offline` option to bower + * + * @return $this + */ + public function offline() + { + $this->option('offline'); + return $this; + } + + /** + * Base constructor. + * + * @param null|string $pathToBower + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToBower = null) + { + $this->command = $pathToBower; + if (!$this->command) { + $this->command = $this->findExecutable('bower'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Bower executable not found."); + } + } + + /** + * @return string + */ + public function getCommand() + { + return "{$this->command} {$this->action}{$this->arguments}"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Install.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Install.php new file mode 100644 index 00000000..c3c0ce75 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Install.php @@ -0,0 +1,36 @@ +taskBowerInstall()->run(); + * + * // prefer dist with custom path + * $this->taskBowerInstall('path/to/my/bower') + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class Install extends Base implements CommandInterface +{ + /** + * {@inheritdoc} + */ + protected $action = 'install'; + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Install Bower packages: {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Update.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Update.php new file mode 100644 index 00000000..f0dfa94e --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/Update.php @@ -0,0 +1,34 @@ +taskBowerUpdate->run(); + * + * // prefer dist with custom path + * $this->taskBowerUpdate('path/to/my/bower') + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class Update extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'update'; + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Update Bower packages: {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/loadTasks.php new file mode 100644 index 00000000..6e33f8ac --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Bower/loadTasks.php @@ -0,0 +1,25 @@ +task(Install::class, $pathToBower); + } + + /** + * @param null|string $pathToBower + * + * @return Update + */ + protected function taskBowerUpdate($pathToBower = null) + { + return $this->task(Update::class, $pathToBower); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/CommandStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/CommandStack.php new file mode 100644 index 00000000..f1cb4492 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/CommandStack.php @@ -0,0 +1,134 @@ +exec); + } + + /** + * @param string $executable + * + * @return $this + */ + public function executable($executable) + { + $this->executable = $executable; + return $this; + } + + /** + * @param string|string[] $command + * + * @return $this + */ + public function exec($command) + { + if (is_array($command)) { + $command = implode(' ', array_filter($command)); + } + + $command = $this->executable . ' ' . $this->stripExecutableFromCommand($command); + $this->exec[] = trim($command); + return $this; + } + + /** + * @param bool $stopOnFail + * + * @return $this + */ + public function stopOnFail($stopOnFail = true) + { + $this->stopOnFail = $stopOnFail; + return $this; + } + + public function result($result) + { + $this->result = $result; + return $this; + } + + /** + * @param string $command + * + * @return string + */ + protected function stripExecutableFromCommand($command) + { + $command = trim($command); + $executable = $this->executable . ' '; + if (strpos($command, $executable) === 0) { + $command = substr($command, strlen($executable)); + } + return $command; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (empty($this->exec)) { + throw new TaskException($this, 'You must add at least one command'); + } + // If 'stopOnFail' is not set, or if there is only one command to run, + // then execute the single command to run. + if (!$this->stopOnFail || (count($this->exec) == 1)) { + $this->printTaskInfo('{command}', ['command' => $this->getCommand()]); + return $this->executeCommand($this->getCommand()); + } + + // When executing multiple commands in 'stopOnFail' mode, run them + // one at a time so that the result will have the exact command + // that failed available to the caller. This is at the expense of + // losing the output from all successful commands. + $data = []; + $message = ''; + $result = null; + foreach ($this->exec as $command) { + $this->printTaskInfo("Executing {command}", ['command' => $command]); + $result = $this->executeCommand($command); + $result->accumulateExecutionTime($data); + $message = $result->accumulateMessage($message); + $data = $result->mergeData($data); + if (!$result->wasSuccessful()) { + return $result; + } + } + + return $result; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Base.php new file mode 100644 index 00000000..de3fe217 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Base.php @@ -0,0 +1,248 @@ +command = $pathToComposer; + if (!$this->command) { + $this->command = $this->findExecutablePhar('composer'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Neither local composer.phar nor global composer installation could be found."); + } + } + + /** + * adds `prefer-dist` option to composer + * + * @return $this + */ + public function preferDist($preferDist = true) + { + if (!$preferDist) { + return $this->preferSource(); + } + $this->prefer = '--prefer-dist'; + return $this; + } + + /** + * adds `prefer-source` option to composer + * + * @return $this + */ + public function preferSource() + { + $this->prefer = '--prefer-source'; + return $this; + } + + /** + * adds `dev` option to composer + * + * @return $this + */ + public function dev($dev = true) + { + if (!$dev) { + return $this->noDev(); + } + $this->dev = '--dev'; + return $this; + } + + /** + * adds `no-dev` option to composer + * + * @return $this + */ + public function noDev() + { + $this->dev = '--no-dev'; + return $this; + } + + /** + * adds `ansi` option to composer + * + * @return $this + */ + public function ansi($ansi = true) + { + if (!$ansi) { + return $this->noAnsi(); + } + $this->ansi = '--ansi'; + return $this; + } + + /** + * adds `no-ansi` option to composer + * + * @return $this + */ + public function noAnsi() + { + $this->ansi = '--no-ansi'; + return $this; + } + + public function interaction($interaction = true) + { + if (!$interaction) { + return $this->noInteraction(); + } + return $this; + } + + /** + * adds `no-interaction` option to composer + * + * @return $this + */ + public function noInteraction() + { + $this->nointeraction = '--no-interaction'; + return $this; + } + + /** + * adds `optimize-autoloader` option to composer + * + * @return $this + */ + public function optimizeAutoloader($optimize = true) + { + if ($optimize) { + $this->option('--optimize-autoloader'); + } + return $this; + } + + /** + * adds `ignore-platform-reqs` option to composer + * + * @return $this + */ + public function ignorePlatformRequirements($ignore = true) + { + $this->option('--ignore-platform-reqs'); + return $this; + } + + /** + * disable plugins + * + * @return $this + */ + public function disablePlugins($disable = true) + { + if ($disable) { + $this->option('--no-plugins'); + } + return $this; + } + + /** + * skip scripts + * + * @return $this + */ + public function noScripts($disable = true) + { + if ($disable) { + $this->option('--no-scripts'); + } + return $this; + } + + /** + * adds `--working-dir $dir` option to composer + * + * @return $this + */ + public function workingDir($dir) + { + $this->option("--working-dir", $dir); + return $this; + } + + /** + * Copy class fields into command options as directed. + */ + public function buildCommand() + { + if (!isset($this->ansi) && $this->getConfig()->get(\Robo\Config\Config::DECORATED)) { + $this->ansi(); + } + if (!isset($this->nointeraction) && !$this->getConfig()->get(\Robo\Config\Config::INTERACTIVE)) { + $this->noInteraction(); + } + $this->option($this->prefer) + ->option($this->dev) + ->option($this->nointeraction) + ->option($this->ansi); + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + if (!$this->built) { + $this->buildCommand(); + $this->built = true; + } + return "{$this->command} {$this->action}{$this->arguments}"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Config.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Config.php new file mode 100644 index 00000000..b5a6bbff --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Config.php @@ -0,0 +1,93 @@ +taskComposerConfig()->set('bin-dir', 'bin/')->run(); + * ?> + * ``` + */ +class Config extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'config'; + + /** + * Set a configuration value + * @return $this + */ + public function set($key, $value) + { + $this->arg($key); + $this->arg($value); + return $this; + } + + /** + * Operate on the global repository + * @return $this + */ + public function useGlobal($useGlobal = true) + { + if ($useGlobal) { + $this->option('global'); + } + return $this; + } + + /** + * @return $this + */ + public function repository($id, $uri, $repoType = 'vcs') + { + $this->arg("repositories.$id"); + $this->arg($repoType); + $this->arg($uri); + return $this; + } + + /** + * @return $this + */ + public function removeRepository($id) + { + $this->option('unset', "repositories.$id"); + return $this; + } + + /** + * @return $this + */ + public function disableRepository($id) + { + $this->arg("repositories.$id"); + $this->arg('false'); + return $this; + } + + /** + * @return $this + */ + public function enableRepository($id) + { + $this->arg("repositories.$id"); + $this->arg('true'); + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Configuring composer.json: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/CreateProject.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/CreateProject.php new file mode 100644 index 00000000..5f979a64 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/CreateProject.php @@ -0,0 +1,112 @@ +taskComposerCreateProject()->source('foo/bar')->target('myBar')->run(); + * ?> + * ``` + */ +class CreateProject extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'create-project'; + + protected $source; + protected $target = ''; + protected $version = ''; + + /** + * @return $this + */ + public function source($source) + { + $this->source = $source; + return $this; + } + + /** + * @return $this + */ + public function target($target) + { + $this->target = $target; + return $this; + } + + /** + * @return $this + */ + public function version($version) + { + $this->version = $version; + return $this; + } + + public function keepVcs($keep = true) + { + if ($keep) { + $this->option('--keep-vcs'); + } + return $this; + } + + public function noInstall($noInstall = true) + { + if ($noInstall) { + $this->option('--no-install'); + } + return $this; + } + + /** + * @return $this + */ + public function repository($repository) + { + if (!empty($repository)) { + $this->option('repository', $repository); + } + return $this; + } + + /** + * @return $this + */ + public function stability($stability) + { + if (!empty($stability)) { + $this->option('stability', $stability); + } + return $this; + } + + public function buildCommand() + { + $this->arg($this->source); + if (!empty($this->target)) { + $this->arg($this->target); + } + if (!empty($this->version)) { + $this->arg($this->version); + } + + return parent::buildCommand(); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Creating project: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/DumpAutoload.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/DumpAutoload.php new file mode 100644 index 00000000..55b1ea00 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/DumpAutoload.php @@ -0,0 +1,62 @@ +taskComposerDumpAutoload()->run(); + * + * // dump auto loader with custom path + * $this->taskComposerDumpAutoload('path/to/my/composer.phar') + * ->preferDist() + * ->run(); + * + * // optimize autoloader dump with custom path + * $this->taskComposerDumpAutoload('path/to/my/composer.phar') + * ->optimize() + * ->run(); + * + * // optimize autoloader dump with custom path and no dev + * $this->taskComposerDumpAutoload('path/to/my/composer.phar') + * ->optimize() + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class DumpAutoload extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'dump-autoload'; + + /** + * @var string + */ + protected $optimize; + + /** + * @return $this + */ + public function optimize($optimize = true) + { + if ($optimize) { + $this->option("--optimize"); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Dumping Autoloader: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Init.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Init.php new file mode 100644 index 00000000..c841299d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Init.php @@ -0,0 +1,115 @@ +taskComposerInit()->run(); + * ?> + * ``` + */ +class Init extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'init'; + + /** + * @return $this + */ + public function projectName($projectName) + { + $this->option('name', $projectName); + return $this; + } + + /** + * @return $this + */ + public function description($description) + { + $this->option('description', $description); + return $this; + } + + /** + * @return $this + */ + public function author($author) + { + $this->option('author', $author); + return $this; + } + + /** + * @return $this + */ + public function projectType($type) + { + $this->option('type', $type); + return $this; + } + + /** + * @return $this + */ + public function homepage($homepage) + { + $this->option('homepage', $homepage); + return $this; + } + + /** + * 'require' is a keyword, so it cannot be a method name. + * @return $this + */ + public function dependency($project, $version = null) + { + if (isset($version)) { + $project .= ":$version"; + } + $this->option('require', $project); + return $this; + } + + /** + * @return $this + */ + public function stability($stability) + { + $this->option('stability', $stability); + return $this; + } + + /** + * @return $this + */ + public function license($license) + { + $this->option('license', $license); + return $this; + } + + /** + * @return $this + */ + public function repository($repository) + { + $this->option('repository', $repository); + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Creating composer.json: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Install.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Install.php new file mode 100644 index 00000000..76cb9861 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Install.php @@ -0,0 +1,40 @@ +taskComposerInstall()->run(); + * + * // prefer dist with custom path + * $this->taskComposerInstall('path/to/my/composer.phar') + * ->preferDist() + * ->run(); + * + * // optimize autoloader with custom path + * $this->taskComposerInstall('path/to/my/composer.phar') + * ->optimizeAutoloader() + * ->run(); + * ?> + * ``` + */ +class Install extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'install'; + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Installing Packages: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Remove.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Remove.php new file mode 100644 index 00000000..b0316f05 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Remove.php @@ -0,0 +1,85 @@ +taskComposerRemove()->run(); + * ?> + * ``` + */ +class Remove extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'remove'; + + /** + * @return $this + */ + public function dev($dev = true) + { + if ($dev) { + $this->option('--dev'); + } + return $this; + } + + /** + * @return $this + */ + public function noProgress($noProgress = true) + { + if ($noProgress) { + $this->option('--no-progress'); + } + return $this; + } + + /** + * @return $this + */ + public function noUpdate($noUpdate = true) + { + if ($noUpdate) { + $this->option('--no-update'); + } + return $this; + } + + /** + * @return $this + */ + public function updateNoDev($updateNoDev = true) + { + if ($updateNoDev) { + $this->option('--update-no-dev'); + } + return $this; + } + + /** + * @return $this + */ + public function noUpdateWithDependencies($updateWithDependencies = true) + { + if ($updateWithDependencies) { + $this->option('--no-update-with-dependencies'); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Removing packages: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/RequireDependency.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/RequireDependency.php new file mode 100644 index 00000000..6cdbf613 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/RequireDependency.php @@ -0,0 +1,50 @@ +taskComposerRequire()->dependency('foo/bar', '^.2.4.8')->run(); + * ?> + * ``` + */ +class RequireDependency extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'require'; + + /** + * 'require' is a keyword, so it cannot be a method name. + * @return $this + */ + public function dependency($project, $version = null) + { + $project = (array)$project; + + if (isset($version)) { + $project = array_map( + function ($item) use ($version) { + return "$item:$version"; + }, + $project + ); + } + $this->args($project); + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Requiring packages: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Update.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Update.php new file mode 100644 index 00000000..3a0a64af --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Update.php @@ -0,0 +1,40 @@ +taskComposerUpdate()->run(); + * + * // prefer dist with custom path + * $this->taskComposerUpdate('path/to/my/composer.phar') + * ->preferDist() + * ->run(); + * + * // optimize autoloader with custom path + * $this->taskComposerUpdate('path/to/my/composer.phar') + * ->optimizeAutoloader() + * ->run(); + * ?> + * ``` + */ +class Update extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'update'; + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Updating Packages: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Validate.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Validate.php new file mode 100644 index 00000000..adb15854 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/Validate.php @@ -0,0 +1,85 @@ +taskComposerValidate()->run(); + * ?> + * ``` + */ +class Validate extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'validate'; + + /** + * @return $this + */ + public function noCheckAll($noCheckAll = true) + { + if ($noCheckAll) { + $this->option('--no-check-all'); + } + return $this; + } + + /** + * @return $this + */ + public function noCheckLock($noCheckLock = true) + { + if ($noCheckLock) { + $this->option('--no-check-lock'); + } + return $this; + } + + /** + * @return $this + */ + public function noCheckPublish($noCheckPublish = true) + { + if ($noCheckPublish) { + $this->option('--no-check-publish'); + } + return $this; + } + + /** + * @return $this + */ + public function withDependencies($withDependencies = true) + { + if ($withDependencies) { + $this->option('--with-dependencies'); + } + return $this; + } + + /** + * @return $this + */ + public function strict($strict = true) + { + if ($strict) { + $this->option('--strict'); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Validating composer.json: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/loadTasks.php new file mode 100644 index 00000000..6b074ba3 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Composer/loadTasks.php @@ -0,0 +1,95 @@ +task(Install::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Update + */ + protected function taskComposerUpdate($pathToComposer = null) + { + return $this->task(Update::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return DumpAutoload + */ + protected function taskComposerDumpAutoload($pathToComposer = null) + { + return $this->task(DumpAutoload::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Init + */ + protected function taskComposerInit($pathToComposer = null) + { + return $this->task(Init::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Init + */ + protected function taskComposerConfig($pathToComposer = null) + { + return $this->task(Config::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Validate + */ + protected function taskComposerValidate($pathToComposer = null) + { + return $this->task(Validate::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Remove + */ + protected function taskComposerRemove($pathToComposer = null) + { + return $this->task(Remove::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Remove + */ + protected function taskComposerRequire($pathToComposer = null) + { + return $this->task(RequireDependency::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Remove + */ + protected function taskComposerCreateProject($pathToComposer = null) + { + return $this->task(CreateProject::class, $pathToComposer); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/Changelog.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/Changelog.php new file mode 100644 index 00000000..44af6d82 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/Changelog.php @@ -0,0 +1,246 @@ +taskChangelog() + * ->version($version) + * ->change("released to github") + * ->run(); + * ?> + * ``` + * + * Changes can be asked from Console + * + * ``` php + * taskChangelog() + * ->version($version) + * ->askForChanges() + * ->run(); + * ?> + * ``` + */ +class Changelog extends BaseTask implements BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var string + */ + protected $filename; + + /** + * @var array + */ + protected $log = []; + + /** + * @var string + */ + protected $anchor = "# Changelog"; + + /** + * @var string + */ + protected $version = ""; + + /** + * @var string + */ + protected $body = ""; + + /** + * @var string + */ + protected $header = ""; + + /** + * @param string $filename + * + * @return $this + */ + public function filename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * Sets the changelog body text. + * + * This method permits the raw changelog text to be set directly If this is set, $this->log changes will be ignored. + * + * @param string $body + * + * @return $this + */ + public function setBody($body) + { + $this->body = $body; + return $this; + } + + /** + * @param string $header + * + * @return $this + */ + public function setHeader($header) + { + $this->header = $header; + return $this; + } + + /** + * @param string $item + * + * @return $this + */ + public function log($item) + { + $this->log[] = $item; + return $this; + } + + /** + * @param string $anchor + * + * @return $this + */ + public function anchor($anchor) + { + $this->anchor = $anchor; + return $this; + } + + /** + * @param string $version + * + * @return $this + */ + public function version($version) + { + $this->version = $version; + return $this; + } + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * @param array $data + * + * @return $this + */ + public function changes(array $data) + { + $this->log = array_merge($this->log, $data); + return $this; + } + + /** + * @param string $change + * + * @return $this + */ + public function change($change) + { + $this->log[] = $change; + return $this; + } + + /** + * @return array + */ + public function getChanges() + { + return $this->log; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (empty($this->body)) { + if (empty($this->log)) { + return Result::error($this, "Changelog is empty"); + } + $this->body = $this->generateBody(); + } + if (empty($this->header)) { + $this->header = $this->generateHeader(); + } + + $text = $this->header . $this->body; + + if (!file_exists($this->filename)) { + $this->printTaskInfo('Creating {filename}', ['filename' => $this->filename]); + $res = file_put_contents($this->filename, $this->anchor); + if ($res === false) { + return Result::error($this, "File {filename} cant be created", ['filename' => $this->filename]); + } + } + + /** @var \Robo\Result $result */ + // trying to append to changelog for today + $result = $this->collectionBuilder()->taskReplaceInFile($this->filename) + ->from($this->header) + ->to($text) + ->run(); + + if (!isset($result['replaced']) || !$result['replaced']) { + $result = $this->collectionBuilder()->taskReplaceInFile($this->filename) + ->from($this->anchor) + ->to($this->anchor . "\n\n" . $text) + ->run(); + } + + return new Result($this, $result->getExitCode(), $result->getMessage(), $this->log); + } + + /** + * @return \Robo\Result|string + */ + protected function generateBody() + { + $text = implode("\n", array_map([$this, 'processLogRow'], $this->log)); + $text .= "\n"; + + return $text; + } + + /** + * @return string + */ + protected function generateHeader() + { + return "#### {$this->version}\n\n"; + } + + /** + * @param $i + * + * @return string + */ + public function processLogRow($i) + { + return "* $i *" . date('Y-m-d') . "*"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GenerateMarkdownDoc.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GenerateMarkdownDoc.php new file mode 100644 index 00000000..0c3ec26c --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GenerateMarkdownDoc.php @@ -0,0 +1,782 @@ +taskGenDoc('models.md') + * ->docClass('Model\User') // take class Model\User + * ->docClass('Model\Post') // take class Model\Post + * ->filterMethods(function(\ReflectionMethod $r) { + * return $r->isPublic() or $r->isProtected(); // process public and protected methods + * })->processClass(function(\ReflectionClass $r, $text) { + * return "Class ".$r->getName()."\n\n$text\n\n###Methods\n"; + * })->run(); + * ``` + * + * By default this task generates a documentation for each public method of a class. + * It combines method signature with a docblock. Both can be post-processed. + * + * ``` php + * taskGenDoc('models.md') + * ->docClass('Model\User') + * ->processClassSignature(false) // false can be passed to not include class signature + * ->processClassDocBlock(function(\ReflectionClass $r, $text) { + * return "[This is part of application model]\n" . $text; + * })->processMethodSignature(function(\ReflectionMethod $r, $text) { + * return "#### {$r->name}()"; + * })->processMethodDocBlock(function(\ReflectionMethod $r, $text) { + * return strpos($r->name, 'save')===0 ? "[Saves to the database]\n" . $text : $text; + * })->run(); + * ``` + */ +class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var string[] + */ + protected $docClass = []; + + /** + * @var callable + */ + protected $filterMethods; + + /** + * @var callable + */ + protected $filterClasses; + + /** + * @var callable + */ + protected $filterProperties; + + /** + * @var callable + */ + protected $processClass; + + /** + * @var callable|false + */ + protected $processClassSignature; + + /** + * @var callable|false + */ + protected $processClassDocBlock; + + /** + * @var callable|false + */ + protected $processMethod; + + /** + * @var callable|false + */ + protected $processMethodSignature; + + /** + * @var callable|false + */ + protected $processMethodDocBlock; + + /** + * @var callable|false + */ + protected $processProperty; + + /** + * @var callable|false + */ + protected $processPropertySignature; + + /** + * @var callable|false + */ + protected $processPropertyDocBlock; + + /** + * @var callable + */ + protected $reorder; + + /** + * @var callable + */ + protected $reorderMethods; + + /** + * @todo Unused property. + * + * @var callable + */ + protected $reorderProperties; + + /** + * @var string + */ + protected $filename; + + /** + * @var string + */ + protected $prepend = ""; + + /** + * @var string + */ + protected $append = ""; + + /** + * @var string + */ + protected $text; + + /** + * @var string[] + */ + protected $textForClass = []; + + /** + * @param string $filename + * + * @return static + */ + public static function init($filename) + { + return new static($filename); + } + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * Put a class you want to be documented. + * + * @param string $item + * + * @return $this + */ + public function docClass($item) + { + $this->docClass[] = $item; + return $this; + } + + /** + * Using a callback function filter out methods that won't be documented. + * + * @param callable $filterMethods + * + * @return $this + */ + public function filterMethods($filterMethods) + { + $this->filterMethods = $filterMethods; + return $this; + } + + /** + * Using a callback function filter out classes that won't be documented. + * + * @param callable $filterClasses + * + * @return $this + */ + public function filterClasses($filterClasses) + { + $this->filterClasses = $filterClasses; + return $this; + } + + /** + * Using a callback function filter out properties that won't be documented. + * + * @param callable $filterProperties + * + * @return $this + */ + public function filterProperties($filterProperties) + { + $this->filterProperties = $filterProperties; + return $this; + } + + /** + * Post-process class documentation. + * + * @param callable $processClass + * + * @return $this + */ + public function processClass($processClass) + { + $this->processClass = $processClass; + return $this; + } + + /** + * Post-process class signature. Provide *false* to skip. + * + * @param callable|false $processClassSignature + * + * @return $this + */ + public function processClassSignature($processClassSignature) + { + $this->processClassSignature = $processClassSignature; + return $this; + } + + /** + * Post-process class docblock contents. Provide *false* to skip. + * + * @param callable|false $processClassDocBlock + * + * @return $this + */ + public function processClassDocBlock($processClassDocBlock) + { + $this->processClassDocBlock = $processClassDocBlock; + return $this; + } + + /** + * Post-process method documentation. Provide *false* to skip. + * + * @param callable|false $processMethod + * + * @return $this + */ + public function processMethod($processMethod) + { + $this->processMethod = $processMethod; + return $this; + } + + /** + * Post-process method signature. Provide *false* to skip. + * + * @param callable|false $processMethodSignature + * + * @return $this + */ + public function processMethodSignature($processMethodSignature) + { + $this->processMethodSignature = $processMethodSignature; + return $this; + } + + /** + * Post-process method docblock contents. Provide *false* to skip. + * + * @param callable|false $processMethodDocBlock + * + * @return $this + */ + public function processMethodDocBlock($processMethodDocBlock) + { + $this->processMethodDocBlock = $processMethodDocBlock; + return $this; + } + + /** + * Post-process property documentation. Provide *false* to skip. + * + * @param callable|false $processProperty + * + * @return $this + */ + public function processProperty($processProperty) + { + $this->processProperty = $processProperty; + return $this; + } + + /** + * Post-process property signature. Provide *false* to skip. + * + * @param callable|false $processPropertySignature + * + * @return $this + */ + public function processPropertySignature($processPropertySignature) + { + $this->processPropertySignature = $processPropertySignature; + return $this; + } + + /** + * Post-process property docblock contents. Provide *false* to skip. + * + * @param callable|false $processPropertyDocBlock + * + * @return $this + */ + public function processPropertyDocBlock($processPropertyDocBlock) + { + $this->processPropertyDocBlock = $processPropertyDocBlock; + return $this; + } + + /** + * Use a function to reorder classes. + * + * @param callable $reorder + * + * @return $this + */ + public function reorder($reorder) + { + $this->reorder = $reorder; + return $this; + } + + /** + * Use a function to reorder methods in class. + * + * @param callable $reorderMethods + * + * @return $this + */ + public function reorderMethods($reorderMethods) + { + $this->reorderMethods = $reorderMethods; + return $this; + } + + /** + * @param callable $reorderProperties + * + * @return $this + */ + public function reorderProperties($reorderProperties) + { + $this->reorderProperties = $reorderProperties; + return $this; + } + + /** + * @param string $filename + * + * @return $this + */ + public function filename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * Inserts text at the beginning of markdown file. + * + * @param string $prepend + * + * @return $this + */ + public function prepend($prepend) + { + $this->prepend = $prepend; + return $this; + } + + /** + * Inserts text at the end of markdown file. + * + * @param string $append + * + * @return $this + */ + public function append($append) + { + $this->append = $append; + return $this; + } + + /** + * @param string $text + * + * @return $this + */ + public function text($text) + { + $this->text = $text; + return $this; + } + + /** + * @param string $item + * + * @return $this + */ + public function textForClass($item) + { + $this->textForClass[] = $item; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + foreach ($this->docClass as $class) { + $this->printTaskInfo("Processing {class}", ['class' => $class]); + $this->textForClass[$class] = $this->documentClass($class); + } + + if (is_callable($this->reorder)) { + $this->printTaskInfo("Applying reorder function"); + call_user_func_array($this->reorder, [$this->textForClass]); + } + + $this->text = implode("\n", $this->textForClass); + + /** @var \Robo\Result $result */ + $result = $this->collectionBuilder()->taskWriteToFile($this->filename) + ->line($this->prepend) + ->text($this->text) + ->line($this->append) + ->run(); + + $this->printTaskSuccess('{filename} created. {class-count} classes documented', ['filename' => $this->filename, 'class-count' => count($this->docClass)]); + + return new Result($this, $result->getExitCode(), $result->getMessage(), $this->textForClass); + } + + /** + * @param string $class + * + * @return null|string + */ + protected function documentClass($class) + { + if (!class_exists($class)) { + return ""; + } + $refl = new \ReflectionClass($class); + + if (is_callable($this->filterClasses)) { + $ret = call_user_func($this->filterClasses, $refl); + if (!$ret) { + return; + } + } + $doc = $this->documentClassSignature($refl); + $doc .= "\n" . $this->documentClassDocBlock($refl); + $doc .= "\n"; + + if (is_callable($this->processClass)) { + $doc = call_user_func($this->processClass, $refl, $doc); + } + + $properties = []; + foreach ($refl->getProperties() as $reflProperty) { + $properties[] = $this->documentProperty($reflProperty); + } + + $properties = array_filter($properties); + $doc .= implode("\n", $properties); + + $methods = []; + foreach ($refl->getMethods() as $reflMethod) { + $methods[$reflMethod->name] = $this->documentMethod($reflMethod); + } + if (is_callable($this->reorderMethods)) { + call_user_func_array($this->reorderMethods, [&$methods]); + } + + $methods = array_filter($methods); + + $doc .= implode("\n", $methods)."\n"; + + return $doc; + } + + /** + * @param \ReflectionClass $reflectionClass + * + * @return string + */ + protected function documentClassSignature(\ReflectionClass $reflectionClass) + { + if ($this->processClassSignature === false) { + return ""; + } + + $signature = "## {$reflectionClass->name}\n\n"; + + if ($parent = $reflectionClass->getParentClass()) { + $signature .= "* *Extends* `{$parent->name}`"; + } + $interfaces = $reflectionClass->getInterfaceNames(); + if (count($interfaces)) { + $signature .= "\n* *Implements* `" . implode('`, `', $interfaces) . '`'; + } + $traits = $reflectionClass->getTraitNames(); + if (count($traits)) { + $signature .= "\n* *Uses* `" . implode('`, `', $traits) . '`'; + } + if (is_callable($this->processClassSignature)) { + $signature = call_user_func($this->processClassSignature, $reflectionClass, $signature); + } + + return $signature; + } + + /** + * @param \ReflectionClass $reflectionClass + * + * @return string + */ + protected function documentClassDocBlock(\ReflectionClass $reflectionClass) + { + if ($this->processClassDocBlock === false) { + return ""; + } + $doc = self::indentDoc($reflectionClass->getDocComment()); + if (is_callable($this->processClassDocBlock)) { + $doc = call_user_func($this->processClassDocBlock, $reflectionClass, $doc); + } + return $doc; + } + + /** + * @param \ReflectionMethod $reflectedMethod + * + * @return string + */ + protected function documentMethod(\ReflectionMethod $reflectedMethod) + { + if ($this->processMethod === false) { + return ""; + } + if (is_callable($this->filterMethods)) { + $ret = call_user_func($this->filterMethods, $reflectedMethod); + if (!$ret) { + return ""; + } + } else { + if (!$reflectedMethod->isPublic()) { + return ""; + } + } + + $signature = $this->documentMethodSignature($reflectedMethod); + $docblock = $this->documentMethodDocBlock($reflectedMethod); + $methodDoc = "$signature $docblock"; + if (is_callable($this->processMethod)) { + $methodDoc = call_user_func($this->processMethod, $reflectedMethod, $methodDoc); + } + return $methodDoc; + } + + /** + * @param \ReflectionProperty $reflectedProperty + * + * @return string + */ + protected function documentProperty(\ReflectionProperty $reflectedProperty) + { + if ($this->processProperty === false) { + return ""; + } + if (is_callable($this->filterProperties)) { + $ret = call_user_func($this->filterProperties, $reflectedProperty); + if (!$ret) { + return ""; + } + } else { + if (!$reflectedProperty->isPublic()) { + return ""; + } + } + $signature = $this->documentPropertySignature($reflectedProperty); + $docblock = $this->documentPropertyDocBlock($reflectedProperty); + $propertyDoc = $signature . $docblock; + if (is_callable($this->processProperty)) { + $propertyDoc = call_user_func($this->processProperty, $reflectedProperty, $propertyDoc); + } + return $propertyDoc; + } + + /** + * @param \ReflectionProperty $reflectedProperty + * + * @return string + */ + protected function documentPropertySignature(\ReflectionProperty $reflectedProperty) + { + if ($this->processPropertySignature === false) { + return ""; + } + $modifiers = implode(' ', \Reflection::getModifierNames($reflectedProperty->getModifiers())); + $signature = "#### *$modifiers* {$reflectedProperty->name}"; + if (is_callable($this->processPropertySignature)) { + $signature = call_user_func($this->processPropertySignature, $reflectedProperty, $signature); + } + return $signature; + } + + /** + * @param \ReflectionProperty $reflectedProperty + * + * @return string + */ + protected function documentPropertyDocBlock(\ReflectionProperty $reflectedProperty) + { + if ($this->processPropertyDocBlock === false) { + return ""; + } + $propertyDoc = $reflectedProperty->getDocComment(); + // take from parent + if (!$propertyDoc) { + $parent = $reflectedProperty->getDeclaringClass(); + while ($parent = $parent->getParentClass()) { + if ($parent->hasProperty($reflectedProperty->name)) { + $propertyDoc = $parent->getProperty($reflectedProperty->name)->getDocComment(); + } + } + } + $propertyDoc = self::indentDoc($propertyDoc, 7); + $propertyDoc = preg_replace("~^@(.*?)([$\s])~", ' * `$1` $2', $propertyDoc); // format annotations + if (is_callable($this->processPropertyDocBlock)) { + $propertyDoc = call_user_func($this->processPropertyDocBlock, $reflectedProperty, $propertyDoc); + } + return ltrim($propertyDoc); + } + + /** + * @param \ReflectionParameter $param + * + * @return string + */ + protected function documentParam(\ReflectionParameter $param) + { + $text = ""; + if ($param->isArray()) { + $text .= 'array '; + } + if ($param->isCallable()) { + $text .= 'callable '; + } + $text .= '$' . $param->name; + if ($param->isDefaultValueAvailable()) { + if ($param->allowsNull()) { + $text .= ' = null'; + } else { + $text .= ' = ' . str_replace("\n", ' ', print_r($param->getDefaultValue(), true)); + } + } + + return $text; + } + + /** + * @param string $doc + * @param int $indent + * + * @return string + */ + public static function indentDoc($doc, $indent = 3) + { + if (!$doc) { + return $doc; + } + return implode( + "\n", + array_map( + function ($line) use ($indent) { + return substr($line, $indent); + }, + explode("\n", $doc) + ) + ); + } + + /** + * @param \ReflectionMethod $reflectedMethod + * + * @return string + */ + protected function documentMethodSignature(\ReflectionMethod $reflectedMethod) + { + if ($this->processMethodSignature === false) { + return ""; + } + $modifiers = implode(' ', \Reflection::getModifierNames($reflectedMethod->getModifiers())); + $params = implode( + ', ', + array_map( + function ($p) { + return $this->documentParam($p); + }, + $reflectedMethod->getParameters() + ) + ); + $signature = "#### *$modifiers* {$reflectedMethod->name}($params)"; + if (is_callable($this->processMethodSignature)) { + $signature = call_user_func($this->processMethodSignature, $reflectedMethod, $signature); + } + return $signature; + } + + /** + * @param \ReflectionMethod $reflectedMethod + * + * @return string + */ + protected function documentMethodDocBlock(\ReflectionMethod $reflectedMethod) + { + if ($this->processMethodDocBlock === false) { + return ""; + } + $methodDoc = $reflectedMethod->getDocComment(); + // take from parent + if (!$methodDoc) { + $parent = $reflectedMethod->getDeclaringClass(); + while ($parent = $parent->getParentClass()) { + if ($parent->hasMethod($reflectedMethod->name)) { + $methodDoc = $parent->getMethod($reflectedMethod->name)->getDocComment(); + } + } + } + // take from interface + if (!$methodDoc) { + $interfaces = $reflectedMethod->getDeclaringClass()->getInterfaces(); + foreach ($interfaces as $interface) { + $i = new \ReflectionClass($interface->name); + if ($i->hasMethod($reflectedMethod->name)) { + $methodDoc = $i->getMethod($reflectedMethod->name)->getDocComment(); + break; + } + } + } + + $methodDoc = self::indentDoc($methodDoc, 7); + $methodDoc = preg_replace("~^@(.*?) ([$\s])~m", ' * `$1` $2', $methodDoc); // format annotations + if (is_callable($this->processMethodDocBlock)) { + $methodDoc = call_user_func($this->processMethodDocBlock, $reflectedMethod, $methodDoc); + } + + return $methodDoc; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GenerateTask.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GenerateTask.php new file mode 100644 index 00000000..9d7a698e --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GenerateTask.php @@ -0,0 +1,107 @@ +taskGenerateTask('Symfony\Component\Filesystem\Filesystem', 'FilesystemStack') + * ->run(); + * ``` + */ +class GenerateTask extends BaseTask +{ + /** + * @var string + */ + protected $className; + + /** + * @var string + */ + protected $wrapperClassName; + + /** + * @param string $className + * @param string $wrapperClassName + */ + public function __construct($className, $wrapperClassName = '') + { + $this->className = $className; + $this->wrapperClassName = $wrapperClassName; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $delegate = new \ReflectionClass($this->className); + $replacements = []; + + $leadingCommentChars = " * "; + $methodDescriptions = []; + $methodImplementations = []; + $immediateMethods = []; + foreach ($delegate->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { + $methodName = $method->name; + $getter = preg_match('/^(get|has|is)/', $methodName); + $setter = preg_match('/^(set|unset)/', $methodName); + $argPrototypeList = []; + $argNameList = []; + $needsImplementation = false; + foreach ($method->getParameters() as $arg) { + $argDescription = '$' . $arg->name; + $argNameList[] = $argDescription; + if ($arg->isOptional()) { + $argDescription = $argDescription . ' = ' . str_replace("\n", "", var_export($arg->getDefaultValue(), true)); + // We will create wrapper methods for any method that + // has default parameters. + $needsImplementation = true; + } + $argPrototypeList[] = $argDescription; + } + $argPrototypeString = implode(', ', $argPrototypeList); + $argNameListString = implode(', ', $argNameList); + + if ($methodName[0] != '_') { + $methodDescriptions[] = "@method $methodName($argPrototypeString)"; + + if ($getter) { + $immediateMethods[] = " public function $methodName($argPrototypeString)\n {\n return \$this->delegate->$methodName($argNameListString);\n }"; + } elseif ($setter) { + $immediateMethods[] = " public function $methodName($argPrototypeString)\n {\n \$this->delegate->$methodName($argNameListString);\n return \$this;\n }"; + } elseif ($needsImplementation) { + // Include an implementation for the wrapper method if necessary + $methodImplementations[] = " protected function _$methodName($argPrototypeString)\n {\n \$this->delegate->$methodName($argNameListString);\n }"; + } + } + } + + $classNameParts = explode('\\', $this->className); + $delegate = array_pop($classNameParts); + $delegateNamespace = implode('\\', $classNameParts); + + if (empty($this->wrapperClassName)) { + $this->wrapperClassName = $delegate; + } + + $replacements['{delegateNamespace}'] = $delegateNamespace; + $replacements['{delegate}'] = $delegate; + $replacements['{wrapperClassName}'] = $this->wrapperClassName; + $replacements['{taskname}'] = "task$delegate"; + $replacements['{methodList}'] = $leadingCommentChars . implode("\n$leadingCommentChars", $methodDescriptions); + $replacements['{immediateMethods}'] = "\n\n" . implode("\n\n", $immediateMethods); + $replacements['{methodImplementations}'] = "\n\n" . implode("\n\n", $methodImplementations); + + $template = file_get_contents(__DIR__ . '/../../../data/Task/Development/GeneratedWrapper.tmpl'); + $template = str_replace(array_keys($replacements), array_values($replacements), $template); + + // Returning data in the $message will cause it to be printed. + return Result::success($this, $template); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GitHub.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GitHub.php new file mode 100644 index 00000000..9fc9909d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GitHub.php @@ -0,0 +1,157 @@ +repo = $repo; + return $this; + } + + /** + * @param string $owner + * + * @return $this + */ + public function owner($owner) + { + $this->owner = $owner; + return $this; + } + + /** + * @param string $uri + * + * @return $this + */ + public function uri($uri) + { + list($this->owner, $this->repo) = explode('/', $uri); + return $this; + } + + /** + * @return string + */ + protected function getUri() + { + return $this->owner . '/' . $this->repo; + } + + /** + * @param string $user + * + * @return $this + */ + public function user($user) + { + $this->user = $user; + return $this; + } + + /** + * @param $password + * + * @return $this + */ + public function password($password) + { + $this->password = $password; + return $this; + } + + /** + * @param $accessToken + * + * @return $this + */ + public function accessToken($token) + { + $this->accessToken = $token; + return $this; + } + + /** + * @param string $uri + * @param array $params + * @param string $method + * + * @return array + * + * @throws \Robo\Exception\TaskException + */ + protected function sendRequest($uri, $params = [], $method = 'POST') + { + if (!$this->owner or !$this->repo) { + throw new TaskException($this, 'Repo URI is not set'); + } + + $ch = curl_init(); + $url = sprintf('%s/repos/%s/%s', self::GITHUB_URL, $this->getUri(), $uri); + $this->printTaskInfo($url); + $this->printTaskInfo('{method} {url}', ['method' => $method, 'url' => $url]); + + if (!empty($this->user)) { + curl_setopt($ch, CURLOPT_USERPWD, $this->user . ':' . $this->password); + } + + if (!empty($this->accessToken)) { + $url .= "?access_token=" . $this->accessToken; + } + + curl_setopt_array( + $ch, + array( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => $method != 'GET', + CURLOPT_POSTFIELDS => json_encode($params), + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_USERAGENT => "Robo" + ) + ); + + $output = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $response = json_decode($output); + + $this->printTaskInfo($output); + return [$code, $response]; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GitHubRelease.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GitHubRelease.php new file mode 100644 index 00000000..bf7a4889 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/GitHubRelease.php @@ -0,0 +1,208 @@ +taskGitHubRelease('0.1.0') + * ->uri('consolidation-org/Robo') + * ->description('Add stuff people need.') + * ->change('Fix #123') + * ->change('Add frobulation method to all widgets') + * ->run(); + * ?> + * ``` + */ +class GitHubRelease extends GitHub +{ + /** + * @var string + */ + protected $tag; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $description = ''; + + /** + * @var string[] + */ + protected $changes = []; + + /** + * @var bool + */ + protected $draft = false; + + /** + * @var bool + */ + protected $prerelease = false; + + /** + * @var string + */ + protected $comittish = 'master'; + + /** + * @param string $tag + */ + public function __construct($tag) + { + $this->tag = $tag; + } + + /** + * @param string $tag + * + * @return $this + */ + public function tag($tag) + { + $this->tag = $tag; + return $this; + } + + /** + * @param bool $draft + * + * @return $this + */ + public function draft($draft) + { + $this->draft = $draft; + return $this; + } + + /** + * @param string $name + * + * @return $this + */ + public function name($name) + { + $this->name = $name; + return $this; + } + + /** + * @param string $description + * + * @return $this + */ + public function description($description) + { + $this->description = $description; + return $this; + } + + /** + * @param bool $prerelease + * + * @return $this + */ + public function prerelease($prerelease) + { + $this->prerelease = $prerelease; + return $this; + } + + /** + * @param string $comittish + * + * @return $this + */ + public function comittish($comittish) + { + $this->comittish = $comittish; + return $this; + } + + /** + * @param string $description + * + * @return $this + */ + public function appendDescription($description) + { + if (!empty($this->description)) { + $this->description .= "\n\n"; + } + $this->description .= $description; + return $this; + } + + public function changes(array $changes) + { + $this->changes = array_merge($this->changes, $changes); + return $this; + } + + /** + * @param string $change + * + * @return $this + */ + public function change($change) + { + $this->changes[] = $change; + return $this; + } + + /** + * @return string + */ + protected function getBody() + { + $body = $this->description; + if (!empty($this->changes)) { + $changes = array_map( + function ($line) { + return "* $line"; + }, + $this->changes + ); + $changesText = implode("\n", $changes); + $body .= "### Changelog \n\n$changesText"; + } + return $body; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Releasing {tag}', ['tag' => $this->tag]); + $this->startTimer(); + list($code, $data) = $this->sendRequest( + 'releases', + [ + "tag_name" => $this->tag, + "target_commitish" => $this->comittish, + "name" => $this->name, + "body" => $this->getBody(), + "draft" => $this->draft, + "prerelease" => $this->prerelease + ] + ); + $this->stopTimer(); + + return new Result( + $this, + in_array($code, [200, 201]) ? 0 : 1, + isset($data->message) ? $data->message : '', + ['response' => $data, 'time' => $this->getExecutionTime()] + ); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/OpenBrowser.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/OpenBrowser.php new file mode 100644 index 00000000..ea01b326 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/OpenBrowser.php @@ -0,0 +1,80 @@ +taskOpenBrowser('http://localhost') + * ->run(); + * + * // open two browser windows + * $this->taskOpenBrowser([ + * 'http://localhost/mysite', + * 'http://localhost/mysite2' + * ]) + * ->run(); + * ``` + */ +class OpenBrowser extends BaseTask +{ + /** + * @var string[] + */ + protected $urls = []; + + /** + * @param string|array $url + */ + public function __construct($url) + { + $this->urls = (array) $url; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $openCommand = $this->getOpenCommand(); + + if (empty($openCommand)) { + return Result::error($this, 'no suitable browser opening command found'); + } + + foreach ($this->urls as $url) { + passthru(sprintf($openCommand, ProcessUtils::escapeArgument($url))); + $this->printTaskInfo('Opened {url}', ['url' => $url]); + } + + return Result::success($this); + } + + /** + * @return null|string + */ + private function getOpenCommand() + { + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + return 'start "web" explorer "%s"'; + } + + passthru('which xdg-open', $linux); + passthru('which open', $osx); + + if (0 === $linux) { + return 'xdg-open %s'; + } + + if (0 === $osx) { + return 'open %s'; + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/PackPhar.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/PackPhar.php new file mode 100644 index 00000000..6d0a04d7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/PackPhar.php @@ -0,0 +1,252 @@ +taskPackPhar('package/codecept.phar') + * ->compress() + * ->stub('package/stub.php'); + * + * $finder = Finder::create() + * ->name('*.php') + * ->in('src'); + * + * foreach ($finder as $file) { + * $pharTask->addFile('src/'.$file->getRelativePathname(), $file->getRealPath()); + * } + * + * $finder = Finder::create()->files() + * ->name('*.php') + * ->in('vendor'); + * + * foreach ($finder as $file) { + * $pharTask->addStripped('vendor/'.$file->getRelativePathname(), $file->getRealPath()); + * } + * $pharTask->run(); + * + * // verify Phar is packed correctly + * $code = $this->_exec('php package/codecept.phar'); + * ?> + * ``` + */ +class PackPhar extends BaseTask implements PrintedInterface, ProgressIndicatorAwareInterface +{ + /** + * @var \Phar + */ + protected $phar; + + /** + * @var null|string + */ + protected $compileDir = null; + + /** + * @var string + */ + protected $filename; + + /** + * @var bool + */ + protected $compress = false; + + protected $stub; + + protected $bin; + + /** + * @var string + */ + protected $stubTemplate = <<filename = $filename; + if (file_exists($file->getRealPath())) { + @unlink($file->getRealPath()); + } + $this->phar = new \Phar($file->getPathname(), 0, $file->getFilename()); + } + + /** + * @param bool $compress + * + * @return $this + */ + public function compress($compress = true) + { + $this->compress = $compress; + return $this; + } + + /** + * @param string $stub + * + * @return $this + */ + public function stub($stub) + { + $this->phar->setStub(file_get_contents($stub)); + return $this; + } + + /** + * {@inheritdoc} + */ + public function progressIndicatorSteps() + { + // run() will call advanceProgressIndicator() once for each + // file, one after calling stopBuffering, and again after compression. + return count($this->files)+2; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Creating {filename}', ['filename' => $this->filename]); + $this->phar->setSignatureAlgorithm(\Phar::SHA1); + $this->phar->startBuffering(); + + $this->printTaskInfo('Packing {file-count} files into phar', ['file-count' => count($this->files)]); + + $this->startProgressIndicator(); + foreach ($this->files as $path => $content) { + $this->phar->addFromString($path, $content); + $this->advanceProgressIndicator(); + } + $this->phar->stopBuffering(); + $this->advanceProgressIndicator(); + + if ($this->compress and in_array('GZ', \Phar::getSupportedCompression())) { + if (count($this->files) > 1000) { + $this->printTaskInfo('Too many files. Compression DISABLED'); + } else { + $this->printTaskInfo('{filename} compressed', ['filename' => $this->filename]); + $this->phar = $this->phar->compressFiles(\Phar::GZ); + } + } + $this->advanceProgressIndicator(); + $this->stopProgressIndicator(); + $this->printTaskSuccess('{filename} produced', ['filename' => $this->filename]); + return Result::success($this, '', ['time' => $this->getExecutionTime()]); + } + + /** + * @param string $path + * @param string $file + * + * @return $this + */ + public function addStripped($path, $file) + { + $this->files[$path] = $this->stripWhitespace(file_get_contents($file)); + return $this; + } + + /** + * @param string $path + * @param string $file + * + * @return $this + */ + public function addFile($path, $file) + { + $this->files[$path] = file_get_contents($file); + return $this; + } + + /** + * @param \Symfony\Component\Finder\SplFileInfo[] $files + */ + public function addFiles($files) + { + foreach ($files as $file) { + $this->addFile($file->getRelativePathname(), $file->getRealPath()); + } + } + + /** + * @param string $file + * + * @return $this + */ + public function executable($file) + { + $source = file_get_contents($file); + if (strpos($source, '#!/usr/bin/env php') === 0) { + $source = substr($source, strpos($source, 'phar->setStub(sprintf($this->stubTemplate, $source)); + return $this; + } + + /** + * Strips whitespace from source. Taken from composer + * + * @param string $source + * + * @return string + */ + private function stripWhitespace($source) + { + if (!function_exists('token_get_all')) { + return $source; + } + + $output = ''; + foreach (token_get_all($source) as $token) { + if (is_string($token)) { + $output .= $token; + } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { + // $output .= $token[1]; + $output .= str_repeat("\n", substr_count($token[1], "\n")); + } elseif (T_WHITESPACE === $token[0]) { + // reduce wide spaces + $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]); + // normalize newlines to \n + $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace); + // trim leading spaces + $whitespace = preg_replace('{\n +}', "\n", $whitespace); + $output .= $whitespace; + } else { + $output .= $token[1]; + } + } + + return $output; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/PhpServer.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/PhpServer.php new file mode 100644 index 00000000..6dd36680 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/PhpServer.php @@ -0,0 +1,86 @@ +taskServer(8000) + * ->dir('public') + * ->run(); + * + * // run with IP 0.0.0.0 + * $this->taskServer(8000) + * ->host('0.0.0.0') + * ->run(); + * + * // execute server in background + * $this->taskServer(8000) + * ->background() + * ->run(); + * ?> + * ``` + */ +class PhpServer extends Exec +{ + /** + * @var int + */ + protected $port; + + /** + * @var string + */ + protected $host = '127.0.0.1'; + + /** + * {@inheritdoc} + */ + protected $command = 'php -S %s:%d '; + + /** + * @param int $port + */ + public function __construct($port) + { + $this->port = $port; + + if (strtolower(PHP_OS) === 'linux') { + $this->command = 'exec php -S %s:%d '; + } + } + + /** + * @param string $host + * + * @return $this + */ + public function host($host) + { + $this->host = $host; + return $this; + } + + /** + * @param string $path + * + * @return $this + */ + public function dir($path) + { + $this->command .= "-t $path"; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return sprintf($this->command . $this->arguments, $this->host, $this->port); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/SemVer.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/SemVer.php new file mode 100644 index 00000000..6c807d89 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/SemVer.php @@ -0,0 +1,255 @@ +taskSemVer('.semver') + * ->increment() + * ->run(); + * ?> + * ``` + * + */ +class SemVer implements TaskInterface +{ + const SEMVER = "---\n:major: %d\n:minor: %d\n:patch: %d\n:special: '%s'\n:metadata: '%s'"; + + const REGEX = "/^\-\-\-\n:major:\s(0|[1-9]\d*)\n:minor:\s(0|[1-9]\d*)\n:patch:\s(0|[1-9]\d*)\n:special:\s'([a-zA-z0-9]*\.?(?:0|[1-9]\d*)?)'\n:metadata:\s'((?:0|[1-9]\d*)?(?:\.[a-zA-z0-9\.]*)?)'/"; + + const REGEX_STRING = '/^(?[0-9]+)\.(?[0-9]+)\.(?[0-9]+)(|-(?[0-9a-zA-Z.]+))(|\+(?[0-9a-zA-Z.]+))$/'; + + /** + * @var string + */ + protected $format = 'v%M.%m.%p%s'; + + /** + * @var string + */ + protected $specialSeparator = '-'; + + /** + * @var string + */ + protected $metadataSeparator = '+'; + + /** + * @var string + */ + protected $path; + + /** + * @var array + */ + protected $version = [ + 'major' => 0, + 'minor' => 0, + 'patch' => 0, + 'special' => '', + 'metadata' => '' + ]; + + /** + * @param string $filename + */ + public function __construct($filename = '') + { + $this->path = $filename; + + if (file_exists($this->path)) { + $semverFileContents = file_get_contents($this->path); + $this->parseFile($semverFileContents); + } + } + + /** + * @return string + */ + public function __toString() + { + $search = ['%M', '%m', '%p', '%s']; + $replace = $this->version + ['extra' => '']; + + foreach (['special', 'metadata'] as $key) { + if (!empty($replace[$key])) { + $separator = $key . 'Separator'; + $replace['extra'] .= $this->{$separator} . $replace[$key]; + } + unset($replace[$key]); + } + + return str_replace($search, $replace, $this->format); + } + + public function version($version) + { + $this->parseString($version); + return $this; + } + + /** + * @param string $format + * + * @return $this + */ + public function setFormat($format) + { + $this->format = $format; + return $this; + } + + /** + * @param string $separator + * + * @return $this + */ + public function setMetadataSeparator($separator) + { + $this->metadataSeparator = $separator; + return $this; + } + + /** + * @param string $separator + * + * @return $this + */ + public function setPrereleaseSeparator($separator) + { + $this->specialSeparator = $separator; + return $this; + } + + /** + * @param string $what + * + * @return $this + * + * @throws \Robo\Exception\TaskException + */ + public function increment($what = 'patch') + { + switch ($what) { + case 'major': + $this->version['major']++; + $this->version['minor'] = 0; + $this->version['patch'] = 0; + break; + case 'minor': + $this->version['minor']++; + $this->version['patch'] = 0; + break; + case 'patch': + $this->version['patch']++; + break; + default: + throw new TaskException( + $this, + 'Bad argument, only one of the following is allowed: major, minor, patch' + ); + } + return $this; + } + + /** + * @param string $tag + * + * @return $this + * + * @throws \Robo\Exception\TaskException + */ + public function prerelease($tag = 'RC') + { + if (!is_string($tag)) { + throw new TaskException($this, 'Bad argument, only strings allowed.'); + } + + $number = 0; + + if (!empty($this->version['special'])) { + list($current, $number) = explode('.', $this->version['special']); + if ($tag != $current) { + $number = 0; + } + } + + $number++; + + $this->version['special'] = implode('.', [$tag, $number]); + return $this; + } + + /** + * @param array|string $data + * + * @return $this + */ + public function metadata($data) + { + if (is_array($data)) { + $data = implode('.', $data); + } + + $this->version['metadata'] = $data; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $written = $this->dump(); + return new Result($this, (int)($written === false), $this->__toString()); + } + + /** + * @return bool + * + * @throws \Robo\Exception\TaskException + */ + protected function dump() + { + if (empty($this->path)) { + return true; + } + extract($this->version); + $semver = sprintf(self::SEMVER, $major, $minor, $patch, $special, $metadata); + if (is_writeable($this->path) === false || file_put_contents($this->path, $semver) === false) { + throw new TaskException($this, 'Failed to write semver file.'); + } + return true; + } + + protected function parseString($semverString) + { + if (!preg_match_all(self::REGEX_STRING, $semverString, $matches)) { + throw new TaskException($this, 'Bad semver value: ' . $semverString); + } + + $this->version = array_intersect_key($matches, $this->version); + $this->version = array_map(function ($item) { + return $item[0]; + }, $this->version); + } + + /** + * @throws \Robo\Exception\TaskException + */ + protected function parseFile($semverFileContents) + { + if (!preg_match_all(self::REGEX, $semverFileContents, $matches)) { + throw new TaskException($this, 'Bad semver file.'); + } + + list(, $major, $minor, $patch, $special, $metadata) = array_map('current', $matches); + $this->version = compact('major', 'minor', 'patch', 'special', 'metadata'); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/loadTasks.php new file mode 100644 index 00000000..e3dc49a3 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Development/loadTasks.php @@ -0,0 +1,86 @@ +task(Changelog::class, $filename); + } + + /** + * @param string $filename + * + * @return GenerateMarkdownDoc + */ + protected function taskGenDoc($filename) + { + return $this->task(GenerateMarkdownDoc::class, $filename); + } + + /** + * @param string $className + * @param string $wrapperClassName + * + * @return \Robo\Task\Development\GenerateTask + */ + protected function taskGenTask($className, $wrapperClassName = '') + { + return $this->task(GenerateTask::class, $className, $wrapperClassName); + } + + /** + * @param string $pathToSemVer + * + * @return SemVer + */ + protected function taskSemVer($pathToSemVer = '.semver') + { + return $this->task(SemVer::class, $pathToSemVer); + } + + /** + * @param int $port + * + * @return PhpServer + */ + protected function taskServer($port = 8000) + { + return $this->task(PhpServer::class, $port); + } + + /** + * @param string $filename + * + * @return PackPhar + */ + protected function taskPackPhar($filename) + { + return $this->task(PackPhar::class, $filename); + } + + /** + * @param string $tag + * + * @return GitHubRelease + */ + protected function taskGitHubRelease($tag) + { + return $this->task(GitHubRelease::class, $tag); + } + + /** + * @param string|array $url + * + * @return OpenBrowser + */ + protected function taskOpenBrowser($url) + { + return $this->task(OpenBrowser::class, $url); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Base.php new file mode 100644 index 00000000..135f39e7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Base.php @@ -0,0 +1,28 @@ +getCommand(); + return $this->executeCommand($command); + } + + abstract public function getCommand(); +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Build.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Build.php new file mode 100644 index 00000000..11eb92ab --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Build.php @@ -0,0 +1,55 @@ +taskDockerBuild()->run(); + * + * $this->taskDockerBuild('path/to/dir') + * ->tag('database') + * ->run(); + * + * ?> + * + * ``` + * + * Class Build + * @package Robo\Task\Docker + */ +class Build extends Base +{ + /** + * @var string + */ + protected $path; + + /** + * @param string $path + */ + public function __construct($path = '.') + { + $this->command = "docker build"; + $this->path = $path; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments . ' ' . $this->path; + } + + /** + * @param string $tag + * + * @return $this + */ + public function tag($tag) + { + return $this->option('-t', $tag); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Commit.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Commit.php new file mode 100644 index 00000000..302f1920 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Commit.php @@ -0,0 +1,66 @@ +taskDockerCommit($containerId) + * ->name('my/database') + * ->run(); + * + * // alternatively you can take the result from DockerRun task: + * + * $result = $this->taskDockerRun('db') + * ->exec('./prepare_database.sh') + * ->run(); + * + * $task->dockerCommit($result) + * ->name('my/database') + * ->run(); + * ``` + */ +class Commit extends Base +{ + /** + * @var string + */ + protected $command = "docker commit"; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $cid; + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + */ + public function __construct($cidOrResult) + { + $this->cid = $cidOrResult instanceof Result ? $cidOrResult->getCid() : $cidOrResult; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->cid . ' ' . $this->name . ' ' . $this->arguments; + } + + /** + * @param $name + * + * @return $this + */ + public function name($name) + { + $this->name = $name; + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Exec.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Exec.php new file mode 100644 index 00000000..fa67c8da --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Exec.php @@ -0,0 +1,95 @@ +taskDockerRun('test_env') + * ->detached() + * ->run(); + * + * $this->taskDockerExec($test) + * ->interactive() + * ->exec('./runtests') + * ->run(); + * + * // alternatively use commands from other tasks + * + * $this->taskDockerExec($test) + * ->interactive() + * ->exec($this->taskCodecept()->suite('acceptance')) + * ->run(); + * ?> + * ``` + * + */ +class Exec extends Base +{ + use CommandReceiver; + + /** + * @var string + */ + protected $command = "docker exec"; + + /** + * @var string + */ + protected $cid; + + /** + * @var string + */ + protected $run = ''; + + /** + * @param string|\Robo\Result $cidOrResult + */ + public function __construct($cidOrResult) + { + $this->cid = $cidOrResult instanceof Result ? $cidOrResult->getCid() : $cidOrResult; + } + + /** + * @return $this + */ + public function detached() + { + $this->option('-d'); + return $this; + } + + /** + * {@inheritdoc)} + */ + public function interactive($interactive = true) + { + if ($interactive) { + $this->option('-i'); + } + return parent::interactive($interactive); + } + + /** + * @param string|\Robo\Contract\CommandInterface $command + * + * @return $this + */ + public function exec($command) + { + $this->run = $this->receiveCommand($command); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments . ' ' . $this->cid.' '.$this->run; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Pull.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Pull.php new file mode 100644 index 00000000..32ba5b40 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Pull.php @@ -0,0 +1,33 @@ +taskDockerPull('wordpress') + * ->run(); + * + * ?> + * ``` + * + */ +class Pull extends Base +{ + /** + * @param string $image + */ + public function __construct($image) + { + $this->command = "docker pull $image "; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Remove.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Remove.php new file mode 100644 index 00000000..0a8c0ac6 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Remove.php @@ -0,0 +1,32 @@ +taskDockerRemove($container) + * ->run(); + * ?> + * ``` + * + */ +class Remove extends Base +{ + /** + * @param string $container + */ + public function __construct($container) + { + $this->command = "docker rm $container "; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Result.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Result.php new file mode 100644 index 00000000..0533159a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Result.php @@ -0,0 +1,35 @@ +taskDockerRun('mysql')->run(); + * + * $result = $this->taskDockerRun('my_db_image') + * ->env('DB', 'database_name') + * ->volume('/path/to/data', '/data') + * ->detached() + * ->publish(3306) + * ->name('my_mysql') + * ->run(); + * + * // retrieve container's cid: + * $this->say("Running container ".$result->getCid()); + * + * // execute script inside container + * $result = $this->taskDockerRun('db') + * ->exec('prepare_test_data.sh') + * ->run(); + * + * $this->taskDockerCommit($result) + * ->name('test_db') + * ->run(); + * + * // link containers + * $mysql = $this->taskDockerRun('mysql') + * ->name('wp_db') // important to set name for linked container + * ->env('MYSQL_ROOT_PASSWORD', '123456') + * ->run(); + * + * $this->taskDockerRun('wordpress') + * ->link($mysql) + * ->publish(80, 8080) + * ->detached() + * ->run(); + * + * ?> + * ``` + * + */ +class Run extends Base +{ + use CommandReceiver; + + /** + * @var string + */ + protected $image = ''; + + /** + * @var string + */ + protected $run = ''; + + /** + * @var string + */ + protected $cidFile; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $dir; + + /** + * @param string $image + */ + public function __construct($image) + { + $this->image = $image; + } + + /** + * {@inheritdoc} + */ + public function getPrinted() + { + return $this->isPrinted; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + if ($this->isPrinted) { + $this->option('-i'); + } + if ($this->cidFile) { + $this->option('cidfile', $this->cidFile); + } + return trim('docker run ' . $this->arguments . ' ' . $this->image . ' ' . $this->run); + } + + /** + * @return $this + */ + public function detached() + { + $this->option('-d'); + return $this; + } + + /** + * {@inheritdoc)} + */ + public function interactive($interactive = true) + { + if ($interactive) { + $this->option('-i'); + } + return parent::interactive($interactive); + } + + /** + * @param string|\Robo\Contract\CommandInterface $run + * + * @return $this + */ + public function exec($run) + { + $this->run = $this->receiveCommand($run); + return $this; + } + + /** + * @param string $from + * @param null|string $to + * + * @return $this + */ + public function volume($from, $to = null) + { + $volume = $to ? "$from:$to" : $from; + $this->option('-v', $volume); + return $this; + } + + /** + * Set environment variables. + * n.b. $this->env($variable, $value) also available here, + * inherited from ExecTrait. + * + * @param array $env + * @return type + */ + public function envVars(array $env) + { + foreach ($env as $variable => $value) { + $this->setDockerEnv($variable, $value); + } + return $this; + } + + /** + * @param string $variable + * @param null|string $value + * + * @return $this + */ + protected function setDockerEnv($variable, $value = null) + { + $env = $value ? "$variable=$value" : $variable; + return $this->option("-e", $env); + } + + /** + * @param null|int $port + * @param null|int $portTo + * + * @return $this + */ + public function publish($port = null, $portTo = null) + { + if (!$port) { + return $this->option('-P'); + } + if ($portTo) { + $port = "$port:$portTo"; + } + return $this->option('-p', $port); + } + + /** + * @param string $dir + * + * @return $this + */ + public function containerWorkdir($dir) + { + return $this->option('-w', $dir); + } + + /** + * @param string $user + * + * @return $this + */ + public function user($user) + { + return $this->option('-u', $user); + } + + /** + * @return $this + */ + public function privileged() + { + return $this->option('--privileged'); + } + + /** + * @param string $name + * + * @return $this + */ + public function name($name) + { + $this->name = $name; + return $this->option('name', $name); + } + + /** + * @param string|\Robo\Task\Docker\Result $name + * @param string $alias + * + * @return $this + */ + public function link($name, $alias) + { + if ($name instanceof Result) { + $name = $name->getContainerName(); + } + $this->option('link', "$name:$alias"); + return $this; + } + + /** + * @param string $dir + * + * @return $this + */ + public function tmpDir($dir) + { + $this->dir = $dir; + return $this; + } + + /** + * @return string + */ + public function getTmpDir() + { + return $this->dir ? $this->dir : sys_get_temp_dir(); + } + + /** + * @return string + */ + public function getUniqId() + { + return uniqid(); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->cidFile = $this->getTmpDir() . '/docker_' . $this->getUniqId() . '.cid'; + $result = parent::run(); + $result['cid'] = $this->getCid(); + return $result; + } + + /** + * @return null|string + */ + protected function getCid() + { + if (!$this->cidFile || !file_exists($this->cidFile)) { + return null; + } + $cid = trim(file_get_contents($this->cidFile)); + @unlink($this->cidFile); + return $cid; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Start.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Start.php new file mode 100644 index 00000000..ef19d74d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Start.php @@ -0,0 +1,41 @@ +taskDockerStart($cidOrResult) + * ->run(); + * ?> + * ``` + */ +class Start extends Base +{ + /** + * @var string + */ + protected $command = "docker start"; + + /** + * @var null|string + */ + protected $cid; + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + */ + public function __construct($cidOrResult) + { + $this->cid = $cidOrResult instanceof Result ? $cidOrResult->getCid() : $cidOrResult; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments . ' ' . $this->cid; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Stop.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Stop.php new file mode 100644 index 00000000..4d0d436d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/Stop.php @@ -0,0 +1,41 @@ +taskDockerStop($cidOrResult) + * ->run(); + * ?> + * ``` + */ +class Stop extends Base +{ + /** + * @var string + */ + protected $command = "docker stop"; + + /** + * @var null|string + */ + protected $cid; + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + */ + public function __construct($cidOrResult) + { + $this->cid = $cidOrResult instanceof Result ? $cidOrResult->getCid() : $cidOrResult; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments . ' ' . $this->cid; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/loadTasks.php new file mode 100644 index 00000000..e58f5ef0 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Docker/loadTasks.php @@ -0,0 +1,85 @@ +task(Run::class, $image); + } + + /** + * @param string $image + * + * @return \Robo\Task\Docker\Pull + */ + protected function taskDockerPull($image) + { + return $this->task(Pull::class, $image); + } + + /** + * @param string $path + * + * @return \Robo\Task\Docker\Build + */ + protected function taskDockerBuild($path = '.') + { + return $this->task(Build::class, $path); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Stop + */ + protected function taskDockerStop($cidOrResult) + { + return $this->task(Stop::class, $cidOrResult); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Commit + */ + protected function taskDockerCommit($cidOrResult) + { + return $this->task(Commit::class, $cidOrResult); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Start + */ + protected function taskDockerStart($cidOrResult) + { + return $this->task(Start::class, $cidOrResult); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Remove + */ + protected function taskDockerRemove($cidOrResult) + { + return $this->task(Remove::class, $cidOrResult); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Exec + */ + protected function taskDockerExec($cidOrResult) + { + return $this->task(Exec::class, $cidOrResult); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Concat.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Concat.php new file mode 100644 index 00000000..12b1eca0 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Concat.php @@ -0,0 +1,101 @@ +taskConcat([ + * 'web/assets/screen.css', + * 'web/assets/print.css', + * 'web/assets/theme.css' + * ]) + * ->to('web/assets/style.css') + * ->run() + * ?> + * ``` + */ +class Concat extends BaseTask +{ + use ResourceExistenceChecker; + + /** + * @var array|Iterator + */ + protected $files; + + /** + * @var string + */ + protected $dst; + + /** + * Constructor. + * + * @param array|Iterator $files + */ + public function __construct($files) + { + $this->files = $files; + } + + /** + * set the destination file + * + * @param string $dst + * + * @return $this + */ + public function to($dst) + { + $this->dst = $dst; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (is_null($this->dst) || "" === $this->dst) { + return Result::error($this, 'You must specify a destination file with to() method.'); + } + + if (!$this->checkResources($this->files, 'file')) { + return Result::error($this, 'Source files are missing!'); + } + + if (file_exists($this->dst) && !is_writable($this->dst)) { + return Result::error($this, 'Destination already exists and cannot be overwritten.'); + } + + $dump = ''; + + foreach ($this->files as $path) { + foreach (glob($path) as $file) { + $dump .= file_get_contents($file) . "\n"; + } + } + + $this->printTaskInfo('Writing {destination}', ['destination' => $this->dst]); + + $dst = $this->dst . '.part'; + $write_result = file_put_contents($dst, $dump); + + if (false === $write_result) { + @unlink($dst); + return Result::error($this, 'File write failed.'); + } + // Cannot be cross-volume; should always succeed. + @rename($dst, $this->dst); + + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Replace.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Replace.php new file mode 100644 index 00000000..0107df13 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Replace.php @@ -0,0 +1,141 @@ +taskReplaceInFile('VERSION') + * ->from('0.2.0') + * ->to('0.3.0') + * ->run(); + * + * $this->taskReplaceInFile('README.md') + * ->from(date('Y')-1) + * ->to(date('Y')) + * ->run(); + * + * $this->taskReplaceInFile('config.yml') + * ->regex('~^service:~') + * ->to('services:') + * ->run(); + * + * $this->taskReplaceInFile('box/robo.txt') + * ->from(array('##dbname##', '##dbhost##')) + * ->to(array('robo', 'localhost')) + * ->run(); + * ?> + * ``` + */ +class Replace extends BaseTask +{ + /** + * @var string + */ + protected $filename; + + /** + * @var string|string[] + */ + protected $from; + + /** + * @var string|string[] + */ + protected $to; + + /** + * @var string + */ + protected $regex; + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * @param string $filename + * + * @return $this + */ + public function filename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * String(s) to be replaced. + * + * @param string|string[] $from + * + * @return $this + */ + public function from($from) + { + $this->from = $from; + return $this; + } + + /** + * Value(s) to be set as a replacement. + * + * @param string|string[] $to + * + * @return $this + */ + public function to($to) + { + $this->to = $to; + return $this; + } + + /** + * Regex to match string to be replaced. + * + * @param string $regex + * + * @return $this + */ + public function regex($regex) + { + $this->regex = $regex; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!file_exists($this->filename)) { + $this->printTaskError('File {filename} does not exist', ['filename' => $this->filename]); + return false; + } + + $text = file_get_contents($this->filename); + if ($this->regex) { + $text = preg_replace($this->regex, $this->to, $text, -1, $count); + } else { + $text = str_replace($this->from, $this->to, $text, $count); + } + if ($count > 0) { + $res = file_put_contents($this->filename, $text); + if ($res === false) { + return Result::error($this, "Error writing to file {filename}.", ['filename' => $this->filename]); + } + $this->printTaskSuccess("{filename} updated. {count} items replaced", ['filename' => $this->filename, 'count' => $count]); + } else { + $this->printTaskInfo("{filename} unchanged. {count} items replaced", ['filename' => $this->filename, 'count' => $count]); + } + return Result::success($this, '', ['replaced' => $count]); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/TmpFile.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/TmpFile.php new file mode 100644 index 00000000..4a18691d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/TmpFile.php @@ -0,0 +1,72 @@ +collectionBuilder(); + * $tmpFilePath = $collection->taskTmpFile() + * ->line('-----') + * ->line(date('Y-m-d').' '.$title) + * ->line('----') + * ->getPath(); + * $collection->run(); + * ?> + * ``` + */ +class TmpFile extends Write implements CompletionInterface +{ + /** + * @param string $filename + * @param string $extension + * @param string $baseDir + * @param bool $includeRandomPart + */ + public function __construct($filename = 'tmp', $extension = '', $baseDir = '', $includeRandomPart = true) + { + if (empty($baseDir)) { + $baseDir = sys_get_temp_dir(); + } + if ($includeRandomPart) { + $random = static::randomString(); + $filename = "{$filename}_{$random}"; + } + $filename .= $extension; + parent::__construct("{$baseDir}/{$filename}"); + } + + /** + * Generate a suitably random string to use as the suffix for our + * temporary file. + * + * @param int $length + * + * @return string + */ + private static function randomString($length = 12) + { + return substr(str_shuffle('23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'), 0, $length); + } + + /** + * Delete this file when our collection completes. + * If this temporary file is not part of a collection, + * then it will be deleted when the program terminates, + * presuming that it was created by taskTmpFile() or _tmpFile(). + */ + public function complete() + { + unlink($this->getPath()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Write.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Write.php new file mode 100644 index 00000000..dc2199f9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/Write.php @@ -0,0 +1,335 @@ +taskWriteToFile('blogpost.md') + * ->line('-----') + * ->line(date('Y-m-d').' '.$title) + * ->line('----') + * ->run(); + * ?> + * ``` + */ +class Write extends BaseTask +{ + /** + * @var array + */ + protected $stack = []; + + /** + * @var string + */ + protected $filename; + + /** + * @var bool + */ + protected $append = false; + + /** + * @var null|string + */ + protected $originalContents = null; + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * @param string $filename + * + * @return $this + */ + public function filename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * @param bool $append + * + * @return $this + */ + public function append($append = true) + { + $this->append = $append; + return $this; + } + + /** + * add a line. + * + * @param string $line + * + * @return $this The current instance + */ + public function line($line) + { + $this->text($line . "\n"); + return $this; + } + + /** + * add more lines. + * + * @param array $lines + * + * @return $this The current instance + */ + public function lines(array $lines) + { + $this->text(implode("\n", $lines) . "\n"); + return $this; + } + + /** + * add a text. + * + * @param string $text + * + * @return $this The current instance + */ + public function text($text) + { + $this->stack[] = array_merge([__FUNCTION__ . 'Collect'], func_get_args()); + return $this; + } + + /** + * add a text from a file. + * + * Note that the file is read in the run() method of this task. + * To load text from the current state of a file (e.g. one that may + * be deleted or altered by other tasks prior the execution of this one), + * use: + * $task->text(file_get_contents($filename)); + * + * @param string $filename + * + * @return $this The current instance + */ + public function textFromFile($filename) + { + $this->stack[] = array_merge([__FUNCTION__ . 'Collect'], func_get_args()); + return $this; + } + + /** + * substitute a placeholder with value, placeholder must be enclosed by `{}`. + * + * @param string $name + * @param string $val + * + * @return $this The current instance + */ + public function place($name, $val) + { + $this->replace('{'.$name.'}', $val); + + return $this; + } + + /** + * replace any string with value. + * + * @param string $string + * @param string $replacement + * + * @return $this The current instance + */ + public function replace($string, $replacement) + { + $this->stack[] = array_merge([__FUNCTION__ . 'Collect'], func_get_args()); + return $this; + } + + /** + * replace any string with value using regular expression. + * + * @param string $pattern + * @param string $replacement + * + * @return $this The current instance + */ + public function regexReplace($pattern, $replacement) + { + $this->stack[] = array_merge([__FUNCTION__ . 'Collect'], func_get_args()); + return $this; + } + + /** + * Append the provided text to the end of the buffer if the provided + * regex pattern matches any text already in the buffer. + * + * @param string $pattern + * @param string $text + * + * @return $this + */ + public function appendIfMatches($pattern, $text) + { + $this->stack[] = array_merge(['appendIfMatchesCollect'], [$pattern, $text, true]); + return $this; + } + + /** + * Append the provided text to the end of the buffer unless the provided + * regex pattern matches any text already in the buffer. + * + * @param string $pattern + * @param string $text + * + * @return $this + */ + public function appendUnlessMatches($pattern, $text) + { + $this->stack[] = array_merge(['appendIfMatchesCollect'], [$pattern, $text, false]); + return $this; + } + + /** + * @param $contents string + * @param $filename string + * + * @return string + */ + protected function textFromFileCollect($contents, $filename) + { + if (file_exists($filename)) { + $contents .= file_get_contents($filename); + } + return $contents; + } + + /** + * @param string|string[] $contents + * @param string|string[] $string + * @param string|string[] $replacement + * + * @return string|string[] + */ + protected function replaceCollect($contents, $string, $replacement) + { + return str_replace($string, $replacement, $contents); + } + + /** + * @param string|string[] $contents + * @param string|string[] $pattern + * @param string|string[] $replacement + * + * @return string|string[] + */ + protected function regexReplaceCollect($contents, $pattern, $replacement) + { + return preg_replace($pattern, $replacement, $contents); + } + + /** + * @param string $contents + * @param string $text + * + * @return string + */ + protected function textCollect($contents, $text) + { + return $contents . $text; + } + + /** + * @param string $contents + * @param string $pattern + * @param string $text + * @param bool $shouldMatch + * + * @return string + */ + protected function appendIfMatchesCollect($contents, $pattern, $text, $shouldMatch) + { + if (preg_match($pattern, $contents) == $shouldMatch) { + $contents .= $text; + } + return $contents; + } + + /** + * @return string + */ + public function originalContents() + { + if (!isset($this->originalContents)) { + $this->originalContents = ''; + if (file_exists($this->filename)) { + $this->originalContents = file_get_contents($this->filename); + } + } + return $this->originalContents; + } + + /** + * @return bool + */ + public function wouldChange() + { + return $this->originalContents() != $this->getContentsToWrite(); + } + + /** + * @return string + */ + protected function getContentsToWrite() + { + $contents = ""; + if ($this->append) { + $contents = $this->originalContents(); + } + foreach ($this->stack as $action) { + $command = array_shift($action); + if (method_exists($this, $command)) { + array_unshift($action, $contents); + $contents = call_user_func_array([$this, $command], $action); + } + } + return $contents; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo("Writing to {filename}.", ['filename' => $this->filename]); + $contents = $this->getContentsToWrite(); + if (!file_exists(dirname($this->filename))) { + mkdir(dirname($this->filename), 0777, true); + } + $res = file_put_contents($this->filename, $contents); + if ($res === false) { + return Result::error($this, "File {$this->filename} couldn't be created"); + } + + return Result::success($this); + } + + /** + * @return string + */ + public function getPath() + { + return $this->filename; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/loadTasks.php new file mode 100644 index 00000000..c5f39c95 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/File/loadTasks.php @@ -0,0 +1,48 @@ +task(Concat::class, $files); + } + + /** + * @param string $file + * + * @return \Robo\Task\File\Replace + */ + protected function taskReplaceInFile($file) + { + return $this->task(Replace::class, $file); + } + + /** + * @param string $file + * + * @return \Robo\Task\File\Write + */ + protected function taskWriteToFile($file) + { + return $this->task(Write::class, $file); + } + + /** + * @param string $filename + * @param string $extension + * @param string $baseDir + * @param bool $includeRandomPart + * + * @return \Robo\Task\File\TmpFile + */ + protected function taskTmpFile($filename = 'tmp', $extension = '', $baseDir = '', $includeRandomPart = true) + { + return $this->task(TmpFile::class, $filename, $extension, $baseDir, $includeRandomPart); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/BaseDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/BaseDir.php new file mode 100644 index 00000000..434334d7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/BaseDir.php @@ -0,0 +1,30 @@ +dirs = $dirs + : $this->dirs[] = $dirs; + + $this->fs = new sfFilesystem(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/CleanDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/CleanDir.php new file mode 100644 index 00000000..762f8550 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/CleanDir.php @@ -0,0 +1,63 @@ +taskCleanDir(['tmp','logs'])->run(); + * // as shortcut + * $this->_cleanDir('app/cache'); + * ?> + * ``` + */ +class CleanDir extends BaseDir +{ + use ResourceExistenceChecker; + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->checkResources($this->dirs, 'dir')) { + return Result::error($this, 'Source directories are missing!'); + } + foreach ($this->dirs as $dir) { + $this->emptyDir($dir); + $this->printTaskInfo("Cleaned {dir}", ['dir' => $dir]); + } + return Result::success($this); + } + + /** + * @param string $path + */ + protected function emptyDir($path) + { + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($path), + \RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach ($iterator as $path) { + if ($path->isDir()) { + $dir = (string)$path; + if (basename($dir) === '.' || basename($dir) === '..') { + continue; + } + $this->fs->remove($dir); + } else { + $file = (string)$path; + if (basename($file) === '.gitignore' || basename($file) === '.gitkeep') { + continue; + } + $this->fs->remove($file); + } + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/CopyDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/CopyDir.php new file mode 100644 index 00000000..08482222 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/CopyDir.php @@ -0,0 +1,162 @@ +taskCopyDir(['dist/config' => 'config'])->run(); + * // as shortcut + * $this->_copyDir('dist/config', 'config'); + * ?> + * ``` + */ +class CopyDir extends BaseDir +{ + use ResourceExistenceChecker; + + /** + * Explicitly declare our consturctor, so that + * our copyDir() method does not look like a php4 constructor. + */ + public function __construct($dirs) + { + parent::__construct($dirs); + } + + /** + * @var int + */ + protected $chmod = 0755; + + /** + * Files to exclude on copying. + * + * @var string[] + */ + protected $exclude = []; + + /** + * Overwrite destination files newer than source files. + */ + protected $overwrite = true; + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->checkResources($this->dirs, 'dir')) { + return Result::error($this, 'Source directories are missing!'); + } + foreach ($this->dirs as $src => $dst) { + $this->copyDir($src, $dst); + $this->printTaskInfo('Copied from {source} to {destination}', ['source' => $src, 'destination' => $dst]); + } + return Result::success($this); + } + + /** + * Sets the default folder permissions for the destination if it doesn't exist + * + * @link http://en.wikipedia.org/wiki/Chmod + * @link http://php.net/manual/en/function.mkdir.php + * @link http://php.net/manual/en/function.chmod.php + * + * @param int $value + * + * @return $this + */ + public function dirPermissions($value) + { + $this->chmod = (int)$value; + return $this; + } + + /** + * List files to exclude. + * + * @param string[] $exclude + * + * @return $this + */ + public function exclude($exclude = []) + { + $this->exclude = $this->simplifyForCompare($exclude); + return $this; + } + + /** + * Destination files newer than source files are overwritten. + * + * @param bool $overwrite + * + * @return $this + */ + public function overwrite($overwrite) + { + $this->overwrite = $overwrite; + return $this; + } + + /** + * Copies a directory to another location. + * + * @param string $src Source directory + * @param string $dst Destination directory + * @param string $parent Parent directory + * + * @throws \Robo\Exception\TaskException + */ + protected function copyDir($src, $dst, $parent = '') + { + $dir = @opendir($src); + if (false === $dir) { + throw new TaskException($this, "Cannot open source directory '" . $src . "'"); + } + if (!is_dir($dst)) { + mkdir($dst, $this->chmod, true); + } + while (false !== ($file = readdir($dir))) { + // Support basename and full path exclusion. + if ($this->excluded($file, $src, $parent)) { + continue; + } + $srcFile = $src . '/' . $file; + $destFile = $dst . '/' . $file; + if (is_dir($srcFile)) { + $this->copyDir($srcFile, $destFile, $parent . $file . DIRECTORY_SEPARATOR); + } else { + $this->fs->copy($srcFile, $destFile, $this->overwrite); + } + } + closedir($dir); + } + + /** + * Check to see if the current item is excluded. + */ + protected function excluded($file, $src, $parent) + { + return + ($file == '.') || + ($file == '..') || + in_array($file, $this->exclude) || + in_array($this->simplifyForCompare($parent . $file), $this->exclude) || + in_array($this->simplifyForCompare($src . DIRECTORY_SEPARATOR . $file), $this->exclude); + } + + /** + * Avoid problems comparing paths on Windows that may have a + * combination of DIRECTORY_SEPARATOR and /. + */ + protected function simplifyForCompare($item) + { + return str_replace(DIRECTORY_SEPARATOR, '/', $item); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/DeleteDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/DeleteDir.php new file mode 100644 index 00000000..25cf007b --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/DeleteDir.php @@ -0,0 +1,36 @@ +taskDeleteDir('tmp')->run(); + * // as shortcut + * $this->_deleteDir(['tmp', 'log']); + * ?> + * ``` + */ +class DeleteDir extends BaseDir +{ + use ResourceExistenceChecker; + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->checkResources($this->dirs, 'dir')) { + return Result::error($this, 'Source directories are missing!'); + } + foreach ($this->dirs as $dir) { + $this->fs->remove($dir); + $this->printTaskInfo("Deleted {dir}...", ['dir' => $dir]); + } + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/FilesystemStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/FilesystemStack.php new file mode 100644 index 00000000..8663e245 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/FilesystemStack.php @@ -0,0 +1,154 @@ +taskFilesystemStack() + * ->mkdir('logs') + * ->touch('logs/.gitignore') + * ->chgrp('www', 'www-data') + * ->symlink('/var/log/nginx/error.log', 'logs/error.log') + * ->run(); + * + * // one line + * $this->_touch('.gitignore'); + * $this->_mkdir('logs'); + * + * ?> + * ``` + * + * @method $this mkdir(string|array|\Traversable $dir, int $mode = 0777) + * @method $this touch(string|array|\Traversable $file, int $time = null, int $atime = null) + * @method $this copy(string $from, string $to, bool $force = false) + * @method $this chmod(string|array|\Traversable $file, int $permissions, int $umask = 0000, bool $recursive = false) + * @method $this chgrp(string|array|\Traversable $file, string $group, bool $recursive = false) + * @method $this chown(string|array|\Traversable $file, string $user, bool $recursive = false) + * @method $this remove(string|array|\Traversable $file) + * @method $this rename(string $from, string $to, bool $force = false) + * @method $this symlink(string $from, string $to, bool $copyOnWindows = false) + * @method $this mirror(string $from, string $to, \Traversable $iterator = null, array $options = []) + */ +class FilesystemStack extends StackBasedTask implements BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var \Symfony\Component\Filesystem\Filesystem + */ + protected $fs; + + public function __construct() + { + $this->fs = new sfFilesystem(); + } + + /** + * @return \Symfony\Component\Filesystem\Filesystem + */ + protected function getDelegate() + { + return $this->fs; + } + + /** + * @param string $from + * @param string $to + * @param bool $force + */ + protected function _copy($from, $to, $force = false) + { + $this->fs->copy($from, $to, $force); + } + + /** + * @param string|string[]|\Traversable $file + * @param int $permissions + * @param int $umask + * @param bool $recursive + */ + protected function _chmod($file, $permissions, $umask = 0000, $recursive = false) + { + $this->fs->chmod($file, $permissions, $umask, $recursive); + } + + /** + * @param string|string[]|\Traversable $file + * @param string $group + * @param bool $recursive + */ + protected function _chgrp($file, $group, $recursive = null) + { + $this->fs->chgrp($file, $group, $recursive); + } + + /** + * @param string|string[]|\Traversable $file + * @param string $user + * @param bool $recursive + */ + protected function _chown($file, $user, $recursive = null) + { + $this->fs->chown($file, $user, $recursive); + } + + /** + * @param string $origin + * @param string $target + * @param bool $overwrite + * + * @return null|true|\Robo\Result + */ + protected function _rename($origin, $target, $overwrite = false) + { + // we check that target does not exist + if ((!$overwrite && is_readable($target)) || (file_exists($target) && !is_writable($target))) { + throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); + } + + // Due to a bug (limitation) in PHP, cross-volume renames do not work. + // See: https://bugs.php.net/bug.php?id=54097 + if (true !== @rename($origin, $target)) { + return $this->crossVolumeRename($origin, $target); + } + return true; + } + + /** + * @param string $origin + * @param string $target + * + * @return null|\Robo\Result + */ + protected function crossVolumeRename($origin, $target) + { + // First step is to try to get rid of the target. If there + // is a single, deletable file, then we will just unlink it. + if (is_file($target)) { + unlink($target); + } + // If the target still exists, we will try to delete it. + // TODO: Note that if this fails partway through, then we cannot + // adequately rollback. Perhaps we need to preflight the operation + // and determine if everything inside of $target is writable. + if (file_exists($target)) { + $this->fs->remove($target); + } + + /** @var \Robo\Result $result */ + $result = $this->collectionBuilder()->taskCopyDir([$origin => $target])->run(); + if (!$result->wasSuccessful()) { + return $result; + } + $this->fs->remove($origin); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/FlattenDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/FlattenDir.php new file mode 100644 index 00000000..6e885112 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/FlattenDir.php @@ -0,0 +1,294 @@ +taskFlattenDir(['assets/*.min.js' => 'dist'])->run(); + * // or use shortcut + * $this->_flattenDir('assets/*.min.js', 'dist'); + * ?> + * ``` + * + * You can also define the target directory with an additional method, instead of + * key/value pairs. More similar to the gulp-flatten syntax: + * + * ``` php + * taskFlattenDir(['assets/*.min.js']) + * ->to('dist') + * ->run(); + * ?> + * ``` + * + * You can also append parts of the parent directories to the target path. If you give + * the value `1` to the `includeParents()` method, then the top parent will be appended + * to the target directory resulting in a path such as `dist/assets/asset-library1.min.js`. + * + * If you give a negative number, such as `-1` (the same as specifying `array(0, 1)` then + * the bottom parent will be appended, resulting in a path such as + * `dist/asset-library1/asset-library1.min.js`. + * + * The top parent directory will always be starting from the relative path to the current + * directory. You can override that with the `parentDir()` method. If in the above example + * you would specify `assets`, then the top parent directory would be `asset-library1`. + * + * ``` php + * taskFlattenDir(['assets/*.min.js' => 'dist']) + * ->parentDir('assets') + * ->includeParents(1) + * ->run(); + * ?> + * ``` + */ +class FlattenDir extends BaseDir +{ + /** + * @var int + */ + protected $chmod = 0755; + + /** + * @var int[] + */ + protected $parents = array(0, 0); + + /** + * @var string + */ + protected $parentDir = ''; + + /** + * @var string + */ + protected $to; + + /** + * {@inheritdoc} + */ + public function __construct($dirs) + { + parent::__construct($dirs); + $this->parentDir = getcwd(); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // find the files + $files = $this->findFiles($this->dirs); + + // copy the files + $this->copyFiles($files); + + $fileNoun = count($files) == 1 ? ' file' : ' files'; + $this->printTaskSuccess("Copied {count} $fileNoun to {destination}", ['count' => count($files), 'destination' => $this->to]); + + return Result::success($this); + } + + /** + * Sets the default folder permissions for the destination if it does not exist. + * + * @link http://en.wikipedia.org/wiki/Chmod + * @link http://php.net/manual/en/function.mkdir.php + * @link http://php.net/manual/en/function.chmod.php + * + * @param int $permission + * + * @return $this + */ + public function dirPermissions($permission) + { + $this->chmod = (int) $permission; + + return $this; + } + + /** + * Sets the value from which direction and how much parent dirs should be included. + * Accepts a positive or negative integer or an array with two integer values. + * + * @param int|int[] $parents + * + * @return $this + * + * @throws TaskException + */ + public function includeParents($parents) + { + if (is_int($parents)) { + // if an integer is given check whether it is for top or bottom parent + if ($parents >= 0) { + $this->parents[0] = $parents; + return $this; + } + $this->parents[1] = 0 - $parents; + return $this; + } + + if (is_array($parents)) { + // check if the array has two values no more, no less + if (count($parents) == 2) { + $this->parents = $parents; + return $this; + } + } + + throw new TaskException($this, 'includeParents expects an integer or an array with two values'); + } + + /** + * Sets the parent directory from which the relative parent directories will be calculated. + * + * @param string $dir + * + * @return $this + */ + public function parentDir($dir) + { + if (!$this->fs->isAbsolutePath($dir)) { + // attach the relative path to current working directory + $dir = getcwd().'/'.$dir; + } + $this->parentDir = $dir; + + return $this; + } + + /** + * Sets the target directory where the files will be copied to. + * + * @param string $target + * + * @return $this + */ + public function to($target) + { + $this->to = rtrim($target, '/'); + + return $this; + } + + /** + * @param array $dirs + * + * @return array|\Robo\Result + * + * @throws \Robo\Exception\TaskException + */ + protected function findFiles($dirs) + { + $files = array(); + + // find the files + foreach ($dirs as $k => $v) { + // reset finder + $finder = new Finder(); + + $dir = $k; + $to = $v; + // check if target was given with the to() method instead of key/value pairs + if (is_int($k)) { + $dir = $v; + if (isset($this->to)) { + $to = $this->to; + } else { + throw new TaskException($this, 'target directory is not defined'); + } + } + + try { + $finder->files()->in($dir); + } catch (\InvalidArgumentException $e) { + // if finder cannot handle it, try with in()->name() + if (strpos($dir, '/') === false) { + $dir = './'.$dir; + } + $parts = explode('/', $dir); + $new_dir = implode('/', array_slice($parts, 0, -1)); + try { + $finder->files()->in($new_dir)->name(array_pop($parts)); + } catch (\InvalidArgumentException $e) { + return Result::fromException($this, $e); + } + } + + foreach ($finder as $file) { + // store the absolute path as key and target as value in the files array + $files[$file->getRealpath()] = $this->getTarget($file->getRealPath(), $to); + } + $fileNoun = count($files) == 1 ? ' file' : ' files'; + $this->printTaskInfo("Found {count} $fileNoun in {dir}", ['count' => count($files), 'dir' => $dir]); + } + + return $files; + } + + /** + * @param string $file + * @param string $to + * + * @return string + */ + protected function getTarget($file, $to) + { + $target = $to.'/'.basename($file); + if ($this->parents !== array(0, 0)) { + // if the parent is set, create additional directories inside target + // get relative path to parentDir + $rel_path = $this->fs->makePathRelative(dirname($file), $this->parentDir); + // get top parents and bottom parents + $parts = explode('/', rtrim($rel_path, '/')); + $prefix_dir = ''; + $prefix_dir .= ($this->parents[0] > 0 ? implode('/', array_slice($parts, 0, $this->parents[0])).'/' : ''); + $prefix_dir .= ($this->parents[1] > 0 ? implode('/', array_slice($parts, (0 - $this->parents[1]), $this->parents[1])) : ''); + $prefix_dir = rtrim($prefix_dir, '/'); + $target = $to.'/'.$prefix_dir.'/'.basename($file); + } + + return $target; + } + + /** + * @param array $files + */ + protected function copyFiles($files) + { + // copy the files + foreach ($files as $from => $to) { + // check if target dir exists + if (!is_dir(dirname($to))) { + $this->fs->mkdir(dirname($to), $this->chmod); + } + $this->fs->copy($from, $to); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/MirrorDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/MirrorDir.php new file mode 100644 index 00000000..4eda9097 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/MirrorDir.php @@ -0,0 +1,40 @@ +taskMirrorDir(['dist/config/' => 'config/'])->run(); + * // or use shortcut + * $this->_mirrorDir('dist/config/', 'config/'); + * + * ?> + * ``` + */ +class MirrorDir extends BaseDir +{ + /** + * {@inheritdoc} + */ + public function run() + { + foreach ($this->dirs as $src => $dst) { + $this->fs->mirror( + $src, + $dst, + null, + [ + 'override' => true, + 'copy_on_windows' => true, + 'delete' => true + ] + ); + $this->printTaskInfo("Mirrored from {source} to {destination}", ['source' => $src, 'destination' => $dst]); + } + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/TmpDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/TmpDir.php new file mode 100644 index 00000000..104318de --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/TmpDir.php @@ -0,0 +1,173 @@ +run(). + * $collection = $this->collectionBuilder(); + * $tmpPath = $collection->tmpDir()->getPath(); + * $collection->taskFilesystemStack() + * ->mkdir("$tmpPath/log") + * ->touch("$tmpPath/log/error.txt"); + * $collection->run(); + * // as shortcut (deleted when program exits) + * $tmpPath = $this->_tmpDir(); + * ?> + * ``` + */ +class TmpDir extends BaseDir implements CompletionInterface +{ + /** + * @var string + */ + protected $base; + + /** + * @var string + */ + protected $prefix; + + /** + * @var bool + */ + protected $cwd; + + /** + * @var string + */ + protected $savedWorkingDirectory; + + /** + * @param string $prefix + * @param string $base + * @param bool $includeRandomPart + */ + public function __construct($prefix = 'tmp', $base = '', $includeRandomPart = true) + { + if (empty($base)) { + $base = sys_get_temp_dir(); + } + $path = "{$base}/{$prefix}"; + if ($includeRandomPart) { + $path = static::randomLocation($path); + } + parent::__construct(["$path"]); + } + + /** + * Add a random part to a path, ensuring that the directory does + * not (currently) exist. + * + * @param string $path The base/prefix path to add a random component to + * @param int $length Number of digits in the random part + * + * @return string + */ + protected static function randomLocation($path, $length = 12) + { + $random = static::randomString($length); + while (is_dir("{$path}_{$random}")) { + $random = static::randomString($length); + } + return "{$path}_{$random}"; + } + + /** + * Generate a suitably random string to use as the suffix for our + * temporary directory. + * + * @param int $length + * + * @return string + */ + protected static function randomString($length = 12) + { + return substr(str_shuffle('23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'), 0, max($length, 3)); + } + + /** + * Flag that we should cwd to the temporary directory when it is + * created, and restore the old working directory when it is deleted. + * + * @param bool $shouldChangeWorkingDirectory + * + * @return $this + */ + public function cwd($shouldChangeWorkingDirectory = true) + { + $this->cwd = $shouldChangeWorkingDirectory; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Save the current working directory + $this->savedWorkingDirectory = getcwd(); + foreach ($this->dirs as $dir) { + $this->fs->mkdir($dir); + $this->printTaskInfo("Created {dir}...", ['dir' => $dir]); + + // Change the current working directory, if requested + if ($this->cwd) { + chdir($dir); + } + } + + return Result::success($this, '', ['path' => $this->getPath()]); + } + + protected function restoreWorkingDirectory() + { + // Restore the current working directory, if we redirected it. + if ($this->cwd) { + chdir($this->savedWorkingDirectory); + } + } + + protected function deleteTmpDir() + { + foreach ($this->dirs as $dir) { + $this->fs->remove($dir); + } + } + + /** + * Delete this directory when our collection completes. + * If this temporary directory is not part of a collection, + * then it will be deleted when the program terminates, + * presuming that it was created by taskTmpDir() or _tmpDir(). + */ + public function complete() + { + $this->restoreWorkingDirectory(); + $this->deleteTmpDir(); + } + + /** + * Get a reference to the path to the temporary directory, so that + * it may be used to create other tasks. Note that the directory + * is not actually created until the task runs. + * + * @return string + */ + public function getPath() + { + return $this->dirs[0]; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/WorkDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/WorkDir.php new file mode 100644 index 00000000..4b75c6ed --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/WorkDir.php @@ -0,0 +1,126 @@ +collectionBuilder(); + * $workingPath = $collection->workDir("build")->getPath(); + * $collection->taskFilesystemStack() + * ->mkdir("$workingPath/log") + * ->touch("$workingPath/log/error.txt"); + * $collection->run(); + * ?> + * ``` + */ +class WorkDir extends TmpDir implements RollbackInterface, BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var string + */ + protected $finalDestination; + + /** + * @param string $finalDestination + */ + public function __construct($finalDestination) + { + $this->finalDestination = $finalDestination; + + // Create a temporary directory to work in. We will place our + // temporary directory in the same location as the final destination + // directory, so that the work directory can be moved into place + // without having to be copied, e.g. in a cross-volume rename scenario. + parent::__construct(basename($finalDestination), dirname($finalDestination)); + } + + /** + * Create our working directory. + * + * @return \Robo\Result + */ + public function run() + { + // Destination cannot be empty + if (empty($this->finalDestination)) { + return Result::error($this, "Destination directory not specified."); + } + + // Before we do anything else, ensure that any directory in the + // final destination is writable, so that we can at a minimum + // move it out of the way before placing our results there. + if (is_dir($this->finalDestination)) { + if (!is_writable($this->finalDestination)) { + return Result::error($this, "Destination directory {dir} exists and cannot be overwritten.", ['dir' => $this->finalDestination]); + } + } + + return parent::run(); + } + + /** + * Move our working directory into its final destination once the + * collection it belongs to completes. + */ + public function complete() + { + $this->restoreWorkingDirectory(); + + // Delete the final destination, if it exists. + // Move it out of the way first, in case it cannot + // be completely deleted. + if (file_exists($this->finalDestination)) { + $temporaryLocation = static::randomLocation($this->finalDestination . '_TO_DELETE_'); + // This should always work, because we already created a temporary + // folder in the parent directory of the final destination, and we + // have already checked to confirm that the final destination is + // writable. + rename($this->finalDestination, $temporaryLocation); + // This may silently fail, leaving artifacts behind, if there + // are permissions problems with some items somewhere inside + // the folder being deleted. + $this->fs->remove($temporaryLocation); + } + + // Move our working directory over the final destination. + // This should never be a cross-volume rename, so this should + // always succeed. + $workDir = reset($this->dirs); + if (file_exists($workDir)) { + rename($workDir, $this->finalDestination); + } + } + + /** + * Delete our working directory + */ + public function rollback() + { + $this->restoreWorkingDirectory(); + $this->deleteTmpDir(); + } + + /** + * Get a reference to the path to the temporary directory, so that + * it may be used to create other tasks. Note that the directory + * is not actually created until the task runs. + * + * @return string + */ + public function getPath() + { + return $this->dirs[0]; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/loadShortcuts.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/loadShortcuts.php new file mode 100644 index 00000000..fe72ce5a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/loadShortcuts.php @@ -0,0 +1,159 @@ +taskCopyDir([$src => $dst])->run(); + } + + /** + * @param string $src + * @param string $dst + * + * @return \Robo\Result + */ + protected function _mirrorDir($src, $dst) + { + return $this->taskMirrorDir([$src => $dst])->run(); + } + + /** + * @param string|string[] $dir + * + * @return \Robo\Result + */ + protected function _deleteDir($dir) + { + return $this->taskDeleteDir($dir)->run(); + } + + /** + * @param string|string[] $dir + * + * @return \Robo\Result + */ + protected function _cleanDir($dir) + { + return $this->taskCleanDir($dir)->run(); + } + + /** + * @param string $from + * @param string $to + * @param bool $overwrite + * + * @return \Robo\Result + */ + protected function _rename($from, $to, $overwrite = false) + { + return $this->taskFilesystemStack()->rename($from, $to, $overwrite)->run(); + } + + /** + * @param string|string[] $dir + * + * @return \Robo\Result + */ + protected function _mkdir($dir) + { + return $this->taskFilesystemStack()->mkdir($dir)->run(); + } + + /** + * @param string $prefix + * @param string $base + * @param bool $includeRandomPart + * + * @return string + */ + protected function _tmpDir($prefix = 'tmp', $base = '', $includeRandomPart = true) + { + $result = $this->taskTmpDir($prefix, $base, $includeRandomPart)->run(); + return isset($result['path']) ? $result['path'] : ''; + } + + /** + * @param string $file + * + * @return \Robo\Result + */ + protected function _touch($file) + { + return $this->taskFilesystemStack()->touch($file)->run(); + } + + /** + * @param string|string[] $file + * + * @return \Robo\Result + */ + protected function _remove($file) + { + return $this->taskFilesystemStack()->remove($file)->run(); + } + + /** + * @param string|string[] $file + * @param string $group + * + * @return \Robo\Result + */ + protected function _chgrp($file, $group) + { + return $this->taskFilesystemStack()->chgrp($file, $group)->run(); + } + + /** + * @param string|string[] $file + * @param int $permissions + * @param int $umask + * @param bool $recursive + * + * @return \Robo\Result + */ + protected function _chmod($file, $permissions, $umask = 0000, $recursive = false) + { + return $this->taskFilesystemStack()->chmod($file, $permissions, $umask, $recursive)->run(); + } + + /** + * @param string $from + * @param string $to + * + * @return \Robo\Result + */ + protected function _symlink($from, $to) + { + return $this->taskFilesystemStack()->symlink($from, $to)->run(); + } + + /** + * @param string $from + * @param string $to + * + * @return \Robo\Result + */ + protected function _copy($from, $to) + { + return $this->taskFilesystemStack()->copy($from, $to)->run(); + } + + /** + * @param string $from + * @param string $to + * + * @return \Robo\Result + */ + protected function _flattenDir($from, $to) + { + return $this->taskFlattenDir([$from => $to])->run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/loadTasks.php new file mode 100644 index 00000000..8fecaaff --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Filesystem/loadTasks.php @@ -0,0 +1,85 @@ +task(CleanDir::class, $dirs); + } + + /** + * @param string|string[] $dirs + * + * @return \Robo\Task\Filesystem\DeleteDir + */ + protected function taskDeleteDir($dirs) + { + return $this->task(DeleteDir::class, $dirs); + } + + /** + * @param string $prefix + * @param string $base + * @param bool $includeRandomPart + * + * @return \Robo\Task\Filesystem\WorkDir + */ + protected function taskTmpDir($prefix = 'tmp', $base = '', $includeRandomPart = true) + { + return $this->task(TmpDir::class, $prefix, $base, $includeRandomPart); + } + + /** + * @param string $finalDestination + * + * @return \Robo\Task\Filesystem\TmpDir + */ + protected function taskWorkDir($finalDestination) + { + return $this->task(WorkDir::class, $finalDestination); + } + + /** + * @param string|string[] $dirs + * + * @return \Robo\Task\Filesystem\CopyDir + */ + protected function taskCopyDir($dirs) + { + return $this->task(CopyDir::class, $dirs); + } + + /** + * @param string|string[] $dirs + * + * @return \Robo\Task\Filesystem\MirrorDir + */ + protected function taskMirrorDir($dirs) + { + return $this->task(MirrorDir::class, $dirs); + } + + /** + * @param string|string[] $dirs + * + * @return \Robo\Task\Filesystem\FlattenDir + */ + protected function taskFlattenDir($dirs) + { + return $this->task(FlattenDir::class, $dirs); + } + + /** + * @return \Robo\Task\Filesystem\FilesystemStack + */ + protected function taskFilesystemStack() + { + return $this->task(FilesystemStack::class); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/Base.php new file mode 100644 index 00000000..42728673 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/Base.php @@ -0,0 +1,97 @@ +option('silent'); + return $this; + } + + /** + * adds `--no-color` option to gulp + * + * @return $this + */ + public function noColor() + { + $this->option('no-color'); + return $this; + } + + /** + * adds `--color` option to gulp + * + * @return $this + */ + public function color() + { + $this->option('color'); + return $this; + } + + /** + * adds `--tasks-simple` option to gulp + * + * @return $this + */ + public function simple() + { + $this->option('tasks-simple'); + return $this; + } + + /** + * @param string $task + * @param null|string $pathToGulp + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($task, $pathToGulp = null) + { + $this->task = $task; + $this->command = $pathToGulp; + if (!$this->command) { + $this->command = $this->findExecutable('gulp'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Gulp executable not found."); + } + } + + /** + * @return string + */ + public function getCommand() + { + return "{$this->command} " . ProcessUtils::escapeArgument($this->task) . "{$this->arguments}"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/Run.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/Run.php new file mode 100644 index 00000000..8f2077b5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/Run.php @@ -0,0 +1,35 @@ +taskGulpRun()->run(); + * + * // run task 'clean' with --silent option + * $this->taskGulpRun('clean') + * ->silent() + * ->run(); + * ?> + * ``` + */ +class Run extends Base implements CommandInterface +{ + /** + * {@inheritdoc} + */ + public function run() + { + if (strlen($this->arguments)) { + $this->printTaskInfo('Running Gulp task: {gulp_task} with arguments: {arguments}', ['gulp_task' => $this->task, 'arguments' => $this->arguments]); + } else { + $this->printTaskInfo('Running Gulp task: {gulp_task} without arguments', ['gulp_task' => $this->task]); + } + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/loadTasks.php new file mode 100644 index 00000000..6fdc6ca7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Gulp/loadTasks.php @@ -0,0 +1,16 @@ +task(Run::class, $task, $pathToGulp); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Base.php new file mode 100644 index 00000000..35ff9c48 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Base.php @@ -0,0 +1,60 @@ +option('production'); + return $this; + } + + /** + * @param null|string $pathToNpm + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToNpm = null) + { + $this->command = $pathToNpm; + if (!$this->command) { + $this->command = $this->findExecutable('npm'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Npm executable not found."); + } + } + + /** + * @return string + */ + public function getCommand() + { + return "{$this->command} {$this->action}{$this->arguments}"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Install.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Install.php new file mode 100644 index 00000000..65cbe618 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Install.php @@ -0,0 +1,36 @@ +taskNpmInstall()->run(); + * + * // prefer dist with custom path + * $this->taskNpmInstall('path/to/my/npm') + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class Install extends Base implements CommandInterface +{ + /** + * @var string + */ + protected $action = 'install'; + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Install Npm packages: {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Update.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Update.php new file mode 100644 index 00000000..75421b30 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/Update.php @@ -0,0 +1,34 @@ +taskNpmUpdate()->run(); + * + * // prefer dist with custom path + * $this->taskNpmUpdate('path/to/my/npm') + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class Update extends Base +{ + /** + * @var string + */ + protected $action = 'update'; + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Update Npm packages: {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/loadTasks.php new file mode 100644 index 00000000..4d9a26eb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Npm/loadTasks.php @@ -0,0 +1,25 @@ +task(Install::class, $pathToNpm); + } + + /** + * @param null|string $pathToNpm + * + * @return \Robo\Task\Npm\Update + */ + protected function taskNpmUpdate($pathToNpm = null) + { + return $this->task(Update::class, $pathToNpm); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/Rsync.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/Rsync.php new file mode 100644 index 00000000..5c334af4 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/Rsync.php @@ -0,0 +1,484 @@ +taskRsync() + * ->fromPath('src/') + * ->toHost('localhost') + * ->toUser('dev') + * ->toPath('/var/www/html/app/') + * ->remoteShell('ssh -i public_key') + * ->recursive() + * ->excludeVcs() + * ->checksum() + * ->wholeFile() + * ->verbose() + * ->progress() + * ->humanReadable() + * ->stats() + * ->run(); + * ``` + * + * You could also clone the task and do a dry-run first: + * + * ``` php + * $rsync = $this->taskRsync() + * ->fromPath('src/') + * ->toPath('example.com:/var/www/html/app/') + * ->archive() + * ->excludeVcs() + * ->progress() + * ->stats(); + * + * $dryRun = clone $rsync; + * $dryRun->dryRun()->run(); + * if ('y' === $this->ask('Do you want to run (y/n)')) { + * $rsync->run(); + * } + * ``` + */ +class Rsync extends BaseTask implements CommandInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * @var string + */ + protected $fromUser; + + /** + * @var string + */ + protected $fromHost; + + /** + * @var string + */ + protected $fromPath; + + /** + * @var string + */ + protected $toUser; + + /** + * @var string + */ + protected $toHost; + + /** + * @var string + */ + protected $toPath; + + /** + * @return static + */ + public static function init() + { + return new static(); + } + + public function __construct() + { + $this->command = 'rsync'; + } + + /** + * This can either be a full rsync path spec (user@host:path) or just a path. + * In case of the former do not specify host and user. + * + * @param string|array $path + * + * @return $this + */ + public function fromPath($path) + { + $this->fromPath = $path; + + return $this; + } + + /** + * This can either be a full rsync path spec (user@host:path) or just a path. + * In case of the former do not specify host and user. + * + * @param string $path + * + * @return $this + */ + public function toPath($path) + { + $this->toPath = $path; + + return $this; + } + + /** + * @param string $fromUser + * + * @return $this + */ + public function fromUser($fromUser) + { + $this->fromUser = $fromUser; + return $this; + } + + /** + * @param string $fromHost + * + * @return $this + */ + public function fromHost($fromHost) + { + $this->fromHost = $fromHost; + return $this; + } + + /** + * @param string $toUser + * + * @return $this + */ + public function toUser($toUser) + { + $this->toUser = $toUser; + return $this; + } + + /** + * @param string $toHost + * + * @return $this + */ + public function toHost($toHost) + { + $this->toHost = $toHost; + return $this; + } + + /** + * @return $this + */ + public function progress() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function stats() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function recursive() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function verbose() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function checksum() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function archive() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function compress() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function owner() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function group() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function times() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function delete() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @param int $seconds + * + * @return $this + */ + public function timeout($seconds) + { + $this->option(__FUNCTION__, $seconds); + + return $this; + } + + /** + * @return $this + */ + public function humanReadable() + { + $this->option('human-readable'); + + return $this; + } + + /** + * @return $this + */ + public function wholeFile() + { + $this->option('whole-file'); + + return $this; + } + + /** + * @return $this + */ + public function dryRun() + { + $this->option('dry-run'); + + return $this; + } + + /** + * @return $this + */ + public function itemizeChanges() + { + $this->option('itemize-changes'); + + return $this; + } + + /** + * Excludes .git, .svn and .hg items at any depth. + * + * @return $this + */ + public function excludeVcs() + { + return $this->exclude([ + '.git', + '.svn', + '.hg', + ]); + } + + /** + * @param array|string $pattern + * + * @return $this + */ + public function exclude($pattern) + { + return $this->optionList(__FUNCTION__, $pattern); + } + + /** + * @param string $file + * + * @return $this + * + * @throws \Robo\Exception\TaskException + */ + public function excludeFrom($file) + { + if (!is_readable($file)) { + throw new TaskException($this, "Exclude file $file is not readable"); + } + + return $this->option('exclude-from', $file); + } + + /** + * @param array|string $pattern + * + * @return $this + */ + public function includeFilter($pattern) + { + return $this->optionList('include', $pattern); + } + + /** + * @param array|string $pattern + * + * @return $this + */ + public function filter($pattern) + { + return $this->optionList(__FUNCTION__, $pattern); + } + + /** + * @param string $file + * + * @return $this + * + * @throws \Robo\Exception\TaskException + */ + public function filesFrom($file) + { + if (!is_readable($file)) { + throw new TaskException($this, "Files-from file $file is not readable"); + } + + return $this->option('files-from', $file); + } + + /** + * @param string $command + * + * @return $this + */ + public function remoteShell($command) + { + $this->option('rsh', "'$command'"); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + + return $this->executeCommand($command); + } + + /** + * Returns command that can be executed. + * This method is used to pass generated command from one task to another. + * + * @return string + */ + public function getCommand() + { + foreach ((array)$this->fromPath as $from) { + $this->option(null, $this->getFromPathSpec($from)); + } + $this->option(null, $this->getToPathSpec()); + + return $this->command . $this->arguments; + } + + /** + * @return string + */ + protected function getFromPathSpec($from) + { + return $this->getPathSpec($this->fromHost, $this->fromUser, $from); + } + + /** + * @return string + */ + protected function getToPathSpec() + { + return $this->getPathSpec($this->toHost, $this->toUser, $this->toPath); + } + + /** + * @param string $host + * @param string $user + * @param string $path + * + * @return string + */ + protected function getPathSpec($host, $user, $path) + { + $spec = isset($path) ? $path : ''; + if (!empty($host)) { + $spec = "{$host}:{$spec}"; + } + if (!empty($user)) { + $spec = "{$user}@{$spec}"; + } + + return $spec; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/Ssh.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/Ssh.php new file mode 100644 index 00000000..69df9fe2 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/Ssh.php @@ -0,0 +1,273 @@ +taskSshExec('remote.example.com', 'user') + * ->remoteDir('/var/www/html') + * ->exec('ls -la') + * ->exec('chmod g+x logs') + * ->run(); + * + * ``` + * + * You can even exec other tasks (which implement CommandInterface): + * + * ```php + * $gitTask = $this->taskGitStack() + * ->checkout('master') + * ->pull(); + * + * $this->taskSshExec('remote.example.com') + * ->remoteDir('/var/www/html/site') + * ->exec($gitTask) + * ->run(); + * ``` + * + * You can configure the remote directory for all future calls: + * + * ```php + * \Robo\Task\Remote\Ssh::configure('remoteDir', '/some-dir'); + * ``` + */ +class Ssh extends BaseTask implements CommandInterface, SimulatedInterface +{ + use \Robo\Common\CommandReceiver; + use \Robo\Common\ExecOneCommand; + + /** + * @var null|string + */ + protected $hostname; + + /** + * @var null|string + */ + protected $user; + + /** + * @var bool + */ + protected $stopOnFail = true; + + /** + * @var array + */ + protected $exec = []; + + /** + * Changes to the given directory before running commands. + * + * @var string + */ + protected $remoteDir; + + /** + * @param null|string $hostname + * @param null|string $user + */ + public function __construct($hostname = null, $user = null) + { + $this->hostname = $hostname; + $this->user = $user; + } + + /** + * @param string $hostname + * + * @return $this + */ + public function hostname($hostname) + { + $this->hostname = $hostname; + return $this; + } + + /** + * @param string $user + * + * @return $this + */ + public function user($user) + { + $this->user = $user; + return $this; + } + + /** + * Whether or not to chain commands together with && and stop the chain if one command fails. + * + * @param bool $stopOnFail + * + * @return $this + */ + public function stopOnFail($stopOnFail = true) + { + $this->stopOnFail = $stopOnFail; + return $this; + } + + /** + * Changes to the given directory before running commands. + * + * @param string $remoteDir + * + * @return $this + */ + public function remoteDir($remoteDir) + { + $this->remoteDir = $remoteDir; + return $this; + } + + /** + * @param string $filename + * + * @return $this + */ + public function identityFile($filename) + { + $this->option('-i', $filename); + + return $this; + } + + /** + * @param int $port + * + * @return $this + */ + public function port($port) + { + $this->option('-p', $port); + + return $this; + } + + /** + * @return $this + */ + public function forcePseudoTty() + { + $this->option('-t'); + + return $this; + } + + /** + * @return $this + */ + public function quiet() + { + $this->option('-q'); + + return $this; + } + + /** + * @return $this + */ + public function verbose() + { + $this->option('-v'); + + return $this; + } + + /** + * @param string|string[]|CommandInterface $command + * + * @return $this + */ + public function exec($command) + { + if (is_array($command)) { + $command = implode(' ', array_filter($command)); + } + + $this->exec[] = $command; + + return $this; + } + + /** + * Returns command that can be executed. + * This method is used to pass generated command from one task to another. + * + * @return string + */ + public function getCommand() + { + $commands = []; + foreach ($this->exec as $command) { + $commands[] = $this->receiveCommand($command); + } + + $remoteDir = $this->remoteDir ? $this->remoteDir : $this->getConfigValue('remoteDir'); + if (!empty($remoteDir)) { + array_unshift($commands, sprintf('cd "%s"', $remoteDir)); + } + $command = implode($this->stopOnFail ? ' && ' : ' ; ', $commands); + + return $this->sshCommand($command); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->validateParameters(); + $command = $this->getCommand(); + return $this->executeCommand($command); + } + + /** + * {@inheritdoc} + */ + public function simulate($context) + { + $command = $this->getCommand(); + $this->printTaskInfo("Running {command}", ['command' => $command] + $context); + } + + protected function validateParameters() + { + if (empty($this->hostname)) { + throw new TaskException($this, 'Please set a hostname'); + } + if (empty($this->exec)) { + throw new TaskException($this, 'Please add at least one command'); + } + } + + /** + * Returns an ssh command string running $command on the remote. + * + * @param string|CommandInterface $command + * + * @return string + */ + protected function sshCommand($command) + { + $command = $this->receiveCommand($command); + $sshOptions = $this->arguments; + $hostSpec = $this->hostname; + if ($this->user) { + $hostSpec = $this->user . '@' . $hostSpec; + } + + return "ssh{$sshOptions} {$hostSpec} '{$command}'"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/loadTasks.php new file mode 100644 index 00000000..092d2a55 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Remote/loadTasks.php @@ -0,0 +1,24 @@ +task(Rsync::class); + } + + /** + * @param null|string $hostname + * @param null|string $user + * + * @return \Robo\Task\Remote\Ssh + */ + protected function taskSshExec($hostname = null, $user = null) + { + return $this->task(Ssh::class, $hostname, $user); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Simulator.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Simulator.php new file mode 100644 index 00000000..e69d23fa --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Simulator.php @@ -0,0 +1,168 @@ +task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + $this->constructorParameters = $constructorParameters; + } + + /** + * @param string $function + * @param array $args + * + * @return \Robo\Result|\Robo\Task\Simulator + */ + public function __call($function, $args) + { + $this->stack[] = array_merge([$function], $args); + $result = call_user_func_array([$this->task, $function], $args); + return $result == $this->task ? $this : $result; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $callchain = ''; + foreach ($this->stack as $action) { + $command = array_shift($action); + $parameters = $this->formatParameters($action); + $callchain .= "\n ->$command($parameters)"; + } + $context = $this->getTaskContext( + [ + '_level' => RoboLogLevel::SIMULATED_ACTION, + 'simulated' => TaskInfo::formatTaskName($this->task), + 'parameters' => $this->formatParameters($this->constructorParameters), + '_style' => ['simulated' => 'fg=blue;options=bold'], + ] + ); + + // RoboLogLevel::SIMULATED_ACTION + $this->printTaskInfo( + "Simulating {simulated}({parameters})$callchain", + $context + ); + + $result = null; + if ($this->task instanceof SimulatedInterface) { + $result = $this->task->simulate($context); + } + if (!isset($result)) { + $result = Result::success($this); + } + + return $result; + } + + /** + * Danger: reach through the simulated wrapper and pull out the command + * to be executed. This is used when using a simulated task with another + * simulated task that runs commands, e.g. the Remote\Ssh task. Using + * a simulated CommandInterface task with a non-simulated task may produce + * unexpected results (e.g. execution!). + * + * @return string + * + * @throws \Robo\Exception\TaskException + */ + public function getCommand() + { + if (!$this->task instanceof CommandInterface) { + throw new TaskException($this->task, 'Simulated task that is not a CommandInterface used as a CommandInterface.'); + } + return $this->task->getCommand(); + } + + /** + * @param string $action + * + * @return string + */ + protected function formatParameters($action) + { + $parameterList = array_map([$this, 'convertParameter'], $action); + return implode(', ', $parameterList); + } + + /** + * @param mixed $item + * + * @return string + */ + protected function convertParameter($item) + { + if (is_callable($item)) { + return 'inline_function(...)'; + } + if (is_array($item)) { + return $this->shortenParameter(var_export($item, true)); + } + if (is_object($item)) { + return '[' . get_class($item). ' object]'; + } + if (is_string($item)) { + return $this->shortenParameter("'$item'"); + } + if (is_null($item)) { + return 'null'; + } + return $item; + } + + /** + * @param string $item + * @param string $shortForm + * + * @return string + */ + protected function shortenParameter($item, $shortForm = '') + { + $maxLength = 80; + $tailLength = 20; + if (strlen($item) < $maxLength) { + return $item; + } + if (!empty($shortForm)) { + return $shortForm; + } + $item = trim($item); + $tail = preg_replace("#.*\n#ms", '', substr($item, -$tailLength)); + $head = preg_replace("#\n.*#ms", '', substr($item, 0, $maxLength - (strlen($tail) + 5))); + return "$head ... $tail"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/StackBasedTask.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/StackBasedTask.php new file mode 100644 index 00000000..91659f33 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/StackBasedTask.php @@ -0,0 +1,236 @@ +friz() + * ->fraz() + * ->frob(); + * + * We presume that the existing library throws an exception on error. + * + * You want: + * + * $result = $this->taskFrobinator($a, $b, $c) + * ->friz() + * ->fraz() + * ->frob() + * ->run(); + * + * Execution is deferred until run(), and a Robo\Result instance is + * returned. Additionally, using Robo will covert Exceptions + * into RoboResult objects. + * + * To create a new Robo task: + * + * - Make a new class that extends StackBasedTask + * - Give it a constructor that creates a new Frobinator + * - Override getDelegate(), and return the Frobinator instance + * + * Finally, add your new class to loadTasks.php as usual, + * and you are all done. + * + * If you need to add any methods to your task that should run + * immediately (e.g. to set parameters used at run() time), just + * implement them in your derived class. + * + * If you need additional methods that should run deferred, just + * define them as 'protected function _foo()'. Then, users may + * call $this->taskFrobinator()->foo() to get deferred execution + * of _foo(). + */ +abstract class StackBasedTask extends BaseTask +{ + /** + * @var array + */ + protected $stack = []; + + /** + * @var bool + */ + protected $stopOnFail = true; + + /** + * @param bool $stop + * + * @return $this + */ + public function stopOnFail($stop = true) + { + $this->stopOnFail = $stop; + return $this; + } + + /** + * Derived classes should override the getDelegate() method, and + * return an instance of the API class being wrapped. When this + * is done, any method of the delegate is available as a method of + * this class. Calling one of the delegate's methods will defer + * execution until the run() method is called. + * + * @return null + */ + protected function getDelegate() + { + return null; + } + + /** + * Derived classes that have more than one delegate may override + * getCommandList to add as many delegate commands as desired to + * the list of potential functions that __call() tried to find. + * + * @param string $function + * + * @return array + */ + protected function getDelegateCommandList($function) + { + return [[$this, "_$function"], [$this->getDelegate(), $function]]; + } + + /** + * Print progress about the commands being executed + * + * @param string $command + * @param string $action + */ + protected function printTaskProgress($command, $action) + { + $this->printTaskInfo('{command} {action}', ['command' => "{$command[1]}", 'action' => json_encode($action, JSON_UNESCAPED_SLASHES)]); + } + + /** + * Derived classes can override processResult to add more + * logic to result handling from functions. By default, it + * is assumed that if a function returns in int, then + * 0 == success, and any other value is the error code. + * + * @param int|\Robo\Result $function_result + * + * @return \Robo\Result + */ + protected function processResult($function_result) + { + if (is_int($function_result)) { + if ($function_result) { + return Result::error($this, $function_result); + } + } + return Result::success($this); + } + + /** + * Record a function to call later. + * + * @param string $command + * @param array $args + * + * @return $this + */ + protected function addToCommandStack($command, $args) + { + $this->stack[] = array_merge([$command], $args); + return $this; + } + + /** + * Any API function provided by the delegate that executes immediately + * may be handled by __call automatically. These operations will all + * be deferred until this task's run() method is called. + * + * @param string $function + * @param array $args + * + * @return $this + */ + public function __call($function, $args) + { + foreach ($this->getDelegateCommandList($function) as $command) { + if (method_exists($command[0], $command[1])) { + // Otherwise, we'll defer calling this function + // until run(), and return $this. + $this->addToCommandStack($command, $args); + return $this; + } + } + + $message = "Method $function does not exist.\n"; + throw new \BadMethodCallException($message); + } + + /** + * @return int + */ + public function progressIndicatorSteps() + { + // run() will call advanceProgressIndicator() once for each + // file, one after calling stopBuffering, and again after compression. + return count($this->stack); + } + + /** + * Run all of the queued objects on the stack + * + * @return \Robo\Result + */ + public function run() + { + $this->startProgressIndicator(); + $result = Result::success($this); + + foreach ($this->stack as $action) { + $command = array_shift($action); + $this->printTaskProgress($command, $action); + $this->advanceProgressIndicator(); + // TODO: merge data from the result on this call + // with data from the result on the previous call? + // For now, the result always comes from the last function. + $result = $this->callTaskMethod($command, $action); + if ($this->stopOnFail && $result && !$result->wasSuccessful()) { + break; + } + } + + $this->stopProgressIndicator(); + + // todo: add timing information to the result + return $result; + } + + /** + * Execute one task method + * + * @param string $command + * @param string $action + * + * @return \Robo\Result + */ + protected function callTaskMethod($command, $action) + { + try { + $function_result = call_user_func_array($command, $action); + return $this->processResult($function_result); + } catch (\Exception $e) { + $this->printTaskError($e->getMessage()); + return Result::fromException($this, $e); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Atoum.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Atoum.php new file mode 100644 index 00000000..56b47d84 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Atoum.php @@ -0,0 +1,184 @@ +taskAtoum() + * ->files('path/to/test.php') + * ->configFile('config/dev.php') + * ->run() + * + * ?> + * ``` + */ +class Atoum extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * Atoum constructor. + * + * @param null|string $pathToAtoum + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToAtoum = null) + { + $this->command = $pathToAtoum; + if (!$this->command) { + $this->command = $this->findExecutable('atoum'); + } + if (!$this->command) { + throw new \Robo\Exception\TaskException(__CLASS__, "Neither local atoum nor global composer installation not found"); + } + } + + /** + * Tag or Tags to filter. + * + * @param string|array $tags + * + * @return $this + */ + public function tags($tags) + { + return $this->addMultipleOption('tags', $tags); + } + + /** + * Display result using the light reporter. + * + * @return $this + */ + public function lightReport() + { + $this->option("--use-light-report"); + + return $this; + } + + /** + * Display result using the tap reporter. + * + * @return $this + */ + public function tap() + { + $this->option("use-tap-report"); + + return $this; + } + + /** + * Path to the bootstrap file. + + * @param string $file + * + * @return $this + */ + public function bootstrap($file) + { + $this->option("bootstrap", $file); + + return $this; + } + + /** + * Path to the config file. + * + * @param string $file + * + * @return $this + */ + public function configFile($file) + { + $this->option('-c', $file); + + return $this; + } + + /** + * Use atoum's debug mode. + * + * @return $this + */ + public function debug() + { + $this->option("debug"); + + return $this; + } + + /** + * Test file or test files to run. + * + * @param string|array + * + * @return $this + */ + public function files($files) + { + return $this->addMultipleOption('f', $files); + } + + /** + * Test directory or directories to run. + * + * @param string|array A single directory or a list of directories. + * + * @return $this + */ + public function directories($directories) + { + return $this->addMultipleOption('directories', $directories); + } + + /** + * @param string $option + * @param string|array $values + * + * @return $this + */ + protected function addMultipleOption($option, $values) + { + if (is_string($values)) { + $values = [$values]; + } + + foreach ($values as $value) { + $this->option($option, $value); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . $this->arguments; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running atoum ' . $this->arguments); + + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Behat.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Behat.php new file mode 100644 index 00000000..7e4f1d41 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Behat.php @@ -0,0 +1,163 @@ +taskBehat() + * ->format('pretty') + * ->noInteraction() + * ->run(); + * ?> + * ``` + * + */ +class Behat extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * @var string[] $formaters available formaters for format option + */ + protected $formaters = ['progress', 'pretty', 'junit']; + + /** + * @var string[] $verbose_levels available verbose levels + */ + protected $verbose_levels = ['v', 'vv']; + + /** + * Behat constructor. + * + * @param null|string $pathToBehat + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToBehat = null) + { + $this->command = $pathToBehat; + if (!$this->command) { + $this->command = $this->findExecutable('behat'); + } + if (!$this->command) { + throw new \Robo\Exception\TaskException(__CLASS__, "Neither composer nor phar installation of Behat found"); + } + } + + /** + * @return $this + */ + public function stopOnFail() + { + $this->option('stop-on-failure'); + return $this; + } + + /** + * @return $this + */ + public function noInteraction() + { + $this->option('no-interaction'); + return $this; + } + + /** + * @param $config_file + * + * @return $this + */ + public function config($config_file) + { + $this->option('config', $config_file); + return $this; + } + + /** + * @return $this + */ + public function colors() + { + $this->option('colors'); + return $this; + } + + /** + * @return $this + */ + public function noColors() + { + $this->option('no-colors'); + return $this; + } + + /** + * @param string $suite + * + * @return $this + */ + public function suite($suite) + { + $this->option('suite', $suite); + return $this; + } + + /** + * @param string $level + * + * @return $this + */ + public function verbose($level = 'v') + { + if (!in_array($level, $this->verbose_levels)) { + throw new \InvalidArgumentException('expected ' . implode(',', $this->verbose_levels)); + } + $this->option('-' . $level); + return $this; + } + + /** + * @param string $formater + * + * @return $this + */ + public function format($formater) + { + if (!in_array($formater, $this->formaters)) { + throw new \InvalidArgumentException('expected ' . implode(',', $this->formaters)); + } + $this->option('format', $formater); + return $this; + } + + /** + * Returns command that can be executed. + * This method is used to pass generated command from one task to another. + * + * @return string + */ + public function getCommand() + { + return $this->command . $this->arguments; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running behat {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Codecept.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Codecept.php new file mode 100644 index 00000000..1f8cce70 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Codecept.php @@ -0,0 +1,271 @@ +taskCodecept() + * ->suite('acceptance') + * ->env('chrome') + * ->group('admin') + * ->xml() + * ->html() + * ->run(); + * + * ?> + * ``` + * + */ +class Codecept extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * @param string $pathToCodeception + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToCodeception = '') + { + $this->command = $pathToCodeception; + if (!$this->command) { + $this->command = $this->findExecutable('codecept'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Neither composer nor phar installation of Codeception found."); + } + $this->command .= ' run'; + } + + /** + * @param string $suite + * + * @return $this + */ + public function suite($suite) + { + $this->option(null, $suite); + return $this; + } + + /** + * @param string $testName + * + * @return $this + */ + public function test($testName) + { + $this->option(null, $testName); + return $this; + } + + /** + * set group option. Can be called multiple times + * + * @param string $group + * + * @return $this + */ + public function group($group) + { + $this->option("group", $group); + return $this; + } + + /** + * @param string $group + * + * @return $this + */ + public function excludeGroup($group) + { + $this->option("skip-group", $group); + return $this; + } + + /** + * generate json report + * + * @param string $file + * + * @return $this + */ + public function json($file = null) + { + $this->option("json", $file); + return $this; + } + + /** + * generate xml JUnit report + * + * @param string $file + * + * @return $this + */ + public function xml($file = null) + { + $this->option("xml", $file); + return $this; + } + + /** + * Generate html report + * + * @param string $dir + * + * @return $this + */ + public function html($dir = null) + { + $this->option("html", $dir); + return $this; + } + + /** + * generate tap report + * + * @param string $file + * + * @return $this + */ + public function tap($file = null) + { + $this->option("tap", $file); + return $this; + } + + /** + * provides config file other then default `codeception.yml` with `-c` option + * + * @param string $file + * + * @return $this + */ + public function configFile($file) + { + $this->option("-c", $file); + return $this; + } + + /** + * collect codecoverage in raw format. You may pass name of cov file to save results + * + * @param null|string $cov + * + * @return $this + */ + public function coverage($cov = null) + { + $this->option("coverage", $cov); + return $this; + } + + /** + * execute in silent mode + * + * @return $this + */ + public function silent() + { + $this->option("silent"); + return $this; + } + + /** + * collect code coverage in xml format. You may pass name of xml file to save results + * + * @param string $xml + * + * @return $this + */ + public function coverageXml($xml = null) + { + $this->option("coverage-xml", $xml); + return $this; + } + + /** + * collect code coverage and generate html report. You may pass + * + * @param string $html + * + * @return $this + */ + public function coverageHtml($html = null) + { + $this->option("coverage-html", $html); + return $this; + } + + /** + * @param string $env + * + * @return $this + */ + public function env($env) + { + $this->option("env", $env); + return $this; + } + + /** + * @return $this + */ + public function debug() + { + $this->option("debug"); + return $this; + } + + /** + * @return $this + */ + public function noRebuild() + { + $this->option("no-rebuild"); + return $this; + } + + /** + * @param string $failGroup + * @return $this + */ + public function failGroup($failGroup) + { + $this->option('override', "extensions: config: Codeception\\Extension\\RunFailed: fail-group: {$failGroup}"); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . $this->arguments; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Executing {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/PHPUnit.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/PHPUnit.php new file mode 100644 index 00000000..df67e1c7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/PHPUnit.php @@ -0,0 +1,199 @@ +taskPHPUnit() + * ->group('core') + * ->bootstrap('test/bootstrap.php') + * ->run() + * + * ?> + * ``` + */ +class PHPUnit extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * Directory of test files or single test file to run. Appended to + * the command and arguments. + * + * @var string + */ + protected $files = ''; + + public function __construct($pathToPhpUnit = null) + { + $this->command = $pathToPhpUnit; + if (!$this->command) { + $this->command = $this->findExecutablePhar('phpunit'); + } + if (!$this->command) { + throw new \Robo\Exception\TaskException(__CLASS__, "Neither local phpunit nor global composer installation not found"); + } + } + + /** + * @param string $filter + * + * @return $this + */ + public function filter($filter) + { + $this->option('filter', $filter); + return $this; + } + + /** + * @param string $group + * + * @return $this + */ + public function group($group) + { + $this->option("group", $group); + return $this; + } + + /** + * @param string $group + * + * @return $this + */ + public function excludeGroup($group) + { + $this->option("exclude-group", $group); + return $this; + } + + /** + * adds `log-json` option to runner + * + * @param string $file + * + * @return $this + */ + public function json($file = null) + { + $this->option("log-json", $file); + return $this; + } + + /** + * adds `log-junit` option + * + * @param string $file + * + * @return $this + */ + public function xml($file = null) + { + $this->option("log-junit", $file); + return $this; + } + + /** + * @param string $file + * + * @return $this + */ + public function tap($file = "") + { + $this->option("log-tap", $file); + return $this; + } + + /** + * @param string $file + * + * @return $this + */ + public function bootstrap($file) + { + $this->option("bootstrap", $file); + return $this; + } + + /** + * @param string $file + * + * @return $this + */ + public function configFile($file) + { + $this->option('-c', $file); + return $this; + } + + /** + * @return $this + */ + public function debug() + { + $this->option("debug"); + return $this; + } + + /** + * Directory of test files or single test file to run. + * + * @param string $files A single test file or a directory containing test files. + * + * @return $this + * + * @throws \Robo\Exception\TaskException + * + * @deprecated Use file() or dir() method instead + */ + public function files($files) + { + if (!empty($this->files) || is_array($files)) { + throw new \Robo\Exception\TaskException(__CLASS__, "Only one file or directory may be provided."); + } + $this->files = ' ' . $files; + + return $this; + } + + /** + * Test the provided file. + * + * @param string $file path to file to test + * + * @return $this + */ + public function file($file) + { + return $this->files($file); + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . $this->arguments . $this->files; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running PHPUnit {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Phpspec.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Phpspec.php new file mode 100644 index 00000000..dd6a5ae7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/Phpspec.php @@ -0,0 +1,116 @@ +taskPhpspec() + * ->format('pretty') + * ->noInteraction() + * ->run(); + * ?> + * ``` + * + */ +class Phpspec extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * @var string[] $formaters available formaters for format option + */ + protected $formaters = ['progress', 'html', 'pretty', 'junit', 'dot', 'tap']; + + /** + * @var array $verbose_levels available verbose levels + */ + protected $verbose_levels = ['v', 'vv', 'vvv']; + + public function __construct($pathToPhpspec = null) + { + $this->command = $pathToPhpspec; + if (!$this->command) { + $this->command = $this->findExecutable('phpspec'); + } + if (!$this->command) { + throw new \Robo\Exception\TaskException(__CLASS__, "Neither composer nor phar installation of Phpspec found"); + } + $this->arg('run'); + } + + public function stopOnFail() + { + $this->option('stop-on-failure'); + return $this; + } + + public function noCodeGeneration() + { + $this->option('no-code-generation'); + return $this; + } + + public function quiet() + { + $this->option('quiet'); + return $this; + } + + public function verbose($level = 'v') + { + if (!in_array($level, $this->verbose_levels)) { + throw new \InvalidArgumentException('expected ' . implode(',', $this->verbose_levels)); + } + $this->option('-' . $level); + return $this; + } + + public function noAnsi() + { + $this->option('no-ansi'); + return $this; + } + + public function noInteraction() + { + $this->option('no-interaction'); + return $this; + } + + public function config($config_file) + { + $this->option('config', $config_file); + return $this; + } + + public function format($formater) + { + if (!in_array($formater, $this->formaters)) { + throw new \InvalidArgumentException('expected ' . implode(',', $this->formaters)); + } + $this->option('format', $formater); + return $this; + } + + public function getCommand() + { + return $this->command . $this->arguments; + } + + public function run() + { + $this->printTaskInfo('Running phpspec {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/loadTasks.php new file mode 100644 index 00000000..43145b9b --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Testing/loadTasks.php @@ -0,0 +1,55 @@ +task(Codecept::class, $pathToCodeception); + } + + /** + * @param null|string $pathToPhpUnit + * + * @return \Robo\Task\Testing\PHPUnit + */ + protected function taskPhpUnit($pathToPhpUnit = null) + { + return $this->task(PHPUnit::class, $pathToPhpUnit); + } + + /** + * @param null $pathToPhpspec + * + * @return \Robo\Task\Testing\Phpspec + */ + protected function taskPhpspec($pathToPhpspec = null) + { + return $this->task(Phpspec::class, $pathToPhpspec); + } + + /** + * @param null $pathToAtoum + * + * @return \Robo\Task\Testing\Atoum + */ + protected function taskAtoum($pathToAtoum = null) + { + return $this->task(Atoum::class, $pathToAtoum); + } + + /** + * @param null $pathToBehat + * + * @return \Robo\Task\Testing\Behat + */ + protected function taskBehat($pathToBehat = null) + { + return $this->task(Behat::class, $pathToBehat); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/GitStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/GitStack.php new file mode 100644 index 00000000..6cb1783f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/GitStack.php @@ -0,0 +1,177 @@ +taskGitStack() + * ->stopOnFail() + * ->add('-A') + * ->commit('adding everything') + * ->push('origin','master') + * ->tag('0.6.0') + * ->push('origin','0.6.0') + * ->run() + * + * $this->taskGitStack() + * ->stopOnFail() + * ->add('doc/*') + * ->commit('doc updated') + * ->push() + * ->run(); + * ?> + * ``` + */ +class GitStack extends CommandStack +{ + /** + * @param string $pathToGit + */ + public function __construct($pathToGit = 'git') + { + $this->executable = $pathToGit; + } + + /** + * Executes `git clone` + * + * @param string $repo + * @param string $to + * + * @return $this + */ + public function cloneRepo($repo, $to = "", $branch = "") + { + $cmd = ['clone', $repo, $to]; + if (!empty($branch)) { + $cmd[] = "--branch $branch"; + } + return $this->exec($cmd); + } + + /** + * Executes `git clone` with depth 1 as default + * + * @param string $repo + * @param string $to + * @param string $branch + * @param int $depth + * + * @return $this + */ + public function cloneShallow($repo, $to = '', $branch = "", $depth = 1) + { + $cmd = ["clone --depth $depth", $repo, $to]; + if (!empty($branch)) { + $cmd[] = "--branch $branch"; + } + + return $this->exec($cmd); + } + + /** + * Executes `git add` command with files to add pattern + * + * @param string $pattern + * + * @return $this + */ + public function add($pattern) + { + return $this->exec([__FUNCTION__, $pattern]); + } + + /** + * Executes `git commit` command with a message + * + * @param string $message + * @param string $options + * + * @return $this + */ + public function commit($message, $options = "") + { + $message = ProcessUtils::escapeArgument($message); + return $this->exec([__FUNCTION__, "-m $message", $options]); + } + + /** + * Executes `git pull` command. + * + * @param string $origin + * @param string $branch + * + * @return $this + */ + public function pull($origin = '', $branch = '') + { + return $this->exec([__FUNCTION__, $origin, $branch]); + } + + /** + * Executes `git push` command + * + * @param string $origin + * @param string $branch + * + * @return $this + */ + public function push($origin = '', $branch = '') + { + return $this->exec([__FUNCTION__, $origin, $branch]); + } + + /** + * Performs git merge + * + * @param string $branch + * + * @return $this + */ + public function merge($branch) + { + return $this->exec([__FUNCTION__, $branch]); + } + + /** + * Executes `git checkout` command + * + * @param string $branch + * + * @return $this + */ + public function checkout($branch) + { + return $this->exec([__FUNCTION__, $branch]); + } + + /** + * Executes `git tag` command + * + * @param string $tag_name + * @param string $message + * + * @return $this + */ + public function tag($tag_name, $message = "") + { + if ($message != "") { + $message = "-m '$message'"; + } + return $this->exec([__FUNCTION__, $message, $tag_name]); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo("Running git commands..."); + return parent::run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/HgStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/HgStack.php new file mode 100644 index 00000000..71cc0ca9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/HgStack.php @@ -0,0 +1,153 @@ +hgStack + * ->cloneRepo('https://bitbucket.org/durin42/hgsubversion') + * ->pull() + * ->add() + * ->commit('changed') + * ->push() + * ->tag('0.6.0') + * ->push('0.6.0') + * ->run(); + * ?> + * ``` + */ +class HgStack extends CommandStack +{ + + /** + * @param string $pathToHg + */ + public function __construct($pathToHg = 'hg') + { + $this->executable = $pathToHg; + } + + /** + * Executes `hg clone` + * + * @param string $repo + * @param string $to + * + * @return $this + */ + public function cloneRepo($repo, $to = '') + { + return $this->exec(['clone', $repo, $to]); + } + + /** + * Executes `hg add` command with files to add by pattern + * + * @param string $include + * @param string $exclude + * + * @return $this + */ + public function add($include = '', $exclude = '') + { + if (strlen($include) > 0) { + $include = "-I {$include}"; + } + + if (strlen($exclude) > 0) { + $exclude = "-X {$exclude}"; + } + + return $this->exec([__FUNCTION__, $include, $exclude]); + } + + /** + * Executes `hg commit` command with a message + * + * @param string $message + * @param string $options + * + * @return $this + */ + public function commit($message, $options = '') + { + return $this->exec([__FUNCTION__, "-m '{$message}'", $options]); + } + + /** + * Executes `hg pull` command. + * + * @param string $branch + * + * @return $this + */ + public function pull($branch = '') + { + if (strlen($branch) > 0) { + $branch = "-b '{$branch}''"; + } + + return $this->exec([__FUNCTION__, $branch]); + } + + /** + * Executes `hg push` command + * + * @param string $branch + * + * @return $this + */ + public function push($branch = '') + { + if (strlen($branch) > 0) { + $branch = "-b '{$branch}'"; + } + + return $this->exec([__FUNCTION__, $branch]); + } + + /** + * Performs hg merge + * + * @param string $revision + * + * @return $this + */ + public function merge($revision = '') + { + if (strlen($revision) > 0) { + $revision = "-r {$revision}"; + } + + return $this->exec([__FUNCTION__, $revision]); + } + + /** + * Executes `hg tag` command + * + * @param string $tag_name + * @param string $message + * + * @return $this + */ + public function tag($tag_name, $message = '') + { + if ($message !== '') { + $message = "-m '{$message}'"; + } + return $this->exec([__FUNCTION__, $message, $tag_name]); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running hg commands...'); + return parent::run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/SvnStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/SvnStack.php new file mode 100644 index 00000000..ec719b53 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/SvnStack.php @@ -0,0 +1,106 @@ +taskSvnStack() + * ->checkout('http://svn.collab.net/repos/svn/trunk') + * ->run() + * + * // alternatively + * $this->_svnCheckout('http://svn.collab.net/repos/svn/trunk'); + * + * $this->taskSvnStack('username', 'password') + * ->stopOnFail() + * ->update() + * ->add('doc/*') + * ->commit('doc updated') + * ->run(); + * ?> + * ``` + */ +class SvnStack extends CommandStack implements CommandInterface +{ + /** + * @var bool + */ + protected $stopOnFail = false; + + /** + * @var \Robo\Result + */ + protected $result; + + /** + * @param string $username + * @param string $password + * @param string $pathToSvn + */ + public function __construct($username = '', $password = '', $pathToSvn = 'svn') + { + $this->executable = $pathToSvn; + if (!empty($username)) { + $this->executable .= " --username $username"; + } + if (!empty($password)) { + $this->executable .= " --password $password"; + } + $this->result = Result::success($this); + } + + /** + * Updates `svn update` command + * + * @param string $path + * + * @return $this; + */ + public function update($path = '') + { + return $this->exec("update $path"); + } + + /** + * Executes `svn add` command with files to add pattern + * + * @param string $pattern + * + * @return $this + */ + public function add($pattern = '') + { + return $this->exec("add $pattern"); + } + + /** + * Executes `svn commit` command with a message + * + * @param string $message + * @param string $options + * + * @return $this + */ + public function commit($message, $options = "") + { + return $this->exec("commit -m '$message' $options"); + } + + /** + * Executes `svn checkout` command + * + * @param string $branch + * + * @return $this + */ + public function checkout($branch) + { + return $this->exec("checkout $branch"); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/loadShortcuts.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/loadShortcuts.php new file mode 100644 index 00000000..7d64ab58 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/loadShortcuts.php @@ -0,0 +1,35 @@ +taskSvnStack()->checkout($url)->run(); + } + + /** + * @param string $url + * + * @return \Robo\Result + */ + protected function _gitClone($url) + { + return $this->taskGitStack()->cloneRepo($url)->run(); + } + + /** + * @param string $url + * + * @return \Robo\Result + */ + protected function _hgClone($url) + { + return $this->taskHgStack()->cloneRepo($url)->run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/loadTasks.php new file mode 100644 index 00000000..6dd06228 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Task/Vcs/loadTasks.php @@ -0,0 +1,37 @@ +task(SvnStack::class, $username, $password, $pathToSvn); + } + + /** + * @param string $pathToGit + * + * @return \Robo\Task\Vcs\GitStack + */ + protected function taskGitStack($pathToGit = 'git') + { + return $this->task(GitStack::class, $pathToGit); + } + + /** + * @param string $pathToHg + * + * @return \Robo\Task\Vcs\HgStack + */ + protected function taskHgStack($pathToHg = 'hg') + { + return $this->task(HgStack::class, $pathToHg); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/TaskAccessor.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/TaskAccessor.php new file mode 100644 index 00000000..e65cd3eb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/TaskAccessor.php @@ -0,0 +1,47 @@ +task(Foo::class, $a, $b); + * + * instead of: + * + * $this->taskFoo($a, $b); + * + * The later form is preferred. + * + * @return \Robo\Collection\CollectionBuilder + */ + protected function task() + { + $args = func_get_args(); + $name = array_shift($args); + + $collectionBuilder = $this->collectionBuilder(); + return $collectionBuilder->build($name, $args); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/TaskInfo.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/TaskInfo.php new file mode 100644 index 00000000..ce59c2d5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/TaskInfo.php @@ -0,0 +1,35 @@ + TaskInfo::formatTaskName($task), + 'task' => $task, + ]; + } + + /** + * @param object $task + * + * @return string + */ + public static function formatTaskName($task) + { + $name = get_class($task); + $name = preg_replace('~Stack^~', '', $name); + $name = str_replace('Robo\\Task\Base\\', '', $name); + $name = str_replace('Robo\\Task\\', '', $name); + $name = str_replace('Robo\\Collection\\', '', $name); + return $name; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Tasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Tasks.php new file mode 100644 index 00000000..2822d7d5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony2/src/Tasks.php @@ -0,0 +1,23 @@ +getDefinition() + ->addOption( + new InputOption('--simulate', null, InputOption::VALUE_NONE, 'Run in simulated mode (show what would have happened).') + ); + $this->getDefinition() + ->addOption( + new InputOption('--progress-delay', null, InputOption::VALUE_REQUIRED, 'Number of seconds before progress bar is displayed in long-running task collections. Default: 2s.', Config::DEFAULT_PROGRESS_DELAY) + ); + + $this->getDefinition() + ->addOption( + new InputOption('--define', '-D', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Define a configuration item value.', []) + ); + } + + /** + * @param string $roboFile + * @param string $roboClass + */ + public function addInitRoboFileCommand($roboFile, $roboClass) + { + $createRoboFile = new Command('init'); + $createRoboFile->setDescription("Intitalizes basic RoboFile in current dir"); + $createRoboFile->setCode(function () use ($roboClass, $roboFile) { + $output = Robo::output(); + $output->writeln(" ~~~ Welcome to Robo! ~~~~ "); + $output->writeln(" ". basename($roboFile) ." will be created in the current directory "); + file_put_contents( + $roboFile, + 'writeln(" Edit this file to add your commands! "); + }); + $this->add($createRoboFile); + } + + /** + * Add self update command, do nothing if null is provided + * + * @param string $repository GitHub Repository for self update + */ + public function addSelfUpdateCommand($repository = null) + { + if (!$repository) { + return; + } + $selfUpdateCommand = new SelfUpdateCommand($this->getName(), $this->getVersion(), $repository); + $this->add($selfUpdateCommand); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CallableTask.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CallableTask.php new file mode 100644 index 00000000..ae9c54fc --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CallableTask.php @@ -0,0 +1,62 @@ +fn = $fn; + $this->reference = $reference; + } + + /** + * @return \Robo\Result + */ + public function run() + { + $result = call_user_func($this->fn, $this->getState()); + // If the function returns no result, then count it + // as a success. + if (!isset($result)) { + $result = Result::success($this->reference); + } + // If the function returns a result, it must either return + // a \Robo\Result or an exit code. In the later case, we + // convert it to a \Robo\Result. + if (!$result instanceof Result) { + $result = new Result($this->reference, $result); + } + + return $result; + } + + public function getState() + { + if ($this->reference instanceof StateAwareInterface) { + return $this->reference->getState(); + } + return new Data(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Collection.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Collection.php new file mode 100644 index 00000000..607435a4 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Collection.php @@ -0,0 +1,769 @@ +resetState(); + } + + public function setProgressBarAutoDisplayInterval($interval) + { + if (!$this->progressIndicator) { + return; + } + return $this->progressIndicator->setProgressBarAutoDisplayInterval($interval); + } + + /** + * {@inheritdoc} + */ + public function add(TaskInterface $task, $name = self::UNNAMEDTASK) + { + $task = new CompletionWrapper($this, $task); + $this->addToTaskList($name, $task); + return $this; + } + + /** + * {@inheritdoc} + */ + public function addCode(callable $code, $name = self::UNNAMEDTASK) + { + return $this->add(new CallableTask($code, $this), $name); + } + + /** + * {@inheritdoc} + */ + public function addIterable($iterable, callable $code) + { + $callbackTask = (new IterationTask($iterable, $code, $this))->inflect($this); + return $this->add($callbackTask); + } + + /** + * {@inheritdoc} + */ + public function rollback(TaskInterface $rollbackTask) + { + // Rollback tasks always try as hard as they can, and never report failures. + $rollbackTask = $this->ignoreErrorsTaskWrapper($rollbackTask); + return $this->wrapAndRegisterRollback($rollbackTask); + } + + /** + * {@inheritdoc} + */ + public function rollbackCode(callable $rollbackCode) + { + // Rollback tasks always try as hard as they can, and never report failures. + $rollbackTask = $this->ignoreErrorsCodeWrapper($rollbackCode); + return $this->wrapAndRegisterRollback($rollbackTask); + } + + /** + * {@inheritdoc} + */ + public function completion(TaskInterface $completionTask) + { + $collection = $this; + $completionRegistrationTask = new CallableTask( + function () use ($collection, $completionTask) { + + $collection->registerCompletion($completionTask); + }, + $this + ); + $this->addToTaskList(self::UNNAMEDTASK, $completionRegistrationTask); + return $this; + } + + /** + * {@inheritdoc} + */ + public function completionCode(callable $completionTask) + { + $completionTask = new CallableTask($completionTask, $this); + return $this->completion($completionTask); + } + + /** + * {@inheritdoc} + */ + public function before($name, $task, $nameOfTaskToAdd = self::UNNAMEDTASK) + { + return $this->addBeforeOrAfter(__FUNCTION__, $name, $task, $nameOfTaskToAdd); + } + + /** + * {@inheritdoc} + */ + public function after($name, $task, $nameOfTaskToAdd = self::UNNAMEDTASK) + { + return $this->addBeforeOrAfter(__FUNCTION__, $name, $task, $nameOfTaskToAdd); + } + + /** + * {@inheritdoc} + */ + public function progressMessage($text, $context = [], $level = LogLevel::NOTICE) + { + $context += ['name' => 'Progress']; + $context += TaskInfo::getTaskContext($this); + return $this->addCode( + function () use ($level, $text, $context) { + $context += $this->getState()->getData(); + $this->printTaskOutput($level, $text, $context); + } + ); + } + + /** + * @param \Robo\Contract\TaskInterface $rollbackTask + * + * @return $this + */ + protected function wrapAndRegisterRollback(TaskInterface $rollbackTask) + { + $collection = $this; + $rollbackRegistrationTask = new CallableTask( + function () use ($collection, $rollbackTask) { + $collection->registerRollback($rollbackTask); + }, + $this + ); + $this->addToTaskList(self::UNNAMEDTASK, $rollbackRegistrationTask); + return $this; + } + + /** + * Add either a 'before' or 'after' function or task. + * + * @param string $method + * @param string $name + * @param callable|TaskInterface $task + * @param string $nameOfTaskToAdd + * + * @return $this + */ + protected function addBeforeOrAfter($method, $name, $task, $nameOfTaskToAdd) + { + if (is_callable($task)) { + $task = new CallableTask($task, $this); + } + $existingTask = $this->namedTask($name); + $fn = [$existingTask, $method]; + call_user_func($fn, $task, $nameOfTaskToAdd); + return $this; + } + + /** + * Wrap the provided task in a wrapper that will ignore + * any errors or exceptions that may be produced. This + * is useful, for example, in adding optional cleanup tasks + * at the beginning of a task collection, to remove previous + * results which may or may not exist. + * + * TODO: Provide some way to specify which sort of errors + * are ignored, so that 'file not found' may be ignored, + * but 'permission denied' reported? + * + * @param \Robo\Contract\TaskInterface $task + * + * @return \Robo\Collection\CallableTask + */ + public function ignoreErrorsTaskWrapper(TaskInterface $task) + { + // If the task is a stack-based task, then tell it + // to try to run all of its operations, even if some + // of them fail. + if ($task instanceof StackBasedTask) { + $task->stopOnFail(false); + } + $ignoreErrorsInTask = function () use ($task) { + $data = []; + try { + $result = $this->runSubtask($task); + $message = $result->getMessage(); + $data = $result->getData(); + $data['exitcode'] = $result->getExitCode(); + } catch (\Exception $e) { + $message = $e->getMessage(); + } + + return Result::success($task, $message, $data); + }; + // Wrap our ignore errors callable in a task. + return new CallableTask($ignoreErrorsInTask, $this); + } + + /** + * @param callable $task + * + * @return \Robo\Collection\CallableTask + */ + public function ignoreErrorsCodeWrapper(callable $task) + { + return $this->ignoreErrorsTaskWrapper(new CallableTask($task, $this)); + } + + /** + * Return the list of task names added to this collection. + * + * @return array + */ + public function taskNames() + { + return array_keys($this->taskList); + } + + /** + * Test to see if a specified task name exists. + * n.b. before() and after() require that the named + * task exist; use this function to test first, if + * unsure. + * + * @param string $name + * + * @return bool + */ + public function hasTask($name) + { + return array_key_exists($name, $this->taskList); + } + + /** + * Find an existing named task. + * + * @param string $name + * The name of the task to insert before. The named task MUST exist. + * + * @return Element + * The task group for the named task. Generally this is only + * used to call 'before()' and 'after()'. + */ + protected function namedTask($name) + { + if (!$this->hasTask($name)) { + throw new \RuntimeException("Could not find task named $name"); + } + return $this->taskList[$name]; + } + + /** + * Add a list of tasks to our task collection. + * + * @param TaskInterface[] $tasks + * An array of tasks to run with rollback protection + * + * @return $this + */ + public function addTaskList(array $tasks) + { + foreach ($tasks as $name => $task) { + $this->add($task, $name); + } + return $this; + } + + /** + * Add the provided task to our task list. + * + * @param string $name + * @param \Robo\Contract\TaskInterface $task + * + * @return \Robo\Collection\Collection + */ + protected function addToTaskList($name, TaskInterface $task) + { + // All tasks are stored in a task group so that we have a place + // to hang 'before' and 'after' tasks. + $taskGroup = new Element($task); + return $this->addCollectionElementToTaskList($name, $taskGroup); + } + + /** + * @param int|string $name + * @param \Robo\Collection\Element $taskGroup + * + * @return $this + */ + protected function addCollectionElementToTaskList($name, Element $taskGroup) + { + // If a task name is not provided, then we'll let php pick + // the array index. + if (Result::isUnnamed($name)) { + $this->taskList[] = $taskGroup; + return $this; + } + // If we are replacing an existing task with the + // same name, ensure that our new task is added to + // the end. + $this->taskList[$name] = $taskGroup; + return $this; + } + + /** + * Set the parent collection. This is necessary so that nested + * collections' rollback and completion tasks can be added to the + * top-level collection, ensuring that the rollbacks for a collection + * will run if any later task fails. + * + * @param \Robo\Collection\NestedCollectionInterface $parentCollection + * + * @return $this + */ + public function setParentCollection(NestedCollectionInterface $parentCollection) + { + $this->parentCollection = $parentCollection; + return $this; + } + + /** + * Get the appropriate parent collection to use + * + * @return CollectionInterface + */ + public function getParentCollection() + { + return $this->parentCollection ? $this->parentCollection : $this; + } + + /** + * Register a rollback task to run if there is any failure. + * + * Clients are free to add tasks to the rollback stack as + * desired; however, usually it is preferable to call + * Collection::rollback() instead. With that function, + * the rollback function will only be called if all of the + * tasks added before it complete successfully, AND some later + * task fails. + * + * One example of a good use-case for registering a callback + * function directly is to add a task that sends notification + * when a task fails. + * + * @param TaskInterface $rollbackTask + * The rollback task to run on failure. + */ + public function registerRollback(TaskInterface $rollbackTask) + { + if ($this->parentCollection) { + return $this->parentCollection->registerRollback($rollbackTask); + } + if ($rollbackTask) { + $this->rollbackStack[] = $rollbackTask; + } + } + + /** + * Register a completion task to run once all other tasks finish. + * Completion tasks run whether or not a rollback operation was + * triggered. They do not trigger rollbacks if they fail. + * + * The typical use-case for a completion function is to clean up + * temporary objects (e.g. temporary folders). The preferred + * way to do that, though, is to use Temporary::wrap(). + * + * On failures, completion tasks will run after all rollback tasks. + * If one task collection is nested inside another task collection, + * then the nested collection's completion tasks will run as soon as + * the nested task completes; they are not deferred to the end of + * the containing collection's execution. + * + * @param TaskInterface $completionTask + * The completion task to run at the end of all other operations. + */ + public function registerCompletion(TaskInterface $completionTask) + { + if ($this->parentCollection) { + return $this->parentCollection->registerCompletion($completionTask); + } + if ($completionTask) { + // Completion tasks always try as hard as they can, and never report failures. + $completionTask = $this->ignoreErrorsTaskWrapper($completionTask); + $this->completionStack[] = $completionTask; + } + } + + /** + * Return the count of steps in this collection + * + * @return int + */ + public function progressIndicatorSteps() + { + $steps = 0; + foreach ($this->taskList as $name => $taskGroup) { + $steps += $taskGroup->progressIndicatorSteps(); + } + return $steps; + } + + /** + * A Collection of tasks can provide a command via `getCommand()` + * if it contains a single task, and that task implements CommandInterface. + * + * @return string + * + * @throws \Robo\Exception\TaskException + */ + public function getCommand() + { + if (empty($this->taskList)) { + return ''; + } + + if (count($this->taskList) > 1) { + // TODO: We could potentially iterate over the items in the collection + // and concatenate the result of getCommand() from each one, and fail + // only if we encounter a command that is not a CommandInterface. + throw new TaskException($this, "getCommand() does not work on arbitrary collections of tasks."); + } + + $taskElement = reset($this->taskList); + $task = $taskElement->getTask(); + $task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + if ($task instanceof CommandInterface) { + return $task->getCommand(); + } + + throw new TaskException($task, get_class($task) . " does not implement CommandInterface, so can't be used to provide a command"); + } + + /** + * Run our tasks, and roll back if necessary. + * + * @return \Robo\Result + */ + public function run() + { + $result = $this->runWithoutCompletion(); + $this->complete(); + return $result; + } + + /** + * @return \Robo\Result + */ + private function runWithoutCompletion() + { + $result = Result::success($this); + + if (empty($this->taskList)) { + return $result; + } + + $this->startProgressIndicator(); + if ($result->wasSuccessful()) { + foreach ($this->taskList as $name => $taskGroup) { + $taskList = $taskGroup->getTaskList(); + $result = $this->runTaskList($name, $taskList, $result); + if (!$result->wasSuccessful()) { + $this->fail(); + return $result; + } + } + $this->taskList = []; + } + $this->stopProgressIndicator(); + $result['time'] = $this->getExecutionTime(); + + return $result; + } + + /** + * Run every task in a list, but only up to the first failure. + * Return the failing result, or success if all tasks run. + * + * @param string $name + * @param TaskInterface[] $taskList + * @param \Robo\Result $result + * + * @return \Robo\Result + * + * @throws \Robo\Exception\TaskExitException + */ + private function runTaskList($name, array $taskList, Result $result) + { + try { + foreach ($taskList as $taskName => $task) { + $taskResult = $this->runSubtask($task); + $this->advanceProgressIndicator(); + // If the current task returns an error code, then stop + // execution and signal a rollback. + if (!$taskResult->wasSuccessful()) { + return $taskResult; + } + // We accumulate our results into a field so that tasks that + // have a reference to the collection may examine and modify + // the incremental results, if they wish. + $key = Result::isUnnamed($taskName) ? $name : $taskName; + $result->accumulate($key, $taskResult); + // The result message will be the message of the last task executed. + $result->setMessage($taskResult->getMessage()); + } + } catch (TaskExitException $exitException) { + $this->fail(); + throw $exitException; + } catch (\Exception $e) { + // Tasks typically should not throw, but if one does, we will + // convert it into an error and roll back. + return Result::fromException($task, $e, $result->getData()); + } + return $result; + } + + /** + * Force the rollback functions to run + * + * @return $this + */ + public function fail() + { + $this->disableProgressIndicator(); + $this->runRollbackTasks(); + $this->complete(); + return $this; + } + + /** + * Force the completion functions to run + * + * @return $this + */ + public function complete() + { + $this->detatchProgressIndicator(); + $this->runTaskListIgnoringFailures($this->completionStack); + $this->reset(); + return $this; + } + + /** + * Reset this collection, removing all tasks. + * + * @return $this + */ + public function reset() + { + $this->taskList = []; + $this->completionStack = []; + $this->rollbackStack = []; + return $this; + } + + /** + * Run all of our rollback tasks. + * + * Note that Collection does not implement RollbackInterface, but + * it may still be used as a task inside another task collection + * (i.e. you can nest task collections, if desired). + */ + protected function runRollbackTasks() + { + $this->runTaskListIgnoringFailures($this->rollbackStack); + // Erase our rollback stack once we have finished rolling + // everything back. This will allow us to potentially use + // a command collection more than once (e.g. to retry a + // failed operation after doing some error recovery). + $this->rollbackStack = []; + } + + /** + * @param TaskInterface|NestedCollectionInterface|WrappedTaskInterface $task + * + * @return \Robo\Result + */ + protected function runSubtask($task) + { + $original = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + $this->setParentCollectionForTask($original, $this->getParentCollection()); + if ($original instanceof InflectionInterface) { + $original->inflect($this); + } + if ($original instanceof StateAwareInterface) { + $original->setState($this->getState()); + } + $this->doDeferredInitialization($original); + $taskResult = $task->run(); + $taskResult = Result::ensureResult($task, $taskResult); + $this->doStateUpdates($original, $taskResult); + return $taskResult; + } + + protected function doStateUpdates($task, Data $taskResult) + { + $this->updateState($taskResult); + $key = spl_object_hash($task); + if (array_key_exists($key, $this->messageStoreKeys)) { + $state = $this->getState(); + list($stateKey, $sourceKey) = $this->messageStoreKeys[$key]; + $value = empty($sourceKey) ? $taskResult->getMessage() : $taskResult[$sourceKey]; + $state[$stateKey] = $value; + } + } + + public function storeState($task, $key, $source = '') + { + $this->messageStoreKeys[spl_object_hash($task)] = [$key, $source]; + + return $this; + } + + public function deferTaskConfiguration($task, $functionName, $stateKey) + { + return $this->defer( + $task, + function ($task, $state) use ($functionName, $stateKey) { + $fn = [$task, $functionName]; + $value = $state[$stateKey]; + $fn($value); + } + ); + } + + /** + * Defer execution of a callback function until just before a task + * runs. Use this time to provide more settings for the task, e.g. from + * the collection's shared state, which is populated with the results + * of previous test runs. + */ + public function defer($task, $callback) + { + $this->deferredCallbacks[spl_object_hash($task)][] = $callback; + + return $this; + } + + protected function doDeferredInitialization($task) + { + // If the task is a state consumer, then call its receiveState method + if ($task instanceof \Robo\State\Consumer) { + $task->receiveState($this->getState()); + } + + // Check and see if there are any deferred callbacks for this task. + $key = spl_object_hash($task); + if (!array_key_exists($key, $this->deferredCallbacks)) { + return; + } + + // Call all of the deferred callbacks + foreach ($this->deferredCallbacks[$key] as $fn) { + $fn($task, $this->getState()); + } + } + + /** + * @param TaskInterface|NestedCollectionInterface|WrappedTaskInterface $task + * @param $parentCollection + */ + protected function setParentCollectionForTask($task, $parentCollection) + { + if ($task instanceof NestedCollectionInterface) { + $task->setParentCollection($parentCollection); + } + } + + /** + * Run all of the tasks in a provided list, ignoring failures. + * This is used to roll back or complete. + * + * @param TaskInterface[] $taskList + */ + protected function runTaskListIgnoringFailures(array $taskList) + { + foreach ($taskList as $task) { + try { + $this->runSubtask($task); + } catch (\Exception $e) { + // Ignore rollback failures. + } + } + } + + /** + * Give all of our tasks to the provided collection builder. + * + * @param CollectionBuilder $builder + */ + public function transferTasks($builder) + { + foreach ($this->taskList as $name => $taskGroup) { + // TODO: We are abandoning all of our before and after tasks here. + // At the moment, transferTasks is only called under conditions where + // there will be none of these, but care should be taken if that changes. + $task = $taskGroup->getTask(); + $builder->addTaskToCollection($task); + } + $this->reset(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionBuilder.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionBuilder.php new file mode 100644 index 00000000..3e037b01 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionBuilder.php @@ -0,0 +1,571 @@ +collectionBuilder() + * ->taskFilesystemStack() + * ->mkdir('g') + * ->touch('g/g.txt') + * ->rollback( + * $this->taskDeleteDir('g') + * ) + * ->taskFilesystemStack() + * ->mkdir('g/h') + * ->touch('g/h/h.txt') + * ->taskFilesystemStack() + * ->mkdir('g/h/i/c') + * ->touch('g/h/i/i.txt') + * ->run() + * ?> + * + * In the example above, the `taskDeleteDir` will be called if + * ``` + */ +class CollectionBuilder extends BaseTask implements NestedCollectionInterface, WrappedTaskInterface, CommandInterface, StateAwareInterface +{ + use StateAwareTrait; + + /** + * @var \Robo\Tasks + */ + protected $commandFile; + + /** + * @var CollectionInterface + */ + protected $collection; + + /** + * @var TaskInterface + */ + protected $currentTask; + + /** + * @var bool + */ + protected $simulated; + + /** + * @param \Robo\Tasks $commandFile + */ + public function __construct($commandFile) + { + $this->commandFile = $commandFile; + $this->resetState(); + } + + public static function create($container, $commandFile) + { + $builder = new self($commandFile); + + $builder->setLogger($container->get('logger')); + $builder->setProgressIndicator($container->get('progressIndicator')); + $builder->setConfig($container->get('config')); + $builder->setOutputAdapter($container->get('outputAdapter')); + + return $builder; + } + + /** + * @param bool $simulated + * + * @return $this + */ + public function simulated($simulated = true) + { + $this->simulated = $simulated; + return $this; + } + + /** + * @return bool + */ + public function isSimulated() + { + if (!isset($this->simulated)) { + $this->simulated = $this->getConfig()->get(Config::SIMULATE); + } + return $this->simulated; + } + + /** + * Create a temporary directory to work in. When the collection + * completes or rolls back, the temporary directory will be deleted. + * Returns the path to the location where the directory will be + * created. + * + * @param string $prefix + * @param string $base + * @param bool $includeRandomPart + * + * @return string + */ + public function tmpDir($prefix = 'tmp', $base = '', $includeRandomPart = true) + { + // n.b. Any task that the builder is asked to create is + // automatically added to the builder's collection, and + // wrapped in the builder object. Therefore, the result + // of any call to `taskFoo()` from within the builder will + // always be `$this`. + return $this->taskTmpDir($prefix, $base, $includeRandomPart)->getPath(); + } + + /** + * Create a working directory to hold results. A temporary directory + * is first created to hold the intermediate results. After the + * builder finishes, the work directory is moved into its final location; + * any results already in place will be moved out of the way and + * then deleted. + * + * @param string $finalDestination The path where the working directory + * will be moved once the task collection completes. + * + * @return string + */ + public function workDir($finalDestination) + { + // Creating the work dir task in this context adds it to our task collection. + return $this->taskWorkDir($finalDestination)->getPath(); + } + + public function addTask(TaskInterface $task) + { + $this->getCollection()->add($task); + return $this; + } + + /** + * Add arbitrary code to execute as a task. + * + * @see \Robo\Collection\CollectionInterface::addCode + * + * @param callable $code + * @param int|string $name + * @return $this + */ + public function addCode(callable $code, $name = \Robo\Collection\CollectionInterface::UNNAMEDTASK) + { + $this->getCollection()->addCode($code, $name); + return $this; + } + + /** + * Add a list of tasks to our task collection. + * + * @param TaskInterface[] $tasks + * An array of tasks to run with rollback protection + * + * @return $this + */ + public function addTaskList(array $tasks) + { + $this->getCollection()->addTaskList($tasks); + return $this; + } + + public function rollback(TaskInterface $task) + { + // Ensure that we have a collection if we are going to add + // a rollback function. + $this->getCollection()->rollback($task); + return $this; + } + + public function rollbackCode(callable $rollbackCode) + { + $this->getCollection()->rollbackCode($rollbackCode); + return $this; + } + + public function completion(TaskInterface $task) + { + $this->getCollection()->completion($task); + return $this; + } + + public function completionCode(callable $completionCode) + { + $this->getCollection()->completionCode($completionCode); + return $this; + } + + /** + * @param string $text + * @param array $context + * @param string $level + * + * @return $this + */ + public function progressMessage($text, $context = [], $level = LogLevel::NOTICE) + { + $this->getCollection()->progressMessage($text, $context, $level); + return $this; + } + + /** + * @param \Robo\Collection\NestedCollectionInterface $parentCollection + * + * @return $this + */ + public function setParentCollection(NestedCollectionInterface $parentCollection) + { + $this->getCollection()->setParentCollection($parentCollection); + return $this; + } + + /** + * Called by the factory method of each task; adds the current + * task to the task builder. + * + * TODO: protected + * + * @param TaskInterface $task + * + * @return $this + */ + public function addTaskToCollection($task) + { + // Postpone creation of the collection until the second time + // we are called. At that time, $this->currentTask will already + // be populated. We call 'getCollection()' so that it will + // create the collection and add the current task to it. + // Note, however, that if our only tasks implements NestedCollectionInterface, + // then we should force this builder to use a collection. + if (!$this->collection && (isset($this->currentTask) || ($task instanceof NestedCollectionInterface))) { + $this->getCollection(); + } + $this->currentTask = $task; + if ($this->collection) { + $this->collection->add($task); + } + return $this; + } + + public function getState() + { + $collection = $this->getCollection(); + return $collection->getState(); + } + + public function storeState($key, $source = '') + { + return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); + } + + public function deferTaskConfiguration($functionName, $stateKey) + { + return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); + } + + public function defer($callback) + { + return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); + } + + protected function callCollectionStateFuntion($functionName, $args) + { + $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; + + array_unshift($args, $currentTask); + $collection = $this->getCollection(); + $fn = [$collection, $functionName]; + + call_user_func_array($fn, $args); + return $this; + } + + public function setVerbosityThreshold($verbosityThreshold) + { + $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; + if ($currentTask) { + $currentTask->setVerbosityThreshold($verbosityThreshold); + return $this; + } + parent::setVerbosityThreshold($verbosityThreshold); + return $this; + } + + + /** + * Return the current task for this collection builder. + * TODO: Not needed? + * + * @return \Robo\Contract\TaskInterface + */ + public function getCollectionBuilderCurrentTask() + { + return $this->currentTask; + } + + /** + * Create a new builder with its own task collection + * + * @return CollectionBuilder + */ + public function newBuilder() + { + $collectionBuilder = new self($this->commandFile); + $collectionBuilder->inflect($this); + $collectionBuilder->simulated($this->isSimulated()); + $collectionBuilder->setVerbosityThreshold($this->verbosityThreshold()); + $collectionBuilder->setState($this->getState()); + + return $collectionBuilder; + } + + /** + * Calling the task builder with methods of the current + * task calls through to that method of the task. + * + * There is extra complexity in this function that could be + * simplified if we attached the 'LoadAllTasks' and custom tasks + * to the collection builder instead of the RoboFile. While that + * change would be a better design overall, it would require that + * the user do a lot more work to set up and use custom tasks. + * We therefore take on some additional complexity here in order + * to allow users to maintain their tasks in their RoboFile, which + * is much more convenient. + * + * Calls to $this->collectionBuilder()->taskFoo() cannot be made + * directly because all of the task methods are protected. These + * calls will therefore end up here. If the method name begins + * with 'task', then it is eligible to be used with the builder. + * + * When we call getBuiltTask, below, it will use the builder attached + * to the commandfile to build the task. However, this is not what we + * want: the task needs to be built from THIS collection builder, so that + * it will be affected by whatever state is active in this builder. + * To do this, we have two choices: 1) save and restore the builder + * in the commandfile, or 2) clone the commandfile and set this builder + * on the copy. 1) is vulnerable to failure in multithreaded environments + * (currently not supported), while 2) might cause confusion if there + * is shared state maintained in the commandfile, which is in the + * domain of the user. + * + * Note that even though we are setting up the commandFile to + * use this builder, getBuiltTask always creates a new builder + * (which is constructed using all of the settings from the + * commandFile's builder), and the new task is added to that. + * We therefore need to transfer the newly built task into this + * builder. The temporary builder is discarded. + * + * @param string $fn + * @param array $args + * + * @return $this|mixed + */ + public function __call($fn, $args) + { + if (preg_match('#^task[A-Z]#', $fn) && (method_exists($this->commandFile, 'getBuiltTask'))) { + $saveBuilder = $this->commandFile->getBuilder(); + $this->commandFile->setBuilder($this); + $temporaryBuilder = $this->commandFile->getBuiltTask($fn, $args); + $this->commandFile->setBuilder($saveBuilder); + if (!$temporaryBuilder) { + throw new \BadMethodCallException("No such method $fn: task does not exist in " . get_class($this->commandFile)); + } + $temporaryBuilder->getCollection()->transferTasks($this); + return $this; + } + if (!isset($this->currentTask)) { + throw new \BadMethodCallException("No such method $fn: current task undefined in collection builder."); + } + // If the method called is a method of the current task, + // then call through to the current task's setter method. + $result = call_user_func_array([$this->currentTask, $fn], $args); + + // If something other than a setter method is called, then return its result. + $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; + if (isset($result) && ($result !== $currentTask)) { + return $result; + } + + return $this; + } + + /** + * Construct the desired task and add it to this builder. + * + * @param string|object $name + * @param array $args + * + * @return \Robo\Collection\CollectionBuilder + */ + public function build($name, $args) + { + $reflection = new ReflectionClass($name); + $task = $reflection->newInstanceArgs($args); + if (!$task) { + throw new RuntimeException("Can not construct task $name"); + } + $task = $this->fixTask($task, $args); + $this->configureTask($name, $task); + return $this->addTaskToCollection($task); + } + + /** + * @param InflectionInterface $task + * @param array $args + * + * @return \Robo\Collection\CompletionWrapper|\Robo\Task\Simulator + */ + protected function fixTask($task, $args) + { + if ($task instanceof InflectionInterface) { + $task->inflect($this); + } + if ($task instanceof BuilderAwareInterface) { + $task->setBuilder($this); + } + if ($task instanceof VerbosityThresholdInterface) { + $task->setVerbosityThreshold($this->verbosityThreshold()); + } + + // Do not wrap our wrappers. + if ($task instanceof CompletionWrapper || $task instanceof Simulator) { + return $task; + } + + // Remember whether or not this is a task before + // it gets wrapped in any decorator. + $isTask = $task instanceof TaskInterface; + $isCollection = $task instanceof NestedCollectionInterface; + + // If the task implements CompletionInterface, ensure + // that its 'complete' method is called when the application + // terminates -- but only if its 'run' method is called + // first. If the task is added to a collection, then the + // task will be unwrapped via its `original` method, and + // it will be re-wrapped with a new completion wrapper for + // its new collection. + if ($task instanceof CompletionInterface) { + $task = new CompletionWrapper(Temporary::getCollection(), $task); + } + + // If we are in simulated mode, then wrap any task in + // a TaskSimulator. + if ($isTask && !$isCollection && ($this->isSimulated())) { + $task = new \Robo\Task\Simulator($task, $args); + $task->inflect($this); + } + + return $task; + } + + /** + * Check to see if there are any setter methods defined in configuration + * for this task. + */ + protected function configureTask($taskClass, $task) + { + $taskClass = static::configClassIdentifier($taskClass); + $configurationApplier = new ConfigForSetters($this->getConfig(), $taskClass, 'task.'); + $configurationApplier->apply($task, 'settings'); + + // TODO: If we counted each instance of $taskClass that was called from + // this builder, then we could also apply configuration from + // "task.{$taskClass}[$N].settings" + + // TODO: If the builder knew what the current command name was, + // then we could also search for task configuration under + // command-specific keys such as "command.{$commandname}.task.{$taskClass}.settings". + } + + /** + * When we run the collection builder, run everything in the collection. + * + * @return \Robo\Result + */ + public function run() + { + $this->startTimer(); + $result = $this->runTasks(); + $this->stopTimer(); + $result['time'] = $this->getExecutionTime(); + $result->mergeData($this->getState()->getData()); + return $result; + } + + /** + * If there is a single task, run it; if there is a collection, run + * all of its tasks. + * + * @return \Robo\Result + */ + protected function runTasks() + { + if (!$this->collection && $this->currentTask) { + $result = $this->currentTask->run(); + return Result::ensureResult($this->currentTask, $result); + } + return $this->getCollection()->run(); + } + + /** + * @return string + */ + public function getCommand() + { + if (!$this->collection && $this->currentTask) { + $task = $this->currentTask; + $task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + if ($task instanceof CommandInterface) { + return $task->getCommand(); + } + } + + return $this->getCollection()->getCommand(); + } + + /** + * @return \Robo\Collection\Collection + */ + public function original() + { + return $this->getCollection(); + } + + /** + * Return the collection of tasks associated with this builder. + * + * @return CollectionInterface + */ + public function getCollection() + { + if (!isset($this->collection)) { + $this->collection = new Collection(); + $this->collection->inflect($this); + $this->collection->setState($this->getState()); + $this->collection->setProgressBarAutoDisplayInterval($this->getConfig()->get(Config::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL)); + + if (isset($this->currentTask)) { + $this->collection->add($this->currentTask); + } + } + return $this->collection; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionInterface.php new file mode 100644 index 00000000..173ca169 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CollectionInterface.php @@ -0,0 +1,151 @@ +run(); + } catch (\Exception $e) { + return Result::fromException($result, $e); + } + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CompletionWrapper.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CompletionWrapper.php new file mode 100644 index 00000000..3e81bd91 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/CompletionWrapper.php @@ -0,0 +1,106 @@ +collection = $collection; + $this->task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + $this->rollbackTask = $rollbackTask; + } + + /** + * {@inheritdoc} + */ + public function original() + { + return $this->task; + } + + /** + * Before running this task, register its rollback and completion + * handlers on its collection. The reason this class exists is to + * defer registration of rollback and completion tasks until 'run()' time. + * + * @return \Robo\Result + */ + public function run() + { + if ($this->rollbackTask) { + $this->collection->registerRollback($this->rollbackTask); + } + if ($this->task instanceof RollbackInterface) { + $this->collection->registerRollback(new CallableTask([$this->task, 'rollback'], $this->task)); + } + if ($this->task instanceof CompletionInterface) { + $this->collection->registerCompletion(new CallableTask([$this->task, 'complete'], $this->task)); + } + + return $this->task->run(); + } + + /** + * Make this wrapper object act like the class it wraps. + * + * @param string $function + * @param array $args + * + * @return mixed + */ + public function __call($function, $args) + { + return call_user_func_array(array($this->task, $function), $args); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Element.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Element.php new file mode 100644 index 00000000..b67b56bb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Element.php @@ -0,0 +1,116 @@ +task = $task; + } + + /** + * @param mixed $before + * @param string $name + */ + public function before($before, $name) + { + if ($name) { + $this->before[$name] = $before; + } else { + $this->before[] = $before; + } + } + + /** + * @param mixed $after + * @param string $name + */ + public function after($after, $name) + { + if ($name) { + $this->after[$name] = $after; + } else { + $this->after[] = $after; + } + } + + /** + * @return array + */ + public function getBefore() + { + return $this->before; + } + + /** + * @return array + */ + public function getAfter() + { + return $this->after; + } + + /** + * @return \Robo\Contract\TaskInterface + */ + public function getTask() + { + return $this->task; + } + + /** + * @return array + */ + public function getTaskList() + { + return array_merge($this->getBefore(), [$this->getTask()], $this->getAfter()); + } + + /** + * @return int + */ + public function progressIndicatorSteps() + { + $steps = 0; + foreach ($this->getTaskList() as $task) { + if ($task instanceof WrappedTaskInterface) { + $task = $task->original(); + } + // If the task is a ProgressIndicatorAwareInterface, then it + // will advance the progress indicator a number of times. + if ($task instanceof ProgressIndicatorAwareInterface) { + $steps += $task->progressIndicatorSteps(); + } + // We also advance the progress indicator once regardless + // of whether it is progress-indicator aware or not. + $steps++; + } + return $steps; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/NestedCollectionInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/NestedCollectionInterface.php new file mode 100644 index 00000000..5e32cf37 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/NestedCollectionInterface.php @@ -0,0 +1,12 @@ +iterable = $iterable; + } + + /** + * @param string $message + * @param array $context + * + * @return $this + */ + public function iterationMessage($message, $context = []) + { + $this->message = $message; + $this->context = $context + ['name' => 'Progress']; + return $this; + } + + /** + * @param int|string $key + * @param mixed $value + */ + protected function showIterationMessage($key, $value) + { + if ($this->message) { + $context = ['key' => $key, 'value' => $value]; + $context += $this->context; + $context += TaskInfo::getTaskContext($this); + $this->printTaskInfo($this->message, $context); + } + } + + /** + * @param callable $fn + * + * @return $this + */ + public function withEachKeyValueCall(callable $fn) + { + $this->functionStack[] = $fn; + return $this; + } + + /** + * @param callable $fn + * + * @return \Robo\Collection\TaskForEach + */ + public function call(callable $fn) + { + return $this->withEachKeyValueCall( + function ($key, $value) use ($fn) { + return call_user_func($fn, $value); + } + ); + } + + /** + * @param callable $fn + * + * @return \Robo\Collection\TaskForEach + */ + public function withBuilder(callable $fn) + { + $this->countingStack[] = + function ($key, $value) use ($fn) { + // Create a new builder for every iteration + $builder = $this->collectionBuilder(); + // The user function should build task operations using + // the $key / $value parameters; we will call run() on + // the builder thus constructed. + call_user_func($fn, $builder, $key, $value); + return $builder->getCollection()->progressIndicatorSteps(); + }; + return $this->withEachKeyValueCall( + function ($key, $value) use ($fn) { + // Create a new builder for every iteration + $builder = $this->collectionBuilder() + ->setParentCollection($this->parentCollection); + // The user function should build task operations using + // the $key / $value parameters; we will call run() on + // the builder thus constructed. + call_user_func($fn, $builder, $key, $value); + return $builder->run(); + } + ); + } + + /** + * {@inheritdoc} + */ + public function setParentCollection(NestedCollectionInterface $parentCollection) + { + $this->parentCollection = $parentCollection; + return $this; + } + + /** + * {@inheritdoc} + */ + public function progressIndicatorSteps() + { + $multiplier = count($this->functionStack); + if (!empty($this->countingStack)) { + $value = reset($this->iterable); + $key = key($this->iterable); + foreach ($this->countingStack as $fn) { + $multiplier += call_user_func($fn, $key, $value); + } + } + return count($this->iterable) * $multiplier; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $finalResult = Result::success($this); + $this->startProgressIndicator(); + foreach ($this->iterable as $key => $value) { + $this->showIterationMessage($key, $value); + try { + foreach ($this->functionStack as $fn) { + $result = call_user_func($fn, $key, $value); + $this->advanceProgressIndicator(); + if (!isset($result)) { + $result = Result::success($this); + } + // If the function returns a result, it must either return + // a \Robo\Result or an exit code. In the later case, we + // convert it to a \Robo\Result. + if (!$result instanceof Result) { + $result = new Result($this, $result); + } + if (!$result->wasSuccessful()) { + return $result; + } + $finalResult = $result->merge($finalResult); + } + } catch (\Exception $e) { + return Result::fromException($result, $e); + } + } + $this->stopProgressIndicator(); + return $finalResult; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Temporary.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Temporary.php new file mode 100644 index 00000000..dad25e34 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/Temporary.php @@ -0,0 +1,57 @@ +get('collection'); + register_shutdown_function(function () { + static::complete(); + }); + } + + return static::$collection; + } + + /** + * Call the complete method of all of the registered objects. + */ + public static function complete() + { + // Run the collection of tasks. This will also run the + // completion tasks. + $collection = static::getCollection(); + $collection->run(); + // Make sure that our completion functions do not run twice. + $collection->reset(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/loadTasks.php new file mode 100644 index 00000000..03f68823 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Collection/loadTasks.php @@ -0,0 +1,17 @@ +task(TaskForEach::class, $collection); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/BuilderAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/BuilderAwareTrait.php new file mode 100644 index 00000000..915ff008 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/BuilderAwareTrait.php @@ -0,0 +1,45 @@ +builder = $builder; + + return $this; + } + + /** + * @see \Robo\Contract\BuilderAwareInterface::getBuilder() + * + * @return \Robo\Collection\CollectionBuilder + */ + public function getBuilder() + { + return $this->builder; + } + + /** + * @return \Robo\Collection\CollectionBuilder + */ + protected function collectionBuilder() + { + return $this->getBuilder()->newBuilder(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/CommandArguments.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/CommandArguments.php new file mode 100644 index 00000000..12c2e89f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/CommandArguments.php @@ -0,0 +1,130 @@ +args($arg); + } + + /** + * Pass methods parameters as arguments to executable. Argument values + * are automatically escaped. + * + * @param string|string[] $args + * + * @return $this + */ + public function args($args) + { + if (!is_array($args)) { + $args = func_get_args(); + } + $this->arguments .= ' ' . implode(' ', array_map('static::escape', $args)); + return $this; + } + + /** + * Pass the provided string in its raw (as provided) form as an argument to executable. + * + * @param string $arg + * + * @return $this + */ + public function rawArg($arg) + { + $this->arguments .= " $arg"; + + return $this; + } + + /** + * Escape the provided value, unless it contains only alphanumeric + * plus a few other basic characters. + * + * @param string $value + * + * @return string + */ + public static function escape($value) + { + if (preg_match('/^[a-zA-Z0-9\/\.@~_-]+$/', $value)) { + return $value; + } + return ProcessUtils::escapeArgument($value); + } + + /** + * Pass option to executable. Options are prefixed with `--` , value can be provided in second parameter. + * Option values are automatically escaped. + * + * @param string $option + * @param string $value + * @param string $separator + * + * @return $this + */ + public function option($option, $value = null, $separator = ' ') + { + if ($option !== null and strpos($option, '-') !== 0) { + $option = "--$option"; + } + $this->arguments .= null == $option ? '' : " " . $option; + $this->arguments .= null == $value ? '' : $separator . static::escape($value); + return $this; + } + + /** + * Pass multiple options to executable. The associative array contains + * the key:value pairs that become `--key value`, for each item in the array. + * Values are automatically escaped. + */ + public function options(array $options, $separator = ' ') + { + foreach ($options as $option => $value) { + $this->option($option, $value, $separator); + } + return $this; + } + + /** + * Pass an option with multiple values to executable. Value can be a string or array. + * Option values are automatically escaped. + * + * @param string $option + * @param string|array $value + * @param string $separator + * + * @return $this + */ + public function optionList($option, $value = array(), $separator = ' ') + { + if (is_array($value)) { + foreach ($value as $item) { + $this->optionList($option, $item, $separator); + } + } else { + $this->option($option, $value, $separator); + } + + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/CommandReceiver.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/CommandReceiver.php new file mode 100644 index 00000000..03b20fce --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/CommandReceiver.php @@ -0,0 +1,30 @@ +getCommand(); + } else { + throw new TaskException($this, get_class($command) . " does not implement CommandInterface, so can't be passed into this task"); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ConfigAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ConfigAwareTrait.php new file mode 100644 index 00000000..d6d45788 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ConfigAwareTrait.php @@ -0,0 +1,109 @@ +config = $config; + + return $this; + } + + /** + * Get the config management object. + * + * @return ConfigInterface + * + * @see \Robo\Contract\ConfigAwareInterface::getConfig() + */ + public function getConfig() + { + return $this->config; + } + + /** + * Any class that uses ConfigAwareTrait SHOULD override this method + * , and define a prefix for its configuration items. This is usually + * done in a base class. When used, this method should return a string + * that ends with a "."; see BaseTask::configPrefix(). + * + * @return string + */ + protected static function configPrefix() + { + return ''; + } + + protected static function configClassIdentifier($classname) + { + $configIdentifier = strtr($classname, '\\', '.'); + $configIdentifier = preg_replace('#^(.*\.Task\.|\.)#', '', $configIdentifier); + + return $configIdentifier; + } + + protected static function configPostfix() + { + return ''; + } + + /** + * @param string $key + * + * @return string + */ + private static function getClassKey($key) + { + $configPrefix = static::configPrefix(); // task. + $configClass = static::configClassIdentifier(get_called_class()); // PARTIAL_NAMESPACE.CLASSNAME + $configPostFix = static::configPostfix(); // .settings + + return sprintf('%s%s%s.%s', $configPrefix, $configClass, $configPostFix, $key); + } + + /** + * @param string $key + * @param mixed $value + * @param Config|null $config + */ + public static function configure($key, $value, $config = null) + { + if (!$config) { + $config = Robo::config(); + } + $config->setDefault(static::getClassKey($key), $value); + } + + /** + * @param string $key + * @param mixed|null $default + * + * @return mixed|null + */ + protected function getConfigValue($key, $default = null) + { + if (!$this->getConfig()) { + return $default; + } + return $this->getConfig()->get(static::getClassKey($key), $default); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/DynamicParams.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/DynamicParams.php new file mode 100644 index 00000000..28a1d150 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/DynamicParams.php @@ -0,0 +1,45 @@ +$property))) { + $this->$property = !$this->$property; + return $this; + } + + // append item to array + if (is_array($this->$property)) { + if (is_array($args[0])) { + $this->$property = $args[0]; + } else { + array_push($this->$property, $args[0]); + } + return $this; + } + + $this->$property = $args[0]; + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecCommand.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecCommand.php new file mode 100644 index 00000000..c3e6c3af --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecCommand.php @@ -0,0 +1,148 @@ +execTimer)) { + $this->execTimer = new TimeKeeper(); + } + return $this->execTimer; + } + + /** + * Look for a "{$cmd}.phar" in the current working + * directory; return a string to exec it if it is + * found. Otherwise, look for an executable command + * of the same name via findExecutable. + * + * @param string $cmd + * + * @return bool|string + */ + protected function findExecutablePhar($cmd) + { + if (file_exists("{$cmd}.phar")) { + return "php {$cmd}.phar"; + } + return $this->findExecutable($cmd); + } + + /** + * Return the best path to the executable program + * with the provided name. Favor vendor/bin in the + * current project. If not found there, use + * whatever is on the $PATH. + * + * @param string $cmd + * + * @return bool|string + */ + protected function findExecutable($cmd) + { + $pathToCmd = $this->searchForExecutable($cmd); + if ($pathToCmd) { + return $this->useCallOnWindows($pathToCmd); + } + return false; + } + + /** + * @param string $cmd + * + * @return string + */ + private function searchForExecutable($cmd) + { + $projectBin = $this->findProjectBin(); + + $localComposerInstallation = $projectBin . DIRECTORY_SEPARATOR . $cmd; + if (file_exists($localComposerInstallation)) { + return $localComposerInstallation; + } + $finder = new ExecutableFinder(); + return $finder->find($cmd, null, []); + } + + /** + * @return bool|string + */ + protected function findProjectBin() + { + $cwd = getcwd(); + $candidates = [ __DIR__ . '/../../vendor/bin', __DIR__ . '/../../bin', $cwd . '/vendor/bin' ]; + + // If this project is inside a vendor directory, give highest priority + // to that directory. + $vendorDirContainingUs = realpath(__DIR__ . '/../../../..'); + if (is_dir($vendorDirContainingUs) && (basename($vendorDirContainingUs) == 'vendor')) { + array_unshift($candidates, $vendorDirContainingUs . '/bin'); + } + + foreach ($candidates as $dir) { + if (is_dir("$dir")) { + return realpath($dir); + } + } + return false; + } + + /** + * Wrap Windows executables in 'call' per 7a88757d + * + * @param string $cmd + * + * @return string + */ + protected function useCallOnWindows($cmd) + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + if (file_exists("{$cmd}.bat")) { + $cmd = "{$cmd}.bat"; + } + return "call $cmd"; + } + return $cmd; + } + + protected function getCommandDescription() + { + return $this->process->getCommandLine(); + } + + /** + * @param string $command + * + * @return \Robo\Result + */ + protected function executeCommand($command) + { + // TODO: Symfony 4 requires that we supply the working directory. + $result_data = $this->execute(new Process($command, getcwd())); + return new Result( + $this, + $result_data->getExitCode(), + $result_data->getMessage(), + $result_data->getData() + ); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecOneCommand.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecOneCommand.php new file mode 100644 index 00000000..60137514 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ExecOneCommand.php @@ -0,0 +1,12 @@ +interactive() based on posix_isatty(). + * + * @return $this + */ + public function detectInteractive() + { + // If the caller did not explicity set the 'interactive' mode, + // and output should be produced by this task (verbosityMeetsThreshold), + // then we will automatically set interactive mode based on whether + // or not output was redirected when robo was executed. + if (!isset($this->interactive) && function_exists('posix_isatty') && $this->verbosityMeetsThreshold()) { + $this->interactive = posix_isatty(STDOUT); + } + + return $this; + } + + /** + * Executes command in background mode (asynchronously) + * + * @return $this + */ + public function background($arg = true) + { + $this->background = $arg; + return $this; + } + + /** + * Stop command if it runs longer then $timeout in seconds + * + * @param int $timeout + * + * @return $this + */ + public function timeout($timeout) + { + $this->timeout = $timeout; + return $this; + } + + /** + * Stops command if it does not output something for a while + * + * @param int $timeout + * + * @return $this + */ + public function idleTimeout($timeout) + { + $this->idleTimeout = $timeout; + return $this; + } + + /** + * Set a single environment variable, or multiple. + */ + public function env($env, $value = null) + { + if (!is_array($env)) { + $env = [$env => ($value ? $value : true)]; + } + return $this->envVars($env); + } + + /** + * Sets the environment variables for the command + * + * @param array $env + * + * @return $this + */ + public function envVars(array $env) + { + $this->env = $env; + return $this; + } + + /** + * Pass an input to the process. Can be resource created with fopen() or string + * + * @param resource|string $input + * + * @return $this + */ + public function setInput($input) + { + $this->input = $input; + return $this; + } + + /** + * Attach tty to process for interactive input + * + * @param $interactive bool + * + * @return $this + */ + public function interactive($interactive = true) + { + $this->interactive = $interactive; + return $this; + } + + + /** + * Is command printing its output to screen + * + * @return bool + */ + public function getPrinted() + { + return $this->isPrinted; + } + + /** + * Changes working directory of command + * + * @param string $dir + * + * @return $this + */ + public function dir($dir) + { + $this->workingDirectory = $dir; + return $this; + } + + /** + * Shortcut for setting isPrinted() and isMetadataPrinted() to false. + * + * @param bool $arg + * + * @return $this + */ + public function silent($arg) + { + if (is_bool($arg)) { + $this->isPrinted = !$arg; + $this->isMetadataPrinted = !$arg; + } + return $this; + } + + /** + * Should command output be printed + * + * @param bool $arg + * + * @return $this + * + * @deprecated + */ + public function printed($arg) + { + $this->logger->warning("printed() is deprecated. Please use printOutput()."); + return $this->printOutput($arg); + } + + /** + * Should command output be printed + * + * @param bool $arg + * + * @return $this + */ + public function printOutput($arg) + { + if (is_bool($arg)) { + $this->isPrinted = $arg; + } + return $this; + } + + /** + * Should command metadata be printed. I,e., command and timer. + * + * @param bool $arg + * + * @return $this + */ + public function printMetadata($arg) + { + if (is_bool($arg)) { + $this->isMetadataPrinted = $arg; + } + return $this; + } + + /** + * @param Process $process + * @param callable $output_callback + * + * @return \Robo\ResultData + */ + protected function execute($process, $output_callback = null) + { + $this->process = $process; + + if (!$output_callback) { + $output_callback = function ($type, $buffer) { + $progressWasVisible = $this->hideTaskProgress(); + $this->writeMessage($buffer); + $this->showTaskProgress($progressWasVisible); + }; + } + + $this->detectInteractive(); + + if ($this->isMetadataPrinted) { + $this->printAction(); + } + $this->process->setTimeout($this->timeout); + $this->process->setIdleTimeout($this->idleTimeout); + if ($this->workingDirectory) { + $this->process->setWorkingDirectory($this->workingDirectory); + } + if ($this->input) { + $this->process->setInput($this->input); + } + + if ($this->interactive && $this->isPrinted) { + $this->process->setTty(true); + } + + if (isset($this->env)) { + $this->process->setEnv($this->env); + } + + if (!$this->background && !$this->isPrinted) { + $this->startTimer(); + $this->process->run(); + $this->stopTimer(); + $output = rtrim($this->process->getOutput()); + return new ResultData( + $this->process->getExitCode(), + $output, + $this->getResultData() + ); + } + + if (!$this->background && $this->isPrinted) { + $this->startTimer(); + $this->process->run($output_callback); + $this->stopTimer(); + return new ResultData( + $this->process->getExitCode(), + $this->process->getOutput(), + $this->getResultData() + ); + } + + try { + $this->process->start(); + } catch (\Exception $e) { + return new ResultData( + $this->process->getExitCode(), + $e->getMessage(), + $this->getResultData() + ); + } + return new ResultData($this->process->getExitCode()); + } + + /** + * + */ + protected function stop() + { + if ($this->background && isset($this->process) && $this->process->isRunning()) { + $this->process->stop(); + $this->printTaskInfo( + "Stopped {command}", + ['command' => $this->getCommandDescription()] + ); + } + } + + /** + * @param array $context + */ + protected function printAction($context = []) + { + $command = $this->getCommandDescription(); + $formatted_command = $this->formatCommandDisplay($command); + + $dir = $this->workingDirectory ? " in {dir}" : ""; + $this->printTaskInfo("Running {command}$dir", [ + 'command' => $formatted_command, + 'dir' => $this->workingDirectory + ] + $context); + } + + /** + * @param $command + * + * @return mixed + */ + protected function formatCommandDisplay($command) + { + $formatted_command = str_replace("&&", "&&\n", $command); + $formatted_command = str_replace("||", "||\n", $formatted_command); + + return $formatted_command; + } + + /** + * Gets the data array to be passed to Result(). + * + * @return array + * The data array passed to Result(). + */ + protected function getResultData() + { + if ($this->isMetadataPrinted) { + return ['time' => $this->getExecutionTime()]; + } + + return []; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/IO.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/IO.php new file mode 100644 index 00000000..d6c77bff --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/IO.php @@ -0,0 +1,171 @@ +io) { + $this->io = new SymfonyStyle($this->input(), $this->output()); + } + return $this->io; + } + + /** + * @param string $nonDecorated + * @param string $decorated + * + * @return string + */ + protected function decorationCharacter($nonDecorated, $decorated) + { + if (!$this->output()->isDecorated() || (strncasecmp(PHP_OS, 'WIN', 3) == 0)) { + return $nonDecorated; + } + return $decorated; + } + + /** + * @param string $text + */ + protected function say($text) + { + $char = $this->decorationCharacter('>', 'âžœ'); + $this->writeln("$char $text"); + } + + /** + * @param string $text + * @param int $length + * @param string $color + */ + protected function yell($text, $length = 40, $color = 'green') + { + $char = $this->decorationCharacter(' ', 'âžœ'); + $format = "$char %s"; + $this->formattedOutput($text, $length, $format); + } + + /** + * @param string $text + * @param int $length + * @param string $format + */ + protected function formattedOutput($text, $length, $format) + { + $lines = explode("\n", trim($text, "\n")); + $maxLineLength = array_reduce(array_map('strlen', $lines), 'max'); + $length = max($length, $maxLineLength); + $len = $length + 2; + $space = str_repeat(' ', $len); + $this->writeln(sprintf($format, $space)); + foreach ($lines as $line) { + $line = str_pad($line, $length, ' ', STR_PAD_BOTH); + $this->writeln(sprintf($format, " $line ")); + } + $this->writeln(sprintf($format, $space)); + } + + /** + * @param string $question + * @param bool $hideAnswer + * + * @return string + */ + protected function ask($question, $hideAnswer = false) + { + if ($hideAnswer) { + return $this->askHidden($question); + } + return $this->doAsk(new Question($this->formatQuestion($question))); + } + + /** + * @param string $question + * + * @return string + */ + protected function askHidden($question) + { + $question = new Question($this->formatQuestion($question)); + $question->setHidden(true); + return $this->doAsk($question); + } + + /** + * @param string $question + * @param string $default + * + * @return string + */ + protected function askDefault($question, $default) + { + return $this->doAsk(new Question($this->formatQuestion("$question [$default]"), $default)); + } + + /** + * @param string $question + * + * @return string + */ + protected function confirm($question) + { + return $this->doAsk(new ConfirmationQuestion($this->formatQuestion($question . ' (y/n)'), false)); + } + + /** + * @param \Symfony\Component\Console\Question\Question $question + * + * @return string + */ + protected function doAsk(Question $question) + { + return $this->getDialog()->ask($this->input(), $this->output(), $question); + } + + /** + * @param string $message + * + * @return string + */ + protected function formatQuestion($message) + { + return "? $message "; + } + + /** + * @return \Symfony\Component\Console\Helper\QuestionHelper + */ + protected function getDialog() + { + return new QuestionHelper(); + } + + /** + * @param $text + */ + protected function writeln($text) + { + $this->output()->writeln($text); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/InflectionTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/InflectionTrait.php new file mode 100644 index 00000000..8bc4e831 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/InflectionTrait.php @@ -0,0 +1,21 @@ +injectDependencies($this); + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/InputAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/InputAwareTrait.php new file mode 100644 index 00000000..bae58c17 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/InputAwareTrait.php @@ -0,0 +1,51 @@ +input = $input; + + return $this; + } + + /** + * @return \Symfony\Component\Console\Input\InputInterface + */ + protected function input() + { + if (!isset($this->input)) { + $this->setInput(new ArgvInput()); + } + return $this->input; + } + + /** + * Backwards compatibility. + * + * @return \Symfony\Component\Console\Input\InputInterface + * + * @deprecated + */ + protected function getInput() + { + return $this->input(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/OutputAdapter.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/OutputAdapter.php new file mode 100644 index 00000000..b8e795f2 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/OutputAdapter.php @@ -0,0 +1,38 @@ + OutputInterface::VERBOSITY_NORMAL, + VerbosityThresholdInterface::VERBOSITY_VERBOSE => OutputInterface::VERBOSITY_VERBOSE, + VerbosityThresholdInterface::VERBOSITY_VERY_VERBOSE => OutputInterface::VERBOSITY_VERY_VERBOSE, + VerbosityThresholdInterface::VERBOSITY_DEBUG => OutputInterface::VERBOSITY_DEBUG, + ]; + + public function verbosityMeetsThreshold($verbosityThreshold) + { + if (!isset($this->verbosityMap[$verbosityThreshold])) { + return true; + } + $verbosityThreshold = $this->verbosityMap[$verbosityThreshold]; + $verbosity = $this->output()->getVerbosity(); + + return $verbosity >= $verbosityThreshold; + } + + public function writeMessage($message) + { + $this->output()->write($message); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/OutputAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/OutputAwareTrait.php new file mode 100644 index 00000000..48082cb3 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/OutputAwareTrait.php @@ -0,0 +1,51 @@ +output = $output; + + return $this; + } + + /** + * @return \Symfony\Component\Console\Output\OutputInterface + */ + protected function output() + { + if (!isset($this->output)) { + $this->setOutput(new NullOutput()); + } + return $this->output; + } + + /** + * Backwards compatibility + * + * @return \Symfony\Component\Console\Output\OutputInterface + * + * @deprecated + */ + protected function getOutput() + { + return $this->output(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProcessExecutor.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProcessExecutor.php new file mode 100644 index 00000000..f78a4775 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProcessExecutor.php @@ -0,0 +1,51 @@ +process = $process; + } + + public static function create($container, $process) + { + $processExecutor = new self($process); + + $processExecutor->setLogger($container->get('logger')); + $processExecutor->setProgressIndicator($container->get('progressIndicator')); + $processExecutor->setConfig($container->get('config')); + $processExecutor->setOutputAdapter($container->get('outputAdapter')); + + return $processExecutor; + } + + /** + * @return string + */ + protected function getCommandDescription() + { + return $this->process->getCommandLine(); + } + + public function run() + { + return $this->execute($this->process); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProcessUtils.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProcessUtils.php new file mode 100644 index 00000000..7dc4e553 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProcessUtils.php @@ -0,0 +1,79 @@ + + */ + +namespace Robo\Common; + +use Symfony\Component\Process\Exception\InvalidArgumentException; + +/** + * ProcessUtils is a bunch of utility methods. We want to allow Robo 1.x + * to work with Symfony 4.x while remaining backwards compatibility. This + * requires us to replace some deprecated functionality removed in Symfony. + */ +class ProcessUtils +{ + /** + * This class should not be instantiated. + */ + private function __construct() + { + } + + /** + * Escapes a string to be used as a shell argument. + * + * @param string $argument The argument that will be escaped + * + * @return string The escaped argument + * + * @deprecated since version 3.3, to be removed in 4.0. Use a command line array or give env vars to the `Process::start/run()` method instead. + */ + public static function escapeArgument($argument) + { + @trigger_error('The '.__METHOD__.'() method is a copy of a method that was deprecated by Symfony 3.3 and removed in Symfony 4; it will be removed in Robo 2.0.', E_USER_DEPRECATED); + + //Fix for PHP bug #43784 escapeshellarg removes % from given string + //Fix for PHP bug #49446 escapeshellarg doesn't work on Windows + //@see https://bugs.php.net/bug.php?id=43784 + //@see https://bugs.php.net/bug.php?id=49446 + if ('\\' === DIRECTORY_SEPARATOR) { + if ('' === $argument) { + return escapeshellarg($argument); + } + + $escapedArgument = ''; + $quote = false; + foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) { + if ('"' === $part) { + $escapedArgument .= '\\"'; + } elseif (self::isSurroundedBy($part, '%')) { + // Avoid environment variable expansion + $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%'; + } else { + // escape trailing backslash + if ('\\' === substr($part, -1)) { + $part .= '\\'; + } + $quote = true; + $escapedArgument .= $part; + } + } + if ($quote) { + $escapedArgument = '"'.$escapedArgument.'"'; + } + + return $escapedArgument; + } + + return "'".str_replace("'", "'\\''", $argument)."'"; + } + + private static function isSurroundedBy($arg, $char) + { + return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1]; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProgressIndicator.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProgressIndicator.php new file mode 100644 index 00000000..050250e5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProgressIndicator.php @@ -0,0 +1,201 @@ +progressBar = $progressBar; + $this->output = $output; + } + + /** + * @param int $interval + */ + public function setProgressBarAutoDisplayInterval($interval) + { + if ($this->progressIndicatorRunning) { + return; + } + $this->autoDisplayInterval = $interval; + } + + /** + * @return bool + */ + public function hideProgressIndicator() + { + $result = $this->progressBarDisplayed; + if ($this->progressIndicatorRunning && $this->progressBarDisplayed) { + $this->progressBar->clear(); + // Hack: progress indicator does not reset cursor to beginning of line on 'clear' + $this->output->write("\x0D"); + $this->progressBarDisplayed = false; + } + return $result; + } + + public function showProgressIndicator() + { + if ($this->progressIndicatorRunning && !$this->progressBarDisplayed && isset($this->progressBar)) { + $this->progressBar->display(); + $this->progressBarDisplayed = true; + $this->advanceProgressIndicatorCachedSteps(); + } + } + + /** + * @param bool $visible + */ + public function restoreProgressIndicator($visible) + { + if ($visible) { + $this->showProgressIndicator(); + } + } + + /** + * @param int $totalSteps + * @param \Robo\Contract\TaskInterface $owner + */ + public function startProgressIndicator($totalSteps, $owner) + { + if (!isset($this->progressBar)) { + return; + } + + $this->progressIndicatorRunning = true; + if (!isset($this->owner)) { + $this->owner = $owner; + $this->startTimer(); + $this->totalSteps = $totalSteps; + $this->autoShowProgressIndicator(); + } + } + + public function autoShowProgressIndicator() + { + if (($this->autoDisplayInterval < 0) || !isset($this->progressBar) || !$this->output->isDecorated()) { + return; + } + if ($this->autoDisplayInterval <= $this->getExecutionTime()) { + $this->autoDisplayInterval = -1; + $this->progressBar->start($this->totalSteps); + $this->showProgressIndicator(); + } + } + + /** + * @return bool + */ + public function inProgress() + { + return $this->progressIndicatorRunning; + } + + /** + * @param \Robo\Contract\TaskInterface $owner + */ + public function stopProgressIndicator($owner) + { + if ($this->progressIndicatorRunning && ($this->owner === $owner)) { + $this->cleanup(); + } + } + + protected function cleanup() + { + $this->progressIndicatorRunning = false; + $this->owner = null; + if ($this->progressBarDisplayed) { + $this->progressBar->finish(); + // Hack: progress indicator does not always finish cleanly + $this->output->writeln(''); + $this->progressBarDisplayed = false; + } + $this->stopTimer(); + } + + /** + * Erase progress indicator and ensure it never returns. Used + * only during error handlers. + */ + public function disableProgressIndicator() + { + $this->cleanup(); + // ProgressIndicator is shared, so this permanently removes + // the program's ability to display progress bars. + $this->progressBar = null; + } + + /** + * @param int $steps + */ + public function advanceProgressIndicator($steps = 1) + { + $this->cachedSteps += $steps; + if ($this->progressIndicatorRunning) { + $this->autoShowProgressIndicator(); + // We only want to call `advance` if the progress bar is visible, + // because it always displays itself when it is advanced. + if ($this->progressBarDisplayed) { + return $this->advanceProgressIndicatorCachedSteps(); + } + } + } + + protected function advanceProgressIndicatorCachedSteps() + { + $this->progressBar->advance($this->cachedSteps); + $this->cachedSteps = 0; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProgressIndicatorAwareTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProgressIndicatorAwareTrait.php new file mode 100644 index 00000000..060e039a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ProgressIndicatorAwareTrait.php @@ -0,0 +1,135 @@ +progressIndicator = $progressIndicator; + + return $this; + } + + /** + * @return null|bool + */ + protected function hideProgressIndicator() + { + if (!$this->progressIndicator) { + return; + } + return $this->progressIndicator->hideProgressIndicator(); + } + + protected function showProgressIndicator() + { + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->showProgressIndicator(); + } + + /** + * @param bool $visible + */ + protected function restoreProgressIndicator($visible) + { + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->restoreProgressIndicator($visible); + } + + /** + * @return int + */ + protected function getTotalExecutionTime() + { + if (!$this->progressIndicator) { + return 0; + } + return $this->progressIndicator->getExecutionTime(); + } + + protected function startProgressIndicator() + { + $this->startTimer(); + if ($this instanceof VerbosityThresholdInterface + && !$this->verbosityMeetsThreshold()) { + return; + } + if (!$this->progressIndicator) { + return; + } + $totalSteps = $this->progressIndicatorSteps(); + $this->progressIndicator->startProgressIndicator($totalSteps, $this); + } + + /** + * @return bool + */ + protected function inProgress() + { + if (!$this->progressIndicator) { + return false; + } + return $this->progressIndicator->inProgress(); + } + + protected function stopProgressIndicator() + { + $this->stopTimer(); + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->stopProgressIndicator($this); + } + + protected function disableProgressIndicator() + { + $this->stopTimer(); + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->disableProgressIndicator(); + } + + protected function detatchProgressIndicator() + { + $this->setProgressIndicator(null); + } + + /** + * @param int $steps + */ + protected function advanceProgressIndicator($steps = 1) + { + if (!$this->progressIndicator) { + return; + } + $this->progressIndicator->advanceProgressIndicator($steps); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ResourceExistenceChecker.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ResourceExistenceChecker.php new file mode 100644 index 00000000..233f90a9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/ResourceExistenceChecker.php @@ -0,0 +1,116 @@ +printTaskError(sprintf('Invalid glob "%s"!', $resource), $this); + $success = false; + continue; + } + foreach ($glob as $resource) { + if (!$this->checkResource($resource, $type)) { + $success = false; + } + } + } + return $success; + } + + /** + * Checks a single resource, file or directory. + * + * It will print an error as well on the console. + * + * @param string $resource File or folder. + * @param string $type "file", "dir", "fileAndDir" + * + * @return bool + */ + protected function checkResource($resource, $type) + { + switch ($type) { + case 'file': + if (!$this->isFile($resource)) { + $this->printTaskError(sprintf('File "%s" does not exist!', $resource), $this); + return false; + } + return true; + case 'dir': + if (!$this->isDir($resource)) { + $this->printTaskError(sprintf('Directory "%s" does not exist!', $resource), $this); + return false; + } + return true; + case 'fileAndDir': + if (!$this->isDir($resource) && !$this->isFile($resource)) { + $this->printTaskError(sprintf('File or directory "%s" does not exist!', $resource), $this); + return false; + } + return true; + } + } + + /** + * Convenience method to check the often uses "source => target" file / folder arrays. + * + * @param string|array $resources + */ + protected function checkSourceAndTargetResource($resources) + { + if (is_string($resources)) { + $resources = [$resources]; + } + $sources = []; + $targets = []; + foreach ($resources as $source => $target) { + $sources[] = $source; + $target[] = $target; + } + $this->checkResources($sources); + $this->checkResources($targets); + } + + /** + * Wrapper method around phps is_dir() + * + * @param string $directory + * + * @return bool + */ + protected function isDir($directory) + { + return is_dir($directory); + } + + /** + * Wrapper method around phps file_exists() + * + * @param string $file + * + * @return bool + */ + protected function isFile($file) + { + return file_exists($file); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/TaskIO.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/TaskIO.php new file mode 100644 index 00000000..49b5ccd8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/TaskIO.php @@ -0,0 +1,237 @@ +logger should always be set in Robo core tasks. + if ($this->logger) { + return $this->logger; + } + + // TODO: Remove call to Robo::logger() once maintaining backwards + // compatibility with legacy external Robo tasks is no longer desired. + if (!Robo::logger()) { + return null; + } + + static $gaveDeprecationWarning = false; + if (!$gaveDeprecationWarning) { + trigger_error('No logger set for ' . get_class($this) . '. Use $this->task(Foo::class) rather than new Foo() in loadTasks to ensure the builder can initialize task the task, or use $this->collectionBuilder()->taskFoo() if creating one task from within another.', E_USER_DEPRECATED); + $gaveDeprecationWarning = true; + } + return Robo::logger(); + } + + /** + * Print information about a task in progress. + * + * With the Symfony Console logger, NOTICE is displayed at VERBOSITY_VERBOSE + * and INFO is displayed at VERBOSITY_VERY_VERBOSE. + * + * Robo overrides the default such that NOTICE is displayed at + * VERBOSITY_NORMAL and INFO is displayed at VERBOSITY_VERBOSE. + * + * n.b. We should probably have printTaskNotice for our ordinary + * output, and use printTaskInfo for less interesting messages. + * + * @param string $text + * @param null|array $context + */ + protected function printTaskInfo($text, $context = null) + { + // The 'note' style is used for both 'notice' and 'info' log levels; + // However, 'notice' is printed at VERBOSITY_NORMAL, whereas 'info' + // is only printed at VERBOSITY_VERBOSE. + $this->printTaskOutput(LogLevel::NOTICE, $text, $this->getTaskContext($context)); + } + + /** + * Provide notification that some part of the task succeeded. + * + * With the Symfony Console logger, success messages are remapped to NOTICE, + * and displayed in VERBOSITY_VERBOSE. When used with the Robo logger, + * success messages are displayed at VERBOSITY_NORMAL. + * + * @param string $text + * @param null|array $context + */ + protected function printTaskSuccess($text, $context = null) + { + // Not all loggers will recognize ConsoleLogLevel::SUCCESS. + // We therefore log as LogLevel::NOTICE, and apply a '_level' + // override in the context so that this message will be + // logged as SUCCESS if that log level is recognized. + $context['_level'] = ConsoleLogLevel::SUCCESS; + $this->printTaskOutput(LogLevel::NOTICE, $text, $this->getTaskContext($context)); + } + + /** + * Provide notification that there is something wrong, but + * execution can continue. + * + * Warning messages are displayed at VERBOSITY_NORMAL. + * + * @param string $text + * @param null|array $context + */ + protected function printTaskWarning($text, $context = null) + { + $this->printTaskOutput(LogLevel::WARNING, $text, $this->getTaskContext($context)); + } + + /** + * Provide notification that some operation in the task failed, + * and the task cannot continue. + * + * Error messages are displayed at VERBOSITY_NORMAL. + * + * @param string $text + * @param null|array $context + */ + protected function printTaskError($text, $context = null) + { + $this->printTaskOutput(LogLevel::ERROR, $text, $this->getTaskContext($context)); + } + + /** + * Provide debugging notification. These messages are only + * displayed if the log level is VERBOSITY_DEBUG. + * + * @param string$text + * @param null|array $context + */ + protected function printTaskDebug($text, $context = null) + { + $this->printTaskOutput(LogLevel::DEBUG, $text, $this->getTaskContext($context)); + } + + /** + * @param string $level + * One of the \Psr\Log\LogLevel constant + * @param string $text + * @param null|array $context + */ + protected function printTaskOutput($level, $text, $context) + { + if (!$this->verbosityMeetsThreshold()) { + return; + } + $logger = $this->logger(); + if (!$logger) { + return; + } + // Hide the progress indicator, if it is visible. + $inProgress = $this->hideTaskProgress(); + $logger->log($level, $text, $this->getTaskContext($context)); + // After we have printed our log message, redraw the progress indicator. + $this->showTaskProgress($inProgress); + } + + /** + * @return bool + */ + protected function hideTaskProgress() + { + $inProgress = false; + if ($this instanceof ProgressIndicatorAwareInterface) { + $inProgress = $this->inProgress(); + } + + // If a progress indicator is running on this task, then we mush + // hide it before we print anything, or its display will be overwritten. + if ($inProgress) { + $inProgress = $this->hideProgressIndicator(); + } + return $inProgress; + } + + /** + * @param $inProgress + */ + protected function showTaskProgress($inProgress) + { + if ($inProgress) { + $this->restoreProgressIndicator($inProgress); + } + } + + /** + * Format a quantity of bytes. + * + * @param int $size + * @param int $precision + * + * @return string + */ + protected function formatBytes($size, $precision = 2) + { + if ($size === 0) { + return 0; + } + $base = log($size, 1024); + $suffixes = array('', 'k', 'M', 'G', 'T'); + return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)]; + } + + /** + * Get the formatted task name for use in task output. + * This is placed in the task context under 'name', and + * used as the log label by Robo\Common\RoboLogStyle, + * which is inserted at the head of log messages by + * Robo\Common\CustomLogStyle::formatMessage(). + * + * @param null|object $task + * + * @return string + */ + protected function getPrintedTaskName($task = null) + { + if (!$task) { + $task = $this; + } + return TaskInfo::formatTaskName($task); + } + + /** + * @param null|array $context + * + * @return array with context information + */ + protected function getTaskContext($context = null) + { + if (!$context) { + $context = []; + } + if (!is_array($context)) { + $context = ['task' => $context]; + } + if (!array_key_exists('task', $context)) { + $context['task'] = $this; + } + + return $context + TaskInfo::getTaskContext($context['task']); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/TimeKeeper.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/TimeKeeper.php new file mode 100644 index 00000000..1cd3e334 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/TimeKeeper.php @@ -0,0 +1,69 @@ +startedAt) { + return; + } + // Get time in seconds as a float, accurate to the microsecond. + $this->startedAt = microtime(true); + } + + public function stop() + { + $this->finishedAt = microtime(true); + } + + /** + * @return float|null + */ + public function elapsed() + { + $finished = $this->finishedAt ? $this->finishedAt : microtime(true); + if ($finished - $this->startedAt <= 0) { + return null; + } + return $finished - $this->startedAt; + } + + /** + * Format a duration into a human-readable time + * + * @param float $duration Duration in seconds, with fractional component + * + * @return string + */ + public static function formatDuration($duration) + { + if ($duration >= self::DAY * 2) { + return gmdate('z \d\a\y\s H:i:s', $duration); + } + if ($duration > self::DAY) { + return gmdate('\1 \d\a\y H:i:s', $duration); + } + if ($duration > self::HOUR) { + return gmdate("H:i:s", $duration); + } + if ($duration > self::MINUTE) { + return gmdate("i:s", $duration); + } + return round($duration, 3).'s'; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/Timer.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/Timer.php new file mode 100644 index 00000000..955eb5bb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/Timer.php @@ -0,0 +1,37 @@ +timer)) { + $this->timer = new TimeKeeper(); + } + $this->timer->start(); + } + + protected function stopTimer() + { + if (!isset($this->timer)) { + return; + } + $this->timer->stop(); + } + + /** + * @return float|null + */ + protected function getExecutionTime() + { + if (!isset($this->timer)) { + return null; + } + return $this->timer->elapsed(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/VerbosityThresholdTrait.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/VerbosityThresholdTrait.php new file mode 100644 index 00000000..2fc51c22 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Common/VerbosityThresholdTrait.php @@ -0,0 +1,79 @@ +verbosityThreshold = $verbosityThreshold; + return $this; + } + + public function verbosityThreshold() + { + return $this->verbosityThreshold; + } + + public function setOutputAdapter(OutputAdapterInterface $outputAdapter) + { + $this->outputAdapter = $outputAdapter; + } + + /** + * @return OutputAdapterInterface + */ + public function outputAdapter() + { + return $this->outputAdapter; + } + + public function hasOutputAdapter() + { + return isset($this->outputAdapter); + } + + public function verbosityMeetsThreshold() + { + if ($this->hasOutputAdapter()) { + return $this->outputAdapter()->verbosityMeetsThreshold($this->verbosityThreshold()); + } + return true; + } + + /** + * Print a message if the selected verbosity level is over this task's + * verbosity threshhold. + */ + public function writeMessage($message) + { + if (!$this->verbosityMeetsThreshold()) { + return; + } + $this->outputAdapter()->writeMessage($message); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config.php new file mode 100644 index 00000000..9e9370d8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config.php @@ -0,0 +1,9 @@ +defaults = $this->getGlobalOptionDefaultValues(); + } + + /** + * Return an associative array containing all of the global configuration + * options and their default values. + * + * @return array + */ + public function getGlobalOptionDefaultValues() + { + $globalOptions = + [ + self::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL => self::DEFAULT_PROGRESS_DELAY, + self::SIMULATE => false, + ]; + return $this->trimPrefixFromGlobalOptions($globalOptions); + } + + /** + * Remove the 'options.' prefix from the global options list. + */ + protected function trimPrefixFromGlobalOptions($globalOptions) + { + $result = []; + foreach ($globalOptions as $option => $value) { + $option = str_replace('options.', '', $option); + $result[$option] = $value; + } + return $result; + } + + /** + * @deprecated Use $config->get(Config::SIMULATE) + * + * @return bool + */ + public function isSimulated() + { + return $this->get(self::SIMULATE); + } + + /** + * @deprecated Use $config->set(Config::SIMULATE, true) + * + * @param bool $simulated + * + * @return $this + */ + public function setSimulated($simulated = true) + { + return $this->set(self::SIMULATE, $simulated); + } + + /** + * @deprecated Use $config->get(Config::INTERACTIVE) + * + * @return bool + */ + public function isInteractive() + { + return $this->get(self::INTERACTIVE); + } + + /** + * @deprecated Use $config->set(Config::INTERACTIVE, true) + * + * @param bool $interactive + * + * @return $this + */ + public function setInteractive($interactive = true) + { + return $this->set(self::INTERACTIVE, $interactive); + } + + /** + * @deprecated Use $config->get(Config::DECORATED) + * + * @return bool + */ + public function isDecorated() + { + return $this->get(self::DECORATED); + } + + /** + * @deprecated Use $config->set(Config::DECORATED, true) + * + * @param bool $decorated + * + * @return $this + */ + public function setDecorated($decorated = true) + { + return $this->set(self::DECORATED, $decorated); + } + + /** + * @deprecated Use $config->set(Config::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL, $interval) + * + * @param int $interval + * + * @return $this + */ + public function setProgressBarAutoDisplayInterval($interval) + { + return $this->set(self::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL, $interval); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config/GlobalOptionDefaultValuesInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config/GlobalOptionDefaultValuesInterface.php new file mode 100644 index 00000000..f7639455 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Config/GlobalOptionDefaultValuesInterface.php @@ -0,0 +1,17 @@ +inflect($this) + * ->initializer() + * ->... + * + * Instead of: + * + * (new SomeTask($args)) + * ->setLogger($this->logger) + * ->initializer() + * ->... + * + * The reason `inflect` is better than the more explicit alternative is + * that subclasses of BaseTask that implement a new FooAwareInterface + * can override injectDependencies() as explained below, and add more + * dependencies that can be injected as needed. + * + * @param \Robo\Contract\InflectionInterface $parent + */ + public function inflect(InflectionInterface $parent); + + /** + * Take all dependencies availble to this task and inject any that are + * needed into the provided task. The general pattern is that, for every + * FooAwareInterface that this class implements, it should test to see + * if the child also implements the same interface, and if so, should call + * $child->setFoo($this->foo). + * + * The benefits of this are pretty large. Any time an object that implements + * InflectionInterface is created, just call `$child->inflect($this)`, and + * any available optional dependencies will be hooked up via setter injection. + * + * The required dependencies of an object should be provided via constructor + * injection, not inflection. + * + * @param InflectionInterface $child An object created by this class that + * should have its dependencies injected. + * + * @see https://mwop.net/blog/2016-04-26-on-locators.html + */ + public function injectDependencies(InflectionInterface $child); +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/OutputAdapterInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/OutputAdapterInterface.php new file mode 100644 index 00000000..948d384c --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Contract/OutputAdapterInterface.php @@ -0,0 +1,11 @@ +prefix = 'options'; + } + + /** + * Add a reference to the Symfony Console application object. + */ + public function setApplication($application) + { + $this->application = $application; + return $this; + } + + /** + * Stipulate the prefix to use for option injection. + * @param string $prefix + */ + public function setGlobalOptionsPrefix($prefix) + { + $this->prefix = $prefix; + return $this; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ConsoleEvents::COMMAND => 'handleCommandEvent']; + } + + /** + * Run all of our individual operations when a command event is received. + */ + public function handleCommandEvent(ConsoleCommandEvent $event) + { + $this->setGlobalOptions($event); + $this->setConfigurationValues($event); + } + + /** + * Before a Console command runs, examine the global + * commandline options from the event Input, and set + * configuration values as appropriate. + * + * @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event + */ + public function setGlobalOptions(ConsoleCommandEvent $event) + { + $config = $this->getConfig(); + $input = $event->getInput(); + + $globalOptions = $config->get($this->prefix, []); + if ($config instanceof \Consolidation\Config\GlobalOptionDefaultValuesInterface) { + $globalOptions += $config->getGlobalOptionDefaultValues(); + } + + $globalOptions += $this->applicationOptionDefaultValues(); + + // Set any config value that has a defined global option (e.g. --simulate) + foreach ($globalOptions as $option => $default) { + $value = $input->hasOption($option) ? $input->getOption($option) : null; + // Unfortunately, the `?:` operator does not differentate between `0` and `null` + if (!isset($value)) { + $value = $default; + } + $config->set($this->prefix . '.' . $option, $value); + } + } + + /** + * Examine the commandline --define / -D options, and apply the provided + * values to the active configuration. + * + * @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event + */ + public function setConfigurationValues(ConsoleCommandEvent $event) + { + $config = $this->getConfig(); + $input = $event->getInput(); + + // Also set any `-D config.key=value` options from the commandline. + if ($input->hasOption('define')) { + $configDefinitions = $input->getOption('define'); + foreach ($configDefinitions as $value) { + list($key, $value) = $this->splitConfigKeyValue($value); + $config->set($key, $value); + } + } + } + + /** + * Split up the key=value config setting into its component parts. If + * the input string contains no '=' character, then the value will be 'true'. + * + * @param string $value + * @return array + */ + protected function splitConfigKeyValue($value) + { + $parts = explode('=', $value, 2); + $parts[] = true; + return $parts; + } + + /** + * Get default option values from the Symfony Console application, if + * it is available. + */ + protected function applicationOptionDefaultValues() + { + if (!$this->application) { + return []; + } + + $result = []; + foreach ($this->application->getDefinition()->getOptions() as $key => $option) { + $result[$key] = $option->acceptValue() ? $option->getDefault() : null; + } + return $result; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/LoadAllTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/LoadAllTasks.php new file mode 100644 index 00000000..3183d5b6 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/LoadAllTasks.php @@ -0,0 +1,39 @@ +getTask(); + if ($task instanceof VerbosityThresholdInterface && !$task->verbosityMeetsThreshold()) { + return; + } + if (!$result->wasSuccessful()) { + return $this->printError($result); + } else { + return $this->printSuccess($result); + } + } + + /** + * Log that we are about to abort due to an error being encountered + * in 'stop on fail' mode. + * + * @param \Robo\Result $result + */ + public function printStopOnFail($result) + { + $this->printMessage(LogLevel::NOTICE, 'Stopping on fail. Exiting....'); + $this->printMessage(LogLevel::ERROR, 'Exit Code: {code}', ['code' => $result->getExitCode()]); + } + + /** + * Log the result of a Robo task that returned an error. + * + * @param \Robo\Result $result + * + * @return bool + */ + protected function printError(Result $result) + { + $task = $result->getTask(); + $context = $result->getContext() + ['timer-label' => 'Time', '_style' => []]; + $context['_style']['message'] = ''; + + $printOutput = true; + if ($task instanceof PrintedInterface) { + $printOutput = !$task->getPrinted(); + } + if ($printOutput) { + $this->printMessage(LogLevel::ERROR, "{message}", $context); + } + $this->printMessage(LogLevel::ERROR, 'Exit code {code}', $context); + return true; + } + + /** + * Log the result of a Robo task that was successful. + * + * @param \Robo\Result $result + * + * @return bool + */ + protected function printSuccess(Result $result) + { + $task = $result->getTask(); + $context = $result->getContext() + ['timer-label' => 'in']; + $time = $result->getExecutionTime(); + if ($time) { + $this->printMessage(ConsoleLogLevel::SUCCESS, 'Done', $context); + } + return false; + } + + /** + * @param string $level + * @param string $message + * @param array $context + */ + protected function printMessage($level, $message, $context = []) + { + $inProgress = $this->hideProgressIndicator(); + $this->logger->log($level, $message, $context); + if ($inProgress) { + $this->restoreProgressIndicator($inProgress); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogLevel.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogLevel.php new file mode 100644 index 00000000..d7d5eb0a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogLevel.php @@ -0,0 +1,11 @@ +labelStyles += [ + RoboLogLevel::SIMULATED_ACTION => self::TASK_STYLE_SIMULATED, + ]; + $this->messageStyles += [ + RoboLogLevel::SIMULATED_ACTION => '', + ]; + } + + /** + * Log style customization for Robo: replace the log level with + * the task name. + * + * @param string $level + * @param string $message + * @param array $context + * + * @return string + */ + protected function formatMessageByLevel($level, $message, $context) + { + $label = $level; + if (array_key_exists('name', $context)) { + $label = $context['name']; + } + return $this->formatMessage($label, $message, $context, $this->labelStyles[$level], $this->messageStyles[$level]); + } + + /** + * Log style customization for Robo: add the time indicator to the + * end of the log message if it exists in the context. + * + * @param string $label + * @param string $message + * @param array $context + * @param string $taskNameStyle + * @param string $messageStyle + * + * @return string + */ + protected function formatMessage($label, $message, $context, $taskNameStyle, $messageStyle = '') + { + $message = parent::formatMessage($label, $message, $context, $taskNameStyle, $messageStyle); + + if (array_key_exists('time', $context) && !empty($context['time']) && array_key_exists('timer-label', $context)) { + $duration = TimeKeeper::formatDuration($context['time']); + $message .= ' ' . $context['timer-label'] . ' ' . $this->wrapFormatString($duration, 'fg=yellow'); + } + + return $message; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogger.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogger.php new file mode 100644 index 00000000..75cf23f7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Log/RoboLogger.php @@ -0,0 +1,29 @@ + OutputInterface::VERBOSITY_NORMAL, // Default is "verbose" + LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL, // Default is "verbose" + LogLevel::INFO => OutputInterface::VERBOSITY_VERBOSE, // Default is "very verbose" + ]; + parent::__construct($output, $roboVerbosityOverrides); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Result.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Result.php new file mode 100644 index 00000000..7d779352 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Result.php @@ -0,0 +1,258 @@ +task = $task; + $this->printResult(); + + if (self::$stopOnFail) { + $this->stopOnFail(); + } + } + + /** + * Tasks should always return a Result. However, they are also + * allowed to return NULL or an array to indicate success. + */ + public static function ensureResult($task, $result) + { + if ($result instanceof Result) { + return $result; + } + if (!isset($result)) { + return static::success($task); + } + if ($result instanceof Data) { + return static::success($task, $result->getMessage(), $result->getData()); + } + if ($result instanceof ResultData) { + return new Result($task, $result->getExitCode(), $result->getMessage(), $result->getData()); + } + if (is_array($result)) { + return static::success($task, '', $result); + } + throw new \Exception(sprintf('Task %s returned a %s instead of a \Robo\Result.', get_class($task), get_class($result))); + } + + protected function printResult() + { + // For historic reasons, the Result constructor is responsible + // for printing task results. + // TODO: Make IO the responsibility of some other class. Maintaining + // existing behavior for backwards compatibility. This is undesirable + // in the long run, though, as it can result in unwanted repeated input + // in task collections et. al. + $resultPrinter = Robo::resultPrinter(); + if ($resultPrinter) { + if ($resultPrinter->printResult($this)) { + $this->alreadyPrinted(); + } + } + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param string $extension + * @param string $service + * + * @return \Robo\Result + */ + public static function errorMissingExtension(TaskInterface $task, $extension, $service) + { + $messageTpl = 'PHP extension required for %s. Please enable %s'; + $message = sprintf($messageTpl, $service, $extension); + + return self::error($task, $message); + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param string $class + * @param string $package + * + * @return \Robo\Result + */ + public static function errorMissingPackage(TaskInterface $task, $class, $package) + { + $messageTpl = 'Class %s not found. Please install %s Composer package'; + $message = sprintf($messageTpl, $class, $package); + + return self::error($task, $message); + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param string $message + * @param array $data + * + * @return \Robo\Result + */ + public static function error(TaskInterface $task, $message, $data = []) + { + return new self($task, self::EXITCODE_ERROR, $message, $data); + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param \Exception $e + * @param array $data + * + * @return \Robo\Result + */ + public static function fromException(TaskInterface $task, \Exception $e, $data = []) + { + $exitCode = $e->getCode(); + if (!$exitCode) { + $exitCode = self::EXITCODE_ERROR; + } + return new self($task, $exitCode, $e->getMessage(), $data); + } + + /** + * @param \Robo\Contract\TaskInterface $task + * @param string $message + * @param array $data + * + * @return \Robo\Result + */ + public static function success(TaskInterface $task, $message = '', $data = []) + { + return new self($task, self::EXITCODE_OK, $message, $data); + } + + /** + * Return a context useful for logging messages. + * + * @return array + */ + public function getContext() + { + $task = $this->getTask(); + + return TaskInfo::getTaskContext($task) + [ + 'code' => $this->getExitCode(), + 'data' => $this->getArrayCopy(), + 'time' => $this->getExecutionTime(), + 'message' => $this->getMessage(), + ]; + } + + /** + * Add the results from the most recent task to the accumulated + * results from all tasks that have run so far, merging data + * as necessary. + * + * @param int|string $key + * @param \Robo\Result $taskResult + */ + public function accumulate($key, Result $taskResult) + { + // If the task is unnamed, then all of its data elements + // just get merged in at the top-level of the final Result object. + if (static::isUnnamed($key)) { + $this->merge($taskResult); + } elseif (isset($this[$key])) { + // There can only be one task with a given name; however, if + // there are tasks added 'before' or 'after' the named task, + // then the results from these will be stored under the same + // name unless they are given a name of their own when added. + $current = $this[$key]; + $this[$key] = $taskResult->merge($current); + } else { + $this[$key] = $taskResult; + } + } + + /** + * We assume that named values (e.g. for associative array keys) + * are non-numeric; numeric keys are presumed to simply be the + * index of an array, and therefore insignificant. + * + * @param int|string $key + * + * @return bool + */ + public static function isUnnamed($key) + { + return is_numeric($key); + } + + /** + * @return \Robo\Contract\TaskInterface + */ + public function getTask() + { + return $this->task; + } + + /** + * @return \Robo\Contract\TaskInterface + */ + public function cloneTask() + { + $reflect = new \ReflectionClass(get_class($this->task)); + return $reflect->newInstanceArgs(func_get_args()); + } + + /** + * @return bool + * + * @deprecated since 1.0. + * + * @see wasSuccessful() + */ + public function __invoke() + { + trigger_error(__METHOD__ . ' is deprecated: use wasSuccessful() instead.', E_USER_DEPRECATED); + return $this->wasSuccessful(); + } + + /** + * @return $this + */ + public function stopOnFail() + { + if (!$this->wasSuccessful()) { + $resultPrinter = Robo::resultPrinter(); + if ($resultPrinter) { + $resultPrinter->printStopOnFail($this); + } + $this->exitEarly($this->getExitCode()); + } + return $this; + } + + /** + * @param int $status + * + * @throws \Robo\Exception\TaskExitException + */ + private function exitEarly($status) + { + throw new TaskExitException($this->getTask(), $this->getMessage(), $status); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/ResultData.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/ResultData.php new file mode 100644 index 00000000..90baf6e9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/ResultData.php @@ -0,0 +1,110 @@ +exitCode = $exitCode; + parent::__construct($message, $data); + } + + /** + * @param string $message + * @param array $data + * + * @return \Robo\ResultData + */ + public static function message($message, $data = []) + { + return new self(self::EXITCODE_OK, $message, $data); + } + + /** + * @param string $message + * @param array $data + * + * @return \Robo\ResultData + */ + public static function cancelled($message = '', $data = []) + { + return new ResultData(self::EXITCODE_USER_CANCEL, $message, $data); + } + + /** + * @return int + */ + public function getExitCode() + { + return $this->exitCode; + } + + /** + * @return null|string + */ + public function getOutputData() + { + if (!empty($this->message) && !isset($this['already-printed']) && isset($this['provide-outputdata'])) { + return $this->message; + } + } + + /** + * Indicate that the message in this data has already been displayed. + */ + public function alreadyPrinted() + { + $this['already-printed'] = true; + } + + /** + * Opt-in to providing the result message as the output data + */ + public function provideOutputdata() + { + $this['provide-outputdata'] = true; + } + + /** + * @return bool + */ + public function wasSuccessful() + { + return $this->exitCode === self::EXITCODE_OK; + } + + /** + * @return bool + */ + public function wasCancelled() + { + return $this->exitCode == self::EXITCODE_USER_CANCEL; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Robo.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Robo.php new file mode 100644 index 00000000..0f427707 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Robo.php @@ -0,0 +1,394 @@ +setSelfUpdateRepository($repository); + $statusCode = $runner->execute($argv, $appName, $appVersion, $output); + return $statusCode; + } + + /** + * Sets a new global container. + * + * @param ContainerInterface $container + * A new container instance to replace the current. + */ + public static function setContainer(ContainerInterface $container) + { + static::$container = $container; + } + + /** + * Unsets the global container. + */ + public static function unsetContainer() + { + static::$container = null; + } + + /** + * Returns the currently active global container. + * + * @return \League\Container\ContainerInterface + * + * @throws \RuntimeException + */ + public static function getContainer() + { + if (static::$container === null) { + throw new \RuntimeException('container is not initialized yet. \Robo\Robo::setContainer() must be called with a real container.'); + } + return static::$container; + } + + /** + * Returns TRUE if the container has been initialized, FALSE otherwise. + * + * @return bool + */ + public static function hasContainer() + { + return static::$container !== null; + } + + /** + * Create a config object and load it from the provided paths. + */ + public static function createConfiguration($paths) + { + $config = new \Robo\Config\Config(); + static::loadConfiguration($paths, $config); + return $config; + } + + /** + * Use a simple config loader to load configuration values from specified paths + */ + public static function loadConfiguration($paths, $config = null) + { + if ($config == null) { + $config = static::config(); + } + $loader = new YamlConfigLoader(); + $processor = new ConfigProcessor(); + $processor->add($config->export()); + foreach ($paths as $path) { + $processor->extend($loader->load($path)); + } + $config->import($processor->export()); + } + + /** + * Create a container and initiailze it. If you wish to *change* + * anything defined in the container, then you should call + * \Robo::configureContainer() instead of this function. + * + * @param null|\Symfony\Component\Console\Input\InputInterface $input + * @param null|\Symfony\Component\Console\Output\OutputInterface $output + * @param null|\Robo\Application $app + * @param null|ConfigInterface $config + * + * @return \League\Container\Container|\League\Container\ContainerInterface + */ + public static function createDefaultContainer($input = null, $output = null, $app = null, $config = null) + { + // Do not allow this function to be called more than once. + if (static::hasContainer()) { + return static::getContainer(); + } + + if (!$app) { + $app = static::createDefaultApplication(); + } + + if (!$config) { + $config = new \Robo\Config\Config(); + } + + // Set up our dependency injection container. + $container = new Container(); + static::configureContainer($container, $app, $config, $input, $output); + + // Set the application dispatcher + $app->setDispatcher($container->get('eventDispatcher')); + + return $container; + } + + /** + * Initialize a container with all of the default Robo services. + * IMPORTANT: after calling this method, clients MUST call: + * + * $dispatcher = $container->get('eventDispatcher'); + * $app->setDispatcher($dispatcher); + * + * Any modification to the container should be done prior to fetching + * objects from it. + * + * It is recommended to use \Robo::createDefaultContainer() + * instead, which does all required setup for the caller, but has + * the limitation that the container it creates can only be + * extended, not modified. + * + * @param \League\Container\ContainerInterface $container + * @param \Symfony\Component\Console\Application $app + * @param ConfigInterface $config + * @param null|\Symfony\Component\Console\Input\InputInterface $input + * @param null|\Symfony\Component\Console\Output\OutputInterface $output + */ + public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, ConfigInterface $config, $input = null, $output = null) + { + // Self-referential container refernce for the inflector + $container->add('container', $container); + static::setContainer($container); + + // Create default input and output objects if they were not provided + if (!$input) { + $input = new StringInput(''); + } + if (!$output) { + $output = new \Symfony\Component\Console\Output\ConsoleOutput(); + } + $config->set(Config::DECORATED, $output->isDecorated()); + $config->set(Config::INTERACTIVE, $input->isInteractive()); + + $container->share('application', $app); + $container->share('config', $config); + $container->share('input', $input); + $container->share('output', $output); + $container->share('outputAdapter', \Robo\Common\OutputAdapter::class); + + // Register logging and related services. + $container->share('logStyler', \Robo\Log\RoboLogStyle::class); + $container->share('logger', \Robo\Log\RoboLogger::class) + ->withArgument('output') + ->withMethodCall('setLogOutputStyler', ['logStyler']); + $container->add('progressBar', \Symfony\Component\Console\Helper\ProgressBar::class) + ->withArgument('output'); + $container->share('progressIndicator', \Robo\Common\ProgressIndicator::class) + ->withArgument('progressBar') + ->withArgument('output'); + $container->share('resultPrinter', \Robo\Log\ResultPrinter::class); + $container->add('simulator', \Robo\Task\Simulator::class); + $container->share('globalOptionsEventListener', \Robo\GlobalOptionsEventListener::class) + ->withMethodCall('setApplication', ['application']); + $container->share('injectConfigEventListener', \Consolidation\Config\Inject\ConfigForCommand::class) + ->withArgument('config') + ->withMethodCall('setApplication', ['application']); + $container->share('collectionProcessHook', \Robo\Collection\CollectionProcessHook::class); + $container->share('alterOptionsCommandEvent', \Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent::class) + ->withArgument('application'); + $container->share('hookManager', \Consolidation\AnnotatedCommand\Hooks\HookManager::class) + ->withMethodCall('addCommandEvent', ['alterOptionsCommandEvent']) + ->withMethodCall('addCommandEvent', ['injectConfigEventListener']) + ->withMethodCall('addCommandEvent', ['globalOptionsEventListener']) + ->withMethodCall('addResultProcessor', ['collectionProcessHook', '*']); + $container->share('eventDispatcher', \Symfony\Component\EventDispatcher\EventDispatcher::class) + ->withMethodCall('addSubscriber', ['hookManager']); + $container->share('formatterManager', \Consolidation\OutputFormatters\FormatterManager::class) + ->withMethodCall('addDefaultFormatters', []) + ->withMethodCall('addDefaultSimplifiers', []); + $container->share('prepareTerminalWidthOption', \Consolidation\AnnotatedCommand\Options\PrepareTerminalWidthOption::class) + ->withMethodCall('setApplication', ['application']); + $container->share('commandProcessor', \Consolidation\AnnotatedCommand\CommandProcessor::class) + ->withArgument('hookManager') + ->withMethodCall('setFormatterManager', ['formatterManager']) + ->withMethodCall('addPrepareFormatter', ['prepareTerminalWidthOption']) + ->withMethodCall( + 'setDisplayErrorFunction', + [ + function ($output, $message) use ($container) { + $logger = $container->get('logger'); + $logger->error($message); + } + ] + ); + $container->share('commandFactory', \Consolidation\AnnotatedCommand\AnnotatedCommandFactory::class) + ->withMethodCall('setCommandProcessor', ['commandProcessor']); + + // Deprecated: favor using collection builders to direct use of collections. + $container->add('collection', \Robo\Collection\Collection::class); + // Deprecated: use CollectionBuilder::create() instead -- or, better + // yet, BuilderAwareInterface::collectionBuilder() if available. + $container->add('collectionBuilder', \Robo\Collection\CollectionBuilder::class); + + static::addInflectors($container); + + // Make sure the application is appropriately initialized. + $app->setAutoExit(false); + } + + /** + * @param null|string $appName + * @param null|string $appVersion + * + * @return \Robo\Application + */ + public static function createDefaultApplication($appName = null, $appVersion = null) + { + $appName = $appName ?: self::APPLICATION_NAME; + $appVersion = $appVersion ?: self::VERSION; + + $app = new \Robo\Application($appName, $appVersion); + $app->setAutoExit(false); + return $app; + } + + /** + * Add the Robo League\Container inflectors to the container + * + * @param \League\Container\ContainerInterface $container + */ + public static function addInflectors($container) + { + // Register our various inflectors. + $container->inflector(\Robo\Contract\ConfigAwareInterface::class) + ->invokeMethod('setConfig', ['config']); + $container->inflector(\Psr\Log\LoggerAwareInterface::class) + ->invokeMethod('setLogger', ['logger']); + $container->inflector(\League\Container\ContainerAwareInterface::class) + ->invokeMethod('setContainer', ['container']); + $container->inflector(\Symfony\Component\Console\Input\InputAwareInterface::class) + ->invokeMethod('setInput', ['input']); + $container->inflector(\Robo\Contract\OutputAwareInterface::class) + ->invokeMethod('setOutput', ['output']); + $container->inflector(\Robo\Contract\ProgressIndicatorAwareInterface::class) + ->invokeMethod('setProgressIndicator', ['progressIndicator']); + $container->inflector(\Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface::class) + ->invokeMethod('setHookManager', ['hookManager']); + $container->inflector(\Robo\Contract\VerbosityThresholdInterface::class) + ->invokeMethod('setOutputAdapter', ['outputAdapter']); + } + + /** + * Retrieves a service from the container. + * + * Use this method if the desired service is not one of those with a dedicated + * accessor method below. If it is listed below, those methods are preferred + * as they can return useful type hints. + * + * @param string $id + * The ID of the service to retrieve. + * + * @return mixed + * The specified service. + */ + public static function service($id) + { + return static::getContainer()->get($id); + } + + /** + * Indicates if a service is defined in the container. + * + * @param string $id + * The ID of the service to check. + * + * @return bool + * TRUE if the specified service exists, FALSE otherwise. + */ + public static function hasService($id) + { + // Check hasContainer() first in order to always return a Boolean. + return static::hasContainer() && static::getContainer()->has($id); + } + + /** + * Return the result printer object. + * + * @return \Robo\Log\ResultPrinter + */ + public static function resultPrinter() + { + return static::service('resultPrinter'); + } + + /** + * @return ConfigInterface + */ + public static function config() + { + return static::service('config'); + } + + /** + * @return \Consolidation\Log\Logger + */ + public static function logger() + { + return static::service('logger'); + } + + /** + * @return \Robo\Application + */ + public static function application() + { + return static::service('application'); + } + + /** + * Return the output object. + * + * @return \Symfony\Component\Console\Output\OutputInterface + */ + public static function output() + { + return static::service('output'); + } + + /** + * Return the input object. + * + * @return \Symfony\Component\Console\Input\InputInterface + */ + public static function input() + { + return static::service('input'); + } + + public static function process(Process $process) + { + return ProcessExecutor::create(static::getContainer(), $process); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Runner.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Runner.php new file mode 100644 index 00000000..800ad281 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Runner.php @@ -0,0 +1,465 @@ +roboClass = $roboClass ? $roboClass : self::ROBOCLASS ; + $this->roboFile = $roboFile ? $roboFile : self::ROBOFILE; + $this->dir = getcwd(); + } + + protected function errorCondtion($msg, $errorType) + { + $this->errorConditions[$msg] = $errorType; + } + + /** + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return bool + */ + protected function loadRoboFile($output) + { + // If we have not been provided an output object, make a temporary one. + if (!$output) { + $output = new \Symfony\Component\Console\Output\ConsoleOutput(); + } + + // If $this->roboClass is a single class that has not already + // been loaded, then we will try to obtain it from $this->roboFile. + // If $this->roboClass is an array, we presume all classes requested + // are available via the autoloader. + if (is_array($this->roboClass) || class_exists($this->roboClass)) { + return true; + } + if (!file_exists($this->dir)) { + $this->errorCondtion("Path `{$this->dir}` is invalid; please provide a valid absolute path to the Robofile to load.", 'red'); + return false; + } + + $realDir = realpath($this->dir); + + $roboFilePath = $realDir . DIRECTORY_SEPARATOR . $this->roboFile; + if (!file_exists($roboFilePath)) { + $requestedRoboFilePath = $this->dir . DIRECTORY_SEPARATOR . $this->roboFile; + $this->errorCondtion("Requested RoboFile `$requestedRoboFilePath` is invalid, please provide valid absolute path to load Robofile.", 'red'); + return false; + } + require_once $roboFilePath; + + if (!class_exists($this->roboClass)) { + $this->errorCondtion("Class {$this->roboClass} was not loaded.", 'red'); + return false; + } + return true; + } + + /** + * @param array $argv + * @param null|string $appName + * @param null|string $appVersion + * @param null|\Symfony\Component\Console\Output\OutputInterface $output + * + * @return int + */ + public function execute($argv, $appName = null, $appVersion = null, $output = null) + { + $argv = $this->shebang($argv); + $argv = $this->processRoboOptions($argv); + $app = null; + if ($appName && $appVersion) { + $app = Robo::createDefaultApplication($appName, $appVersion); + } + $commandFiles = $this->getRoboFileCommands($output); + return $this->run($argv, $output, $app, $commandFiles); + } + + /** + * @param null|\Symfony\Component\Console\Input\InputInterface $input + * @param null|\Symfony\Component\Console\Output\OutputInterface $output + * @param null|\Robo\Application $app + * @param array[] $commandFiles + * + * @return int + */ + public function run($input = null, $output = null, $app = null, $commandFiles = []) + { + // Create default input and output objects if they were not provided + if (!$input) { + $input = new StringInput(''); + } + if (is_array($input)) { + $input = new ArgvInput($input); + } + if (!$output) { + $output = new \Symfony\Component\Console\Output\ConsoleOutput(); + } + $this->setInput($input); + $this->setOutput($output); + + // If we were not provided a container, then create one + if (!$this->getContainer()) { + $userConfig = 'robo.yml'; + $roboAppConfig = dirname(__DIR__) . '/robo.yml'; + $config = Robo::createConfiguration([$userConfig, $roboAppConfig]); + $container = Robo::createDefaultContainer($input, $output, $app, $config); + $this->setContainer($container); + // Automatically register a shutdown function and + // an error handler when we provide the container. + $this->installRoboHandlers(); + } + + if (!$app) { + $app = Robo::application(); + } + if ($app instanceof \Robo\Application) { + $app->addSelfUpdateCommand($this->getSelfUpdateRepository()); + if (!isset($commandFiles)) { + $this->errorCondtion("Robo is not initialized here. Please run `robo init` to create a new RoboFile.", 'yellow'); + $app->addInitRoboFileCommand($this->roboFile, $this->roboClass); + $commandFiles = []; + } + } + $this->registerCommandClasses($app, $commandFiles); + + try { + $statusCode = $app->run($input, $output); + } catch (TaskExitException $e) { + $statusCode = $e->getCode() ?: 1; + } + + // If there were any error conditions in bootstrapping Robo, + // print them only if the requested command did not complete + // successfully. + if ($statusCode) { + foreach ($this->errorConditions as $msg => $color) { + $this->yell($msg, 40, $color); + } + } + return $statusCode; + } + + /** + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return null|string + */ + protected function getRoboFileCommands($output) + { + if (!$this->loadRoboFile($output)) { + return; + } + return $this->roboClass; + } + + /** + * @param \Robo\Application $app + * @param array $commandClasses + */ + public function registerCommandClasses($app, $commandClasses) + { + foreach ((array)$commandClasses as $commandClass) { + $this->registerCommandClass($app, $commandClass); + } + } + + /** + * @param \Robo\Application $app + * @param string|BuilderAwareInterface|ContainerAwareInterface $commandClass + * + * @return mixed|void + */ + public function registerCommandClass($app, $commandClass) + { + $container = Robo::getContainer(); + $roboCommandFileInstance = $this->instantiateCommandClass($commandClass); + if (!$roboCommandFileInstance) { + return; + } + + // Register commands for all of the public methods in the RoboFile. + $commandFactory = $container->get('commandFactory'); + $commandList = $commandFactory->createCommandsFromClass($roboCommandFileInstance); + foreach ($commandList as $command) { + $app->add($command); + } + return $roboCommandFileInstance; + } + + /** + * @param string|BuilderAwareInterface|ContainerAwareInterface $commandClass + * + * @return null|object + */ + protected function instantiateCommandClass($commandClass) + { + $container = Robo::getContainer(); + + // Register the RoboFile with the container and then immediately + // fetch it; this ensures that all of the inflectors will run. + // If the command class is already an instantiated object, then + // just use it exactly as it was provided to us. + if (is_string($commandClass)) { + if (!class_exists($commandClass)) { + return; + } + $reflectionClass = new \ReflectionClass($commandClass); + if ($reflectionClass->isAbstract()) { + return; + } + + $commandFileName = "{$commandClass}Commands"; + $container->share($commandFileName, $commandClass); + $commandClass = $container->get($commandFileName); + } + // If the command class is a Builder Aware Interface, then + // ensure that it has a builder. Every command class needs + // its own collection builder, as they have references to each other. + if ($commandClass instanceof BuilderAwareInterface) { + $builder = CollectionBuilder::create($container, $commandClass); + $commandClass->setBuilder($builder); + } + if ($commandClass instanceof ContainerAwareInterface) { + $commandClass->setContainer($container); + } + return $commandClass; + } + + public function installRoboHandlers() + { + register_shutdown_function(array($this, 'shutdown')); + set_error_handler(array($this, 'handleError')); + } + + /** + * Process a shebang script, if one was used to launch this Runner. + * + * @param array $args + * + * @return array $args with shebang script removed + */ + protected function shebang($args) + { + // Option 1: Shebang line names Robo, but includes no parameters. + // #!/bin/env robo + // The robo class may contain multiple commands; the user may + // select which one to run, or even get a list of commands or + // run 'help' on any of the available commands as usual. + if ((count($args) > 1) && $this->isShebangFile($args[1])) { + return array_merge([$args[0]], array_slice($args, 2)); + } + // Option 2: Shebang line stipulates which command to run. + // #!/bin/env robo mycommand + // The robo class must contain a public method named 'mycommand'. + // This command will be executed every time. Arguments and options + // may be provided on the commandline as usual. + if ((count($args) > 2) && $this->isShebangFile($args[2])) { + return array_merge([$args[0]], explode(' ', $args[1]), array_slice($args, 3)); + } + return $args; + } + + /** + * Determine if the specified argument is a path to a shebang script. + * If so, load it. + * + * @param string $filepath file to check + * + * @return bool Returns TRUE if shebang script was processed + */ + protected function isShebangFile($filepath) + { + if (!is_file($filepath)) { + return false; + } + $fp = fopen($filepath, "r"); + if ($fp === false) { + return false; + } + $line = fgets($fp); + $result = $this->isShebangLine($line); + if ($result) { + while ($line = fgets($fp)) { + $line = trim($line); + if ($line == 'roboClass = $matches[1]; + eval($script); + $result = true; + } + } + } + } + fclose($fp); + + return $result; + } + + /** + * Test to see if the provided line is a robo 'shebang' line. + * + * @param string $line + * + * @return bool + */ + protected function isShebangLine($line) + { + return ((substr($line, 0, 2) == '#!') && (strstr($line, 'robo') !== false)); + } + + /** + * Check for Robo-specific arguments such as --load-from, process them, + * and remove them from the array. We have to process --load-from before + * we set up Symfony Console. + * + * @param array $argv + * + * @return array + */ + protected function processRoboOptions($argv) + { + // loading from other directory + $pos = $this->arraySearchBeginsWith('--load-from', $argv) ?: array_search('-f', $argv); + if ($pos === false) { + return $argv; + } + + $passThru = array_search('--', $argv); + if (($passThru !== false) && ($passThru < $pos)) { + return $argv; + } + + if (substr($argv[$pos], 0, 12) == '--load-from=') { + $this->dir = substr($argv[$pos], 12); + } elseif (isset($argv[$pos +1])) { + $this->dir = $argv[$pos +1]; + unset($argv[$pos +1]); + } + unset($argv[$pos]); + // Make adjustments if '--load-from' points at a file. + if (is_file($this->dir) || (substr($this->dir, -4) == '.php')) { + $this->roboFile = basename($this->dir); + $this->dir = dirname($this->dir); + $className = basename($this->roboFile, '.php'); + if ($className != $this->roboFile) { + $this->roboClass = $className; + } + } + // Convert directory to a real path, but only if the + // path exists. We do not want to lose the original + // directory if the user supplied a bad value. + $realDir = realpath($this->dir); + if ($realDir) { + chdir($realDir); + $this->dir = $realDir; + } + + return $argv; + } + + /** + * @param string $needle + * @param string[] $haystack + * + * @return bool|int + */ + protected function arraySearchBeginsWith($needle, $haystack) + { + for ($i = 0; $i < count($haystack); ++$i) { + if (substr($haystack[$i], 0, strlen($needle)) == $needle) { + return $i; + } + } + return false; + } + + public function shutdown() + { + $error = error_get_last(); + if (!is_array($error)) { + return; + } + $this->writeln(sprintf("ERROR: %s \nin %s:%d\n", $error['message'], $error['file'], $error['line'])); + } + + /** + * This is just a proxy error handler that checks the current error_reporting level. + * In case error_reporting is disabled the error is marked as handled, otherwise + * the normal internal error handling resumes. + * + * @return bool + */ + public function handleError() + { + if (error_reporting() === 0) { + return true; + } + return false; + } + + /** + * @return string + */ + public function getSelfUpdateRepository() + { + return $this->selfUpdateRepository; + } + + /** + * @param string $selfUpdateRepository + */ + public function setSelfUpdateRepository($selfUpdateRepository) + { + $this->selfUpdateRepository = $selfUpdateRepository; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/SelfUpdateCommand.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/SelfUpdateCommand.php new file mode 100644 index 00000000..d07ee71f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/SelfUpdateCommand.php @@ -0,0 +1,152 @@ + + */ +class SelfUpdateCommand extends Command +{ + const SELF_UPDATE_COMMAND_NAME = 'self:update'; + + protected $gitHubRepository; + + protected $currentVersion; + + protected $applicationName; + + public function __construct($applicationName = null, $currentVersion = null, $gitHubRepository = null) + { + parent::__construct(self::SELF_UPDATE_COMMAND_NAME); + + $this->applicationName = $applicationName; + $this->currentVersion = $currentVersion; + $this->gitHubRepository = $gitHubRepository; + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setAliases(array('update')) + ->setDescription('Updates the robo.phar to the latest version.') + ->setHelp( + <<self-update command checks github for newer +versions of robo and if found, installs the latest. +EOT + ); + } + + protected function getLatestReleaseFromGithub() + { + $opts = [ + 'http' => [ + 'method' => 'GET', + 'header' => [ + 'User-Agent: ' . $this->applicationName . ' (' . $this->gitHubRepository . ')' . ' Self-Update (PHP)' + ] + ] + ]; + + $context = stream_context_create($opts); + + $releases = file_get_contents('https://api.github.com/repos/' . $this->gitHubRepository . '/releases', false, $context); + $releases = json_decode($releases); + + if (! isset($releases[0])) { + throw new \Exception('API error - no release found at GitHub repository ' . $this->gitHubRepository); + } + + $version = $releases[0]->tag_name; + $url = $releases[0]->assets[0]->browser_download_url; + + return [ $version, $url ]; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (empty(\Phar::running())) { + throw new \Exception(self::SELF_UPDATE_COMMAND_NAME . ' only works when running the phar version of ' . $this->applicationName . '.'); + } + + $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; + $programName = basename($localFilename); + $tempFilename = dirname($localFilename) . '/' . basename($localFilename, '.phar') . '-temp.phar'; + + // check for permissions in local filesystem before start connection process + if (! is_writable($tempDirectory = dirname($tempFilename))) { + throw new \Exception( + $programName . ' update failed: the "' . $tempDirectory . + '" directory used to download the temp file could not be written' + ); + } + + if (! is_writable($localFilename)) { + throw new \Exception( + $programName . ' update failed: the "' . $localFilename . '" file could not be written (execute with sudo)' + ); + } + + list( $latest, $downloadUrl ) = $this->getLatestReleaseFromGithub(); + + + if ($this->currentVersion == $latest) { + $output->writeln('No update available'); + return; + } + + $fs = new sfFilesystem(); + + $output->writeln('Downloading ' . $this->applicationName . ' (' . $this->gitHubRepository . ') ' . $latest); + + $fs->copy($downloadUrl, $tempFilename); + + $output->writeln('Download finished'); + + try { + \error_reporting(E_ALL); // supress notices + + @chmod($tempFilename, 0777 & ~umask()); + // test the phar validity + $phar = new \Phar($tempFilename); + // free the variable to unlock the file + unset($phar); + @rename($tempFilename, $localFilename); + $output->writeln('Successfully updated ' . $programName . ''); + $this->_exit(); + } catch (\Exception $e) { + @unlink($tempFilename); + if (! $e instanceof \UnexpectedValueException && ! $e instanceof \PharException) { + throw $e; + } + $output->writeln('The download is corrupted (' . $e->getMessage() . ').'); + $output->writeln('Please re-run the self-update command to try again.'); + } + } + + /** + * Stop execution + * + * This is a workaround to prevent warning of dispatcher after replacing + * the phar file. + * + * @return void + */ + protected function _exit() + { + exit; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/Consumer.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/Consumer.php new file mode 100644 index 00000000..ab9c0e27 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/Consumer.php @@ -0,0 +1,12 @@ +message = $message; + parent::__construct($data); + } + + /** + * @return array + */ + public function getData() + { + return $this->getArrayCopy(); + } + + /** + * @return string + */ + public function getMessage() + { + return $this->message; + } + + /** + * @param string message + */ + public function setMessage($message) + { + $this->message = $message; + } + + /** + * Merge another result into this result. Data already + * existing in this result takes precedence over the + * data in the Result being merged. + * + * @param \Robo\ResultData $result + * + * @return $this + */ + public function merge(Data $result) + { + $mergedData = $this->getArrayCopy() + $result->getArrayCopy(); + $this->exchangeArray($mergedData); + return $this; + } + + /** + * Update the current data with the data provided in the parameter. + * Provided data takes precedence. + * + * @param \ArrayObject $update + * + * @return $this + */ + public function update(\ArrayObject $update) + { + $iterator = $update->getIterator(); + + while ($iterator->valid()) { + $this[$iterator->key()] = $iterator->current(); + $iterator->next(); + } + + return $this; + } + + /** + * Merge another result into this result. Data already + * existing in this result takes precedence over the + * data in the Result being merged. + * + * $data['message'] is handled specially, and is appended + * to $this->message if set. + * + * @param array $data + * + * @return array + */ + public function mergeData(array $data) + { + $mergedData = $this->getArrayCopy() + $data; + $this->exchangeArray($mergedData); + return $mergedData; + } + + /** + * @return bool + */ + public function hasExecutionTime() + { + return isset($this['time']); + } + + /** + * @return null|float + */ + public function getExecutionTime() + { + if (!$this->hasExecutionTime()) { + return null; + } + return $this['time']; + } + + /** + * Accumulate execution time + */ + public function accumulateExecutionTime($duration) + { + // Convert data arrays to scalar + if (is_array($duration)) { + $duration = isset($duration['time']) ? $duration['time'] : 0; + } + $this['time'] = $this->getExecutionTime() + $duration; + return $this->getExecutionTime(); + } + + /** + * Accumulate the message. + */ + public function accumulateMessage($message) + { + if (!empty($this->message)) { + $this->message .= "\n"; + } + $this->message .= $message; + return $this->getMessage(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/StateAwareInterface.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/StateAwareInterface.php new file mode 100644 index 00000000..f86bccb8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/State/StateAwareInterface.php @@ -0,0 +1,30 @@ +state; + } + + /** + * {@inheritdoc} + */ + public function setState(Data $state) + { + $this->state = $state; + } + + /** + * {@inheritdoc} + */ + public function setStateValue($key, $value) + { + $this->state[$key] = $value; + } + + /** + * {@inheritdoc} + */ + public function updateState(Data $update) + { + $this->state->update($update); + } + + /** + * {@inheritdoc} + */ + public function resetState() + { + $this->state = new Data(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/ApiGen/ApiGen.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/ApiGen/ApiGen.php new file mode 100644 index 00000000..11ff764c --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/ApiGen/ApiGen.php @@ -0,0 +1,518 @@ +taskApiGen('./vendor/apigen/apigen.phar') + * ->config('./apigen.neon') + * ->templateConfig('vendor/apigen/apigen/templates/bootstrap/config.neon') + * ->wipeout(true) + * ->run(); + * ?> + * ``` + */ +class ApiGen extends BaseTask implements CommandInterface +{ + use \Robo\Common\ExecOneCommand; + + const BOOL_NO = 'no'; + const BOOL_YES = 'yes'; + + /** + * @var string + */ + protected $command; + protected $operation = 'generate'; + + /** + * @param null|string $pathToApiGen + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToApiGen = null) + { + $this->command = $pathToApiGen; + $command_parts = []; + preg_match('/((?:.+)?apigen(?:\.phar)?) ?( \w+)? ?(.+)?/', $this->command, $command_parts); + if (count($command_parts) === 3) { + list(, $this->command, $this->operation) = $command_parts; + } + if (count($command_parts) === 4) { + list(, $this->command, $this->operation, $arg) = $command_parts; + $this->arg($arg); + } + if (!$this->command) { + $this->command = $this->findExecutablePhar('apigen'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "No apigen installation found"); + } + } + + /** + * Pass methods parameters as arguments to executable. Argument values + * are automatically escaped. + * + * @param string|string[] $args + * + * @return $this + */ + public function args($args) + { + if (!is_array($args)) { + $args = func_get_args(); + } + $args = array_map(function ($arg) { + if (preg_match('/^\w+$/', trim($arg)) === 1) { + $this->operation = $arg; + return null; + } + return $arg; + }, $args); + $args = array_filter($args); + $this->arguments .= ' ' . implode(' ', array_map('static::escape', $args)); + return $this; + } + + /** + * @param array|Traversable|string $arg a single object or something traversable + * + * @return array|Traversable the provided argument if it was already traversable, or the given + * argument returned as a one-element array + */ + protected static function forceTraversable($arg) + { + $traversable = $arg; + if (!is_array($traversable) && !($traversable instanceof \Traversable)) { + $traversable = array($traversable); + } + return $traversable; + } + + /** + * @param array|string $arg a single argument or an array of multiple string values + * + * @return string a comma-separated string of all of the provided arguments, suitable + * as a command-line "list" type argument for ApiGen + */ + protected static function asList($arg) + { + $normalized = is_array($arg) ? $arg : array($arg); + return implode(',', $normalized); + } + + /** + * @param bool|string $val an argument to be normalized + * @param string $default one of self::BOOL_YES or self::BOOK_NO if the provided + * value could not deterministically be converted to a + * yes or no value + * + * @return string the given value as a command-line "yes|no" type of argument for ApiGen, + * or the default value if none could be determined + */ + protected static function asTextBool($val, $default) + { + if ($val === self::BOOL_YES || $val === self::BOOL_NO) { + return $val; + } + if (!$val) { + return self::BOOL_NO; + } + if ($val === true) { + return self::BOOL_YES; + } + if (is_numeric($val) && $val != 0) { + return self::BOOL_YES; + } + if (strcasecmp($val[0], 'y') === 0) { + return self::BOOL_YES; + } + if (strcasecmp($val[0], 'n') === 0) { + return self::BOOL_NO; + } + // meh, good enough, let apigen sort it out + return $default; + } + + /** + * @param string $config + * + * @return $this + */ + public function config($config) + { + $this->option('config', $config); + return $this; + } + + /** + * @param array|string|Traversable $src one or more source values + * + * @return $this + */ + public function source($src) + { + foreach (self::forceTraversable($src) as $source) { + $this->option('source', $source); + } + return $this; + } + + /** + * @param string $dest + * + * @return $this + */ + public function destination($dest) + { + $this->option('destination', $dest); + return $this; + } + + /** + * @param array|string $exts one or more extensions + * + * @return $this + */ + public function extensions($exts) + { + $this->option('extensions', self::asList($exts)); + return $this; + } + + /** + * @param array|string $exclude one or more exclusions + * + * @return $this + */ + public function exclude($exclude) + { + foreach (self::forceTraversable($exclude) as $excl) { + $this->option('exclude', $excl); + } + return $this; + } + + /** + * @param array|string|Traversable $path one or more skip-doc-path values + * + * @return $this + */ + public function skipDocPath($path) + { + foreach (self::forceTraversable($path) as $skip) { + $this->option('skip-doc-path', $skip); + } + return $this; + } + + /** + * @param array|string|Traversable $prefix one or more skip-doc-prefix values + * + * @return $this + */ + public function skipDocPrefix($prefix) + { + foreach (self::forceTraversable($prefix) as $skip) { + $this->option('skip-doc-prefix', $skip); + } + return $this; + } + + /** + * @param array|string $charset one or more charsets + * + * @return $this + */ + public function charset($charset) + { + $this->option('charset', self::asList($charset)); + return $this; + } + + /** + * @param string $name + * + * @return $this + */ + public function mainProjectNamePrefix($name) + { + $this->option('main', $name); + return $this; + } + + /** + * @param string $title + * + * @return $this + */ + public function title($title) + { + $this->option('title', $title); + return $this; + } + + /** + * @param string $baseUrl + * + * @return $this + */ + public function baseUrl($baseUrl) + { + $this->option('base-url', $baseUrl); + return $this; + } + + /** + * @param string $id + * + * @return $this + */ + public function googleCseId($id) + { + $this->option('google-cse-id', $id); + return $this; + } + + /** + * @param string $trackingCode + * + * @return $this + */ + public function googleAnalytics($trackingCode) + { + $this->option('google-analytics', $trackingCode); + return $this; + } + + /** + * @param mixed $templateConfig + * + * @return $this + */ + public function templateConfig($templateConfig) + { + $this->option('template-config', $templateConfig); + return $this; + } + + /** + * @param array|string $tags one or more supported html tags + * + * @return $this + */ + public function allowedHtml($tags) + { + $this->option('allowed-html', self::asList($tags)); + return $this; + } + + /** + * @param string $groups + * + * @return $this + */ + public function groups($groups) + { + $this->option('groups', $groups); + return $this; + } + + /** + * @param array|string $types or more supported autocomplete types + * + * @return $this + */ + public function autocomplete($types) + { + $this->option('autocomplete', self::asList($types)); + return $this; + } + + /** + * @param array|string $levels one or more access levels + * + * @return $this + */ + public function accessLevels($levels) + { + $this->option('access-levels', self::asList($levels)); + return $this; + } + + /** + * @param boolean|string $internal 'yes' or true if internal, 'no' or false if not + * + * @return $this + */ + public function internal($internal) + { + $this->option('internal', self::asTextBool($internal, self::BOOL_NO)); + return $this; + } + + /** + * @param boolean|string $php 'yes' or true to generate documentation for internal php classes, + * 'no' or false otherwise + * + * @return $this + */ + public function php($php) + { + $this->option('php', self::asTextBool($php, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $tree 'yes' or true to generate a tree view of classes, 'no' or false otherwise + * + * @return $this + */ + public function tree($tree) + { + $this->option('tree', self::asTextBool($tree, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $dep 'yes' or true to generate documentation for deprecated classes, 'no' or false otherwise + * + * @return $this + */ + public function deprecated($dep) + { + $this->option('deprecated', self::asTextBool($dep, self::BOOL_NO)); + return $this; + } + + /** + * @param bool|string $todo 'yes' or true to document tasks, 'no' or false otherwise + * + * @return $this + */ + public function todo($todo) + { + $this->option('todo', self::asTextBool($todo, self::BOOL_NO)); + return $this; + } + + /** + * @param bool|string $src 'yes' or true to generate highlighted source code, 'no' or false otherwise + * + * @return $this + */ + public function sourceCode($src) + { + $this->option('source-code', self::asTextBool($src, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $zipped 'yes' or true to generate downloadable documentation, 'no' or false otherwise + * + * @return $this + */ + public function download($zipped) + { + $this->option('download', self::asTextBool($zipped, self::BOOL_NO)); + return $this; + } + + public function report($path) + { + $this->option('report', $path); + return $this; + } + + /** + * @param bool|string $wipeout 'yes' or true to clear out the destination directory, 'no' or false otherwise + * + * @return $this + */ + public function wipeout($wipeout) + { + $this->option('wipeout', self::asTextBool($wipeout, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $quiet 'yes' or true for quiet, 'no' or false otherwise + * + * @return $this + */ + public function quiet($quiet) + { + $this->option('quiet', self::asTextBool($quiet, self::BOOL_NO)); + return $this; + } + + /** + * @param bool|string $bar 'yes' or true to display a progress bar, 'no' or false otherwise + * + * @return $this + */ + public function progressbar($bar) + { + $this->option('progressbar', self::asTextBool($bar, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $colors 'yes' or true colorize the output, 'no' or false otherwise + * + * @return $this + */ + public function colors($colors) + { + $this->option('colors', self::asTextBool($colors, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $check 'yes' or true to check for updates, 'no' or false otherwise + * + * @return $this + */ + public function updateCheck($check) + { + $this->option('update-check', self::asTextBool($check, self::BOOL_YES)); + return $this; + } + + /** + * @param bool|string $debug 'yes' or true to enable debug mode, 'no' or false otherwise + * + * @return $this + */ + public function debug($debug) + { + $this->option('debug', self::asTextBool($debug, self::BOOL_NO)); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return "$this->command $this->operation$this->arguments"; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running ApiGen {args}', ['args' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/ApiGen/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/ApiGen/loadTasks.php new file mode 100644 index 00000000..e8cd372a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/ApiGen/loadTasks.php @@ -0,0 +1,15 @@ +task(ApiGen::class, $pathToApiGen); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/Extract.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/Extract.php new file mode 100644 index 00000000..a00a0baf --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/Extract.php @@ -0,0 +1,279 @@ +taskExtract($archivePath) + * ->to($destination) + * ->preserveTopDirectory(false) // the default + * ->run(); + * ?> + * ``` + */ +class Extract extends BaseTask implements BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var string + */ + protected $filename; + + /** + * @var string + */ + protected $to; + + /** + * @var bool + */ + private $preserveTopDirectory = false; + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * Location to store extracted files. + * + * @param string $to + * + * @return $this + */ + public function to($to) + { + $this->to = $to; + return $this; + } + + /** + * @param bool $preserve + * + * @return $this + */ + public function preserveTopDirectory($preserve = true) + { + $this->preserveTopDirectory = $preserve; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!file_exists($this->filename)) { + $this->printTaskError("File {filename} does not exist", ['filename' => $this->filename]); + + return false; + } + if (!($mimetype = static::archiveType($this->filename))) { + $this->printTaskError("Could not determine type of archive for {filename}", ['filename' => $this->filename]); + + return false; + } + + // We will first extract to $extractLocation and then move to $this->to + $extractLocation = static::getTmpDir(); + @mkdir($extractLocation); + @mkdir(dirname($this->to)); + + $this->startTimer(); + + $this->printTaskInfo("Extracting {filename}", ['filename' => $this->filename]); + + $result = $this->extractAppropriateType($mimetype, $extractLocation); + if ($result->wasSuccessful()) { + $this->printTaskInfo("{filename} extracted", ['filename' => $this->filename]); + // Now, we want to move the extracted files to $this->to. There + // are two possibilities that we must consider: + // + // (1) Archived files were encapsulated in a folder with an arbitrary name + // (2) There was no encapsulating folder, and all the files in the archive + // were extracted into $extractLocation + // + // In the case of (1), we want to move and rename the encapsulating folder + // to $this->to. + // + // In the case of (2), we will just move and rename $extractLocation. + $filesInExtractLocation = glob("$extractLocation/*"); + $hasEncapsulatingFolder = ((count($filesInExtractLocation) == 1) && is_dir($filesInExtractLocation[0])); + if ($hasEncapsulatingFolder && !$this->preserveTopDirectory) { + $result = (new FilesystemStack()) + ->inflect($this) + ->rename($filesInExtractLocation[0], $this->to) + ->run(); + (new DeleteDir($extractLocation)) + ->inflect($this) + ->run(); + } else { + $result = (new FilesystemStack()) + ->inflect($this) + ->rename($extractLocation, $this->to) + ->run(); + } + } + $this->stopTimer(); + $result['time'] = $this->getExecutionTime(); + + return $result; + } + + /** + * @param string $mimetype + * @param string $extractLocation + * + * @return \Robo\Result + */ + protected function extractAppropriateType($mimetype, $extractLocation) + { + // Perform the extraction of a zip file. + if (($mimetype == 'application/zip') || ($mimetype == 'application/x-zip')) { + return $this->extractZip($extractLocation); + } + return $this->extractTar($extractLocation); + } + + /** + * @param string $extractLocation + * + * @return \Robo\Result + */ + protected function extractZip($extractLocation) + { + if (!extension_loaded('zlib')) { + return Result::errorMissingExtension($this, 'zlib', 'zip extracting'); + } + + $zip = new \ZipArchive(); + if (($status = $zip->open($this->filename)) !== true) { + return Result::error($this, "Could not open zip archive {$this->filename}"); + } + if (!$zip->extractTo($extractLocation)) { + return Result::error($this, "Could not extract zip archive {$this->filename}"); + } + $zip->close(); + + return Result::success($this); + } + + /** + * @param string $extractLocation + * + * @return \Robo\Result + */ + protected function extractTar($extractLocation) + { + if (!class_exists('Archive_Tar')) { + return Result::errorMissingPackage($this, 'Archive_Tar', 'pear/archive_tar'); + } + $tar_object = new \Archive_Tar($this->filename); + if (!$tar_object->extract($extractLocation)) { + return Result::error($this, "Could not extract tar archive {$this->filename}"); + } + + return Result::success($this); + } + + /** + * @param string $filename + * + * @return bool|string + */ + protected static function archiveType($filename) + { + $content_type = false; + if (class_exists('finfo')) { + $finfo = new \finfo(FILEINFO_MIME_TYPE); + $content_type = $finfo->file($filename); + // If finfo cannot determine the content type, then we will try other methods + if ($content_type == 'application/octet-stream') { + $content_type = false; + } + } + // Examing the file's magic header bytes. + if (!$content_type) { + if ($file = fopen($filename, 'rb')) { + $first = fread($file, 2); + fclose($file); + if ($first !== false) { + // Interpret the two bytes as a little endian 16-bit unsigned int. + $data = unpack('v', $first); + switch ($data[1]) { + case 0x8b1f: + // First two bytes of gzip files are 0x1f, 0x8b (little-endian). + // See http://www.gzip.org/zlib/rfc-gzip.html#header-trailer + $content_type = 'application/x-gzip'; + break; + + case 0x4b50: + // First two bytes of zip files are 0x50, 0x4b ('PK') (little-endian). + // See http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers + $content_type = 'application/zip'; + break; + + case 0x5a42: + // First two bytes of bzip2 files are 0x5a, 0x42 ('BZ') (big-endian). + // See http://en.wikipedia.org/wiki/Bzip2#File_format + $content_type = 'application/x-bzip2'; + break; + } + } + } + } + // 3. Lastly if above methods didn't work, try to guess the mime type from + // the file extension. This is useful if the file has no identificable magic + // header bytes (for example tarballs). + if (!$content_type) { + // Remove querystring from the filename, if present. + $filename = basename(current(explode('?', $filename, 2))); + $extension_mimetype = array( + '.tar.gz' => 'application/x-gzip', + '.tgz' => 'application/x-gzip', + '.tar' => 'application/x-tar', + ); + foreach ($extension_mimetype as $extension => $ct) { + if (substr($filename, -strlen($extension)) === $extension) { + $content_type = $ct; + break; + } + } + } + + return $content_type; + } + + /** + * @return string + */ + protected static function getTmpDir() + { + return getcwd().'/tmp'.rand().time(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/Pack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/Pack.php new file mode 100644 index 00000000..0970f8e8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/Pack.php @@ -0,0 +1,257 @@ +taskPack( + * ) + * ->add('README') // Puts file 'README' in archive at the root + * ->add('project') // Puts entire contents of directory 'project' in archinve inside 'project' + * ->addFile('dir/file.txt', 'file.txt') // Takes 'file.txt' from cwd and puts it in archive inside 'dir'. + * ->run(); + * ?> + * ``` + */ +class Pack extends BaseTask implements PrintedInterface +{ + /** + * The list of items to be packed into the archive. + * + * @var array + */ + private $items = []; + + /** + * The full path to the archive to be created. + * + * @var string + */ + private $archiveFile; + + /** + * Construct the class. + * + * @param string $archiveFile The full path and name of the archive file to create. + * + * @since 1.0 + */ + public function __construct($archiveFile) + { + $this->archiveFile = $archiveFile; + } + + /** + * Satisfy the parent requirement. + * + * @return bool Always returns true. + * + * @since 1.0 + */ + public function getPrinted() + { + return true; + } + + /** + * @param string $archiveFile + * + * @return $this + */ + public function archiveFile($archiveFile) + { + $this->archiveFile = $archiveFile; + return $this; + } + + /** + * Add an item to the archive. Like file_exists(), the parameter + * may be a file or a directory. + * + * @var string + * Relative path and name of item to store in archive + * @var string + * Absolute or relative path to file or directory's location in filesystem + * + * @return $this + */ + public function addFile($placementLocation, $filesystemLocation) + { + $this->items[$placementLocation] = $filesystemLocation; + + return $this; + } + + /** + * Alias for addFile, in case anyone has angst about using + * addFile with a directory. + * + * @var string + * Relative path and name of directory to store in archive + * @var string + * Absolute or relative path to directory or directory's location in filesystem + * + * @return $this + */ + public function addDir($placementLocation, $filesystemLocation) + { + $this->addFile($placementLocation, $filesystemLocation); + + return $this; + } + + /** + * Add a file or directory, or list of same to the archive. + * + * @var string|array + * If given a string, should contain the relative filesystem path to the + * the item to store in archive; this will also be used as the item's + * path in the archive, so absolute paths should not be used here. + * If given an array, the key of each item should be the path to store + * in the archive, and the value should be the filesystem path to the + * item to store. + * @return $this + */ + public function add($item) + { + if (is_array($item)) { + $this->items = array_merge($this->items, $item); + } else { + $this->addFile($item, $item); + } + + return $this; + } + + /** + * Create a zip archive for distribution. + * + * @return \Robo\Result + * + * @since 1.0 + */ + public function run() + { + $this->startTimer(); + + // Use the file extension to determine what kind of archive to create. + $fileInfo = new \SplFileInfo($this->archiveFile); + $extension = strtolower($fileInfo->getExtension()); + if (empty($extension)) { + return Result::error($this, "Archive filename must use an extension (e.g. '.zip') to specify the kind of archive to create."); + } + + try { + // Inform the user which archive we are creating + $this->printTaskInfo("Creating archive {filename}", ['filename' => $this->archiveFile]); + if ($extension == 'zip') { + $result = $this->archiveZip($this->archiveFile, $this->items); + } else { + $result = $this->archiveTar($this->archiveFile, $this->items); + } + $this->printTaskSuccess("{filename} created.", ['filename' => $this->archiveFile]); + } catch (\Exception $e) { + $this->printTaskError("Could not create {filename}. {exception}", ['filename' => $this->archiveFile, 'exception' => $e->getMessage(), '_style' => ['exception' => '']]); + $result = Result::error($this, sprintf('Could not create %s. %s', $this->archiveFile, $e->getMessage())); + } + $this->stopTimer(); + $result['time'] = $this->getExecutionTime(); + + return $result; + } + + /** + * @param string $archiveFile + * @param array $items + * + * @return \Robo\Result + */ + protected function archiveTar($archiveFile, $items) + { + if (!class_exists('Archive_Tar')) { + return Result::errorMissingPackage($this, 'Archive_Tar', 'pear/archive_tar'); + } + + $tar_object = new \Archive_Tar($archiveFile); + foreach ($items as $placementLocation => $filesystemLocation) { + $p_remove_dir = $filesystemLocation; + $p_add_dir = $placementLocation; + if (is_file($filesystemLocation)) { + $p_remove_dir = dirname($filesystemLocation); + $p_add_dir = dirname($placementLocation); + if (basename($filesystemLocation) != basename($placementLocation)) { + return Result::error($this, "Tar archiver does not support renaming files during extraction; could not add $filesystemLocation as $placementLocation."); + } + } + + if (!$tar_object->addModify([$filesystemLocation], $p_add_dir, $p_remove_dir)) { + return Result::error($this, "Could not add $filesystemLocation to the archive."); + } + } + + return Result::success($this); + } + + /** + * @param string $archiveFile + * @param array $items + * + * @return \Robo\Result + */ + protected function archiveZip($archiveFile, $items) + { + if (!extension_loaded('zlib')) { + return Result::errorMissingExtension($this, 'zlib', 'zip packing'); + } + + $zip = new \ZipArchive($archiveFile, \ZipArchive::CREATE); + if (!$zip->open($archiveFile, \ZipArchive::CREATE)) { + return Result::error($this, "Could not create zip archive {$archiveFile}"); + } + $result = $this->addItemsToZip($zip, $items); + $zip->close(); + + return $result; + } + + /** + * @param \ZipArchive $zip + * @param array $items + * + * @return \Robo\Result + */ + protected function addItemsToZip($zip, $items) + { + foreach ($items as $placementLocation => $filesystemLocation) { + if (is_dir($filesystemLocation)) { + $finder = new Finder(); + $finder->files()->in($filesystemLocation)->ignoreDotFiles(false); + + foreach ($finder as $file) { + // Replace Windows slashes or resulting zip will have issues on *nixes. + $relativePathname = str_replace('\\', '/', $file->getRelativePathname()); + + if (!$zip->addFile($file->getRealpath(), "{$placementLocation}/{$relativePathname}")) { + return Result::error($this, "Could not add directory $filesystemLocation to the archive; error adding {$file->getRealpath()}."); + } + } + } elseif (is_file($filesystemLocation)) { + if (!$zip->addFile($filesystemLocation, $placementLocation)) { + return Result::error($this, "Could not add file $filesystemLocation to the archive."); + } + } else { + return Result::error($this, "Could not find $filesystemLocation for the archive."); + } + } + + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/loadTasks.php new file mode 100644 index 00000000..cf846fdf --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Archive/loadTasks.php @@ -0,0 +1,25 @@ +task(Pack::class, $filename); + } + + /** + * @param $filename + * + * @return Extract + */ + protected function taskExtract($filename) + { + return $this->task(Extract::class, $filename); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/CssPreprocessor.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/CssPreprocessor.php new file mode 100644 index 00000000..a15d2078 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/CssPreprocessor.php @@ -0,0 +1,214 @@ +files = $input; + + $this->setDefaultCompiler(); + } + + protected function setDefaultCompiler() + { + if (isset($this->compilers[0])) { + //set first compiler as default + $this->compiler = $this->compilers[0]; + } + } + + /** + * Sets import directories + * Alias for setImportPaths + * @see CssPreprocessor::setImportPaths + * + * @param array|string $dirs + * + * @return $this + */ + public function importDir($dirs) + { + return $this->setImportPaths($dirs); + } + + /** + * Adds import directory + * + * @param string $dir + * + * @return $this + */ + public function addImportPath($dir) + { + if (!isset($this->compilerOptions['importDirs'])) { + $this->compilerOptions['importDirs'] = []; + } + + if (!in_array($dir, $this->compilerOptions['importDirs'], true)) { + $this->compilerOptions['importDirs'][] = $dir; + } + + return $this; + } + + /** + * Sets import directories + * + * @param array|string $dirs + * + * @return $this + */ + public function setImportPaths($dirs) + { + if (!is_array($dirs)) { + $dirs = [$dirs]; + } + + $this->compilerOptions['importDirs'] = $dirs; + + return $this; + } + + /** + * @param string $formatterName + * + * @return $this + */ + public function setFormatter($formatterName) + { + $this->compilerOptions['formatter'] = $formatterName; + + return $this; + } + + /** + * Sets the compiler. + * + * @param string $compiler + * @param array $options + * + * @return $this + */ + public function compiler($compiler, array $options = []) + { + $this->compiler = $compiler; + $this->compilerOptions = array_merge($this->compilerOptions, $options); + + return $this; + } + + /** + * Compiles file + * + * @param $file + * + * @return bool|mixed + */ + protected function compile($file) + { + if (is_callable($this->compiler)) { + return call_user_func($this->compiler, $file, $this->compilerOptions); + } + + if (method_exists($this, $this->compiler)) { + return $this->{$this->compiler}($file); + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!in_array($this->compiler, $this->compilers, true) + && !is_callable($this->compiler) + ) { + $message = sprintf('Invalid ' . static::FORMAT_NAME . ' compiler %s!', $this->compiler); + + return Result::error($this, $message); + } + + foreach ($this->files as $in => $out) { + if (!file_exists($in)) { + $message = sprintf('File %s not found.', $in); + + return Result::error($this, $message); + } + if (file_exists($out) && !is_writable($out)) { + return Result::error($this, 'Destination already exists and cannot be overwritten.'); + } + } + + foreach ($this->files as $in => $out) { + $css = $this->compile($in); + + if ($css instanceof Result) { + return $css; + } elseif (false === $css) { + $message = sprintf( + ucfirst(static::FORMAT_NAME) . ' compilation failed for %s.', + $in + ); + + return Result::error($this, $message); + } + + $dst = $out . '.part'; + $write_result = file_put_contents($dst, $css); + + if (false === $write_result) { + $message = sprintf('File write failed: %s', $out); + + @unlink($dst); + return Result::error($this, $message); + } + + // Cannot be cross-volume: should always succeed + @rename($dst, $out); + + $this->printTaskSuccess('Wrote CSS to {filename}', ['filename' => $out]); + } + + return Result::success($this, 'All ' . static::FORMAT_NAME . ' files compiled.'); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/ImageMinify.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/ImageMinify.php new file mode 100644 index 00000000..1aa62593 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/ImageMinify.php @@ -0,0 +1,716 @@ +taskImageMinify('assets/images/*') + * ->to('dist/images/') + * ->run(); + * ``` + * + * This will use the following minifiers: + * + * - PNG: optipng + * - GIF: gifsicle + * - JPG, JPEG: jpegtran + * - SVG: svgo + * + * When the minifier is specified the task will use that for all the input files. In that case + * it is useful to filter the files with the extension: + * + * ```php + * $this->taskImageMinify('assets/images/*.png') + * ->to('dist/images/') + * ->minifier('pngcrush'); + * ->run(); + * ``` + * + * The task supports the following minifiers: + * + * - optipng + * - pngquant + * - advpng + * - pngout + * - zopflipng + * - pngcrush + * - gifsicle + * - jpegoptim + * - jpeg-recompress + * - jpegtran + * - svgo (only minification, no downloading) + * + * You can also specifiy extra options for the minifiers: + * + * ```php + * $this->taskImageMinify('assets/images/*.jpg') + * ->to('dist/images/') + * ->minifier('jpegtran', ['-progressive' => null, '-copy' => 'none']) + * ->run(); + * ``` + * + * This will execute as: + * `jpegtran -copy none -progressive -optimize -outfile "dist/images/test.jpg" "/var/www/test/assets/images/test.jpg"` + */ +class ImageMinify extends BaseTask +{ + /** + * Destination directory for the minified images. + * + * @var string + */ + protected $to; + + /** + * Array of the source files. + * + * @var array + */ + protected $dirs = []; + + /** + * Symfony 2 filesystem. + * + * @var sfFilesystem + */ + protected $fs; + + /** + * Target directory for the downloaded binary executables. + * + * @var string + */ + protected $executableTargetDir; + + /** + * Array for the downloaded binary executables. + * + * @var array + */ + protected $executablePaths = []; + + /** + * Array for the individual results of all the files. + * + * @var array + */ + protected $results = []; + + /** + * Default minifier to use. + * + * @var string + */ + protected $minifier; + + /** + * Array for minifier options. + * + * @var array + */ + protected $minifierOptions = []; + + /** + * Supported minifiers. + * + * @var array + */ + protected $minifiers = [ + // Default 4 + 'optipng', + 'gifsicle', + 'jpegtran', + 'svgo', + // PNG + 'pngquant', + 'advpng', + 'pngout', + 'zopflipng', + 'pngcrush', + // JPG + 'jpegoptim', + 'jpeg-recompress', + ]; + + /** + * Binary repositories of Imagemin. + * + * @link https://github.com/imagemin + * + * @var array + */ + protected $imageminRepos = [ + // PNG + 'optipng' => 'https://github.com/imagemin/optipng-bin', + 'pngquant' => 'https://github.com/imagemin/pngquant-bin', + 'advpng' => 'https://github.com/imagemin/advpng-bin', + 'pngout' => 'https://github.com/imagemin/pngout-bin', + 'zopflipng' => 'https://github.com/imagemin/zopflipng-bin', + 'pngcrush' => 'https://github.com/imagemin/pngcrush-bin', + // Gif + 'gifsicle' => 'https://github.com/imagemin/gifsicle-bin', + // JPG + 'jpegtran' => 'https://github.com/imagemin/jpegtran-bin', + 'jpegoptim' => 'https://github.com/imagemin/jpegoptim-bin', + 'cjpeg' => 'https://github.com/imagemin/mozjpeg-bin', // note: we do not support this minifier because it creates JPG from non-JPG files + 'jpeg-recompress' => 'https://github.com/imagemin/jpeg-recompress-bin', + // WebP + 'cwebp' => 'https://github.com/imagemin/cwebp-bin', // note: we do not support this minifier because it creates WebP from non-WebP files + ]; + + public function __construct($dirs) + { + is_array($dirs) + ? $this->dirs = $dirs + : $this->dirs[] = $dirs; + + $this->fs = new sfFilesystem(); + + // guess the best path for the executables based on __DIR__ + if (($pos = strpos(__DIR__, 'consolidation/robo')) !== false) { + // the executables should be stored in vendor/bin + $this->executableTargetDir = substr(__DIR__, 0, $pos).'bin'; + } + + // check if the executables are already available + foreach ($this->imageminRepos as $exec => $url) { + $path = $this->executableTargetDir.'/'.$exec; + // if this is Windows add a .exe extension + if (substr($this->getOS(), 0, 3) == 'win') { + $path .= '.exe'; + } + if (is_file($path)) { + $this->executablePaths[$exec] = $path; + } + } + } + + /** + * {@inheritdoc} + */ + public function run() + { + // find the files + $files = $this->findFiles($this->dirs); + + // minify the files + $result = $this->minify($files); + // check if there was an error + if ($result instanceof Result) { + return $result; + } + + $amount = (count($files) == 1 ? 'image' : 'images'); + $message = "Minified {filecount} out of {filetotal} $amount into {destination}"; + $context = ['filecount' => count($this->results['success']), 'filetotal' => count($files), 'destination' => $this->to]; + + if (count($this->results['success']) == count($files)) { + $this->printTaskSuccess($message, $context); + + return Result::success($this, $message, $context); + } else { + return Result::error($this, $message, $context); + } + } + + /** + * Sets the target directory where the files will be copied to. + * + * @param string $target + * + * @return $this + */ + public function to($target) + { + $this->to = rtrim($target, '/'); + + return $this; + } + + /** + * Sets the minifier. + * + * @param string $minifier + * @param array $options + * + * @return $this + */ + public function minifier($minifier, array $options = []) + { + $this->minifier = $minifier; + $this->minifierOptions = array_merge($this->minifierOptions, $options); + + return $this; + } + + /** + * @param array $dirs + * + * @return array|\Robo\Result + * + * @throws \Robo\Exception\TaskException + */ + protected function findFiles($dirs) + { + $files = array(); + + // find the files + foreach ($dirs as $k => $v) { + // reset finder + $finder = new Finder(); + + $dir = $k; + $to = $v; + // check if target was given with the to() method instead of key/value pairs + if (is_int($k)) { + $dir = $v; + if (isset($this->to)) { + $to = $this->to; + } else { + throw new TaskException($this, 'target directory is not defined'); + } + } + + try { + $finder->files()->in($dir); + } catch (\InvalidArgumentException $e) { + // if finder cannot handle it, try with in()->name() + if (strpos($dir, '/') === false) { + $dir = './'.$dir; + } + $parts = explode('/', $dir); + $new_dir = implode('/', array_slice($parts, 0, -1)); + try { + $finder->files()->in($new_dir)->name(array_pop($parts)); + } catch (\InvalidArgumentException $e) { + return Result::fromException($this, $e); + } + } + + foreach ($finder as $file) { + // store the absolute path as key and target as value in the files array + $files[$file->getRealpath()] = $this->getTarget($file->getRealPath(), $to); + } + $fileNoun = count($finder) == 1 ? ' file' : ' files'; + $this->printTaskInfo("Found {filecount} $fileNoun in {dir}", ['filecount' => count($finder), 'dir' => $dir]); + } + + return $files; + } + + /** + * @param string $file + * @param string $to + * + * @return string + */ + protected function getTarget($file, $to) + { + $target = $to.'/'.basename($file); + + return $target; + } + + /** + * @param array $files + * + * @return \Robo\Result + */ + protected function minify($files) + { + // store the individual results into the results array + $this->results = [ + 'success' => [], + 'error' => [], + ]; + + // loop through the files + foreach ($files as $from => $to) { + if (!isset($this->minifier)) { + // check filetype based on the extension + $extension = strtolower(pathinfo($from, PATHINFO_EXTENSION)); + + // set the default minifiers based on the extension + switch ($extension) { + case 'png': + $minifier = 'optipng'; + break; + case 'jpg': + case 'jpeg': + $minifier = 'jpegtran'; + break; + case 'gif': + $minifier = 'gifsicle'; + break; + case 'svg': + $minifier = 'svgo'; + break; + } + } else { + if (!in_array($this->minifier, $this->minifiers, true) + && !is_callable(strtr($this->minifier, '-', '_')) + ) { + $message = sprintf('Invalid minifier %s!', $this->minifier); + + return Result::error($this, $message); + } + $minifier = $this->minifier; + } + + // Convert minifier name to camelCase (e.g. jpeg-recompress) + $funcMinifier = $this->camelCase($minifier); + + // call the minifier method which prepares the command + if (is_callable($funcMinifier)) { + $command = call_user_func($funcMinifier, $from, $to, $this->minifierOptions); + } elseif (method_exists($this, $funcMinifier)) { + $command = $this->{$funcMinifier}($from, $to); + } else { + $message = sprintf('Minifier method %s cannot be found!', $funcMinifier); + + return Result::error($this, $message); + } + + // launch the command + $this->printTaskInfo('Minifying {filepath} with {minifier}', ['filepath' => $from, 'minifier' => $minifier]); + $result = $this->executeCommand($command); + + // check the return code + if ($result->getExitCode() == 127) { + $this->printTaskError('The {minifier} executable cannot be found', ['minifier' => $minifier]); + // try to install from imagemin repository + if (array_key_exists($minifier, $this->imageminRepos)) { + $result = $this->installFromImagemin($minifier); + if ($result instanceof Result) { + if ($result->wasSuccessful()) { + $this->printTaskSuccess($result->getMessage()); + // retry the conversion with the downloaded executable + if (is_callable($minifier)) { + $command = call_user_func($minifier, $from, $to, $minifierOptions); + } elseif (method_exists($this, $minifier)) { + $command = $this->{$minifier}($from, $to); + } + // launch the command + $this->printTaskInfo('Minifying {filepath} with {minifier}', ['filepath' => $from, 'minifier' => $minifier]); + $result = $this->executeCommand($command); + } else { + $this->printTaskError($result->getMessage()); + // the download was not successful + return $result; + } + } + } else { + return $result; + } + } + + // check the success of the conversion + if ($result->getExitCode() !== 0) { + $this->results['error'][] = $from; + } else { + $this->results['success'][] = $from; + } + } + } + + /** + * @return string + */ + protected function getOS() + { + $os = php_uname('s'); + $os .= '/'.php_uname('m'); + // replace x86_64 to x64, because the imagemin repo uses that + $os = str_replace('x86_64', 'x64', $os); + // replace i386, i686, etc to x86, because of imagemin + $os = preg_replace('/i[0-9]86/', 'x86', $os); + // turn info to lowercase, because of imagemin + $os = strtolower($os); + + return $os; + } + + /** + * @param string $command + * + * @return \Robo\Result + */ + protected function executeCommand($command) + { + // insert the options into the command + $a = explode(' ', $command); + $executable = array_shift($a); + foreach ($this->minifierOptions as $key => $value) { + // first prepend the value + if (!empty($value)) { + array_unshift($a, $value); + } + // then add the key + if (!is_numeric($key)) { + array_unshift($a, $key); + } + } + // check if the executable can be replaced with the downloaded one + if (array_key_exists($executable, $this->executablePaths)) { + $executable = $this->executablePaths[$executable]; + } + array_unshift($a, $executable); + $command = implode(' ', $a); + + // execute the command + $exec = new Exec($command); + + return $exec->inflect($this)->printed(false)->run(); + } + + /** + * @param string $executable + * + * @return \Robo\Result + */ + protected function installFromImagemin($executable) + { + // check if there is an url defined for the executable + if (!array_key_exists($executable, $this->imageminRepos)) { + $message = sprintf('The executable %s cannot be found in the defined imagemin repositories', $executable); + + return Result::error($this, $message); + } + $this->printTaskInfo('Downloading the {executable} executable from the imagemin repository', ['executable' => $executable]); + + $os = $this->getOS(); + $url = $this->imageminRepos[$executable].'/blob/master/vendor/'.$os.'/'.$executable.'?raw=true'; + if (substr($os, 0, 3) == 'win') { + // if it is win, add a .exe extension + $url = $this->imageminRepos[$executable].'/blob/master/vendor/'.$os.'/'.$executable.'.exe?raw=true'; + } + $data = @file_get_contents($url, false, null); + if ($data === false) { + // there is something wrong with the url, try it without the version info + $url = preg_replace('/x[68][64]\//', '', $url); + $data = @file_get_contents($url, false, null); + if ($data === false) { + // there is still something wrong with the url if it is win, try with win32 + if (substr($os, 0, 3) == 'win') { + $url = preg_replace('win/', 'win32/', $url); + $data = @file_get_contents($url, false, null); + if ($data === false) { + // there is nothing more we can do + $message = sprintf('Could not download the executable %s', $executable); + + return Result::error($this, $message); + } + } + // if it is not windows there is nothing we can do + $message = sprintf('Could not download the executable %s', $executable); + + return Result::error($this, $message); + } + } + // check if target directory exists + if (!is_dir($this->executableTargetDir)) { + mkdir($this->executableTargetDir); + } + // save the executable into the target dir + $path = $this->executableTargetDir.'/'.$executable; + if (substr($os, 0, 3) == 'win') { + // if it is win, add a .exe extension + $path = $this->executableTargetDir.'/'.$executable.'.exe'; + } + $result = file_put_contents($path, $data); + if ($result === false) { + $message = sprintf('Could not copy the executable %s to %s', $executable, $target_dir); + + return Result::error($this, $message); + } + // set the binary to executable + chmod($path, 0755); + + // if everything successful, store the executable path + $this->executablePaths[$executable] = $this->executableTargetDir.'/'.$executable; + // if it is win, add a .exe extension + if (substr($os, 0, 3) == 'win') { + $this->executablePaths[$executable] .= '.exe'; + } + + $message = sprintf('Executable %s successfully downloaded', $executable); + + return Result::success($this, $message); + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function optipng($from, $to) + { + $command = sprintf('optipng -quiet -out "%s" -- "%s"', $to, $from); + if ($from != $to && is_file($to)) { + // earlier versions of optipng do not overwrite the target without a backup + // http://sourceforge.net/p/optipng/bugs/37/ + unlink($to); + } + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function jpegtran($from, $to) + { + $command = sprintf('jpegtran -optimize -outfile "%s" "%s"', $to, $from); + + return $command; + } + + protected function gifsicle($from, $to) + { + $command = sprintf('gifsicle -o "%s" "%s"', $to, $from); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function svgo($from, $to) + { + $command = sprintf('svgo "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function pngquant($from, $to) + { + $command = sprintf('pngquant --force --output "%s" "%s"', $to, $from); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function advpng($from, $to) + { + // advpng does not have any output parameters, copy the file and then compress the copy + $command = sprintf('advpng --recompress --quiet "%s"', $to); + $this->fs->copy($from, $to, true); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function pngout($from, $to) + { + $command = sprintf('pngout -y -q "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function zopflipng($from, $to) + { + $command = sprintf('zopflipng -y "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function pngcrush($from, $to) + { + $command = sprintf('pngcrush -q -ow "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function jpegoptim($from, $to) + { + // jpegoptim only takes the destination directory as an argument + $command = sprintf('jpegoptim --quiet -o --dest "%s" "%s"', dirname($to), $from); + + return $command; + } + + /** + * @param string $from + * @param string $to + * + * @return string + */ + protected function jpegRecompress($from, $to) + { + $command = sprintf('jpeg-recompress --quiet "%s" "%s"', $from, $to); + + return $command; + } + + /** + * @param string $text + * + * @return string + */ + public static function camelCase($text) + { + // non-alpha and non-numeric characters become spaces + $text = preg_replace('/[^a-z0-9]+/i', ' ', $text); + $text = trim($text); + // uppercase the first character of each word + $text = ucwords($text); + $text = str_replace(" ", "", $text); + $text = lcfirst($text); + + return $text; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Less.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Less.php new file mode 100644 index 00000000..4cfa0978 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Less.php @@ -0,0 +1,108 @@ +taskLess([ + * 'less/default.less' => 'css/default.css' + * ]) + * ->run(); + * ?> + * ``` + * + * Use one of both less compilers in your project: + * + * ``` + * "leafo/lessphp": "~0.5", + * "oyejorge/less.php": "~1.5" + * ``` + * + * Specify directory (string or array) for less imports lookup: + * + * ```php + * taskLess([ + * 'less/default.less' => 'css/default.css' + * ]) + * ->importDir('less') + * ->compiler('lessphp') + * ->run(); + * ?> + * ``` + * + * You can implement additional compilers by extending this task and adding a + * method named after them and overloading the lessCompilers() method to + * inject the name there. + */ +class Less extends CssPreprocessor +{ + const FORMAT_NAME = 'less'; + + /** + * @var string[] + */ + protected $compilers = [ + 'less', // https://github.com/oyejorge/less.php + 'lessphp', //https://github.com/leafo/lessphp + ]; + + /** + * lessphp compiler + * @link https://github.com/leafo/lessphp + * + * @param string $file + * + * @return string + */ + protected function lessphp($file) + { + if (!class_exists('\lessc')) { + return Result::errorMissingPackage($this, 'lessc', 'leafo/lessphp'); + } + + $lessCode = file_get_contents($file); + + $less = new \lessc(); + if (isset($this->compilerOptions['importDirs'])) { + $less->setImportDir($this->compilerOptions['importDirs']); + } + + return $less->compile($lessCode); + } + + /** + * less compiler + * @link https://github.com/oyejorge/less.php + * + * @param string $file + * + * @return string + */ + protected function less($file) + { + if (!class_exists('\Less_Parser')) { + return Result::errorMissingPackage($this, 'Less_Parser', 'oyejorge/less.php'); + } + + $lessCode = file_get_contents($file); + + $parser = new \Less_Parser(); + $parser->SetOptions($this->compilerOptions); + if (isset($this->compilerOptions['importDirs'])) { + $importDirs = []; + foreach ($this->compilerOptions['importDirs'] as $dir) { + $importDirs[$dir] = $dir; + } + $parser->SetImportDirs($importDirs); + } + + $parser->parse($lessCode); + + return $parser->getCss(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Minify.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Minify.php new file mode 100644 index 00000000..3187714e --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Minify.php @@ -0,0 +1,297 @@ +taskMinify( 'web/assets/theme.css' ) + * ->run() + * ?> + * ``` + * Please install additional dependencies to use: + * + * ``` + * "patchwork/jsqueeze": "~1.0", + * "natxet/CssMin": "~3.0" + * ``` + */ +class Minify extends BaseTask +{ + /** + * @var array + */ + protected $types = ['css', 'js']; + + /** + * @var string + */ + protected $text; + + /** + * @var string + */ + protected $dst; + + /** + * @var string + */ + protected $type; + + /** + * @var array + */ + protected $squeezeOptions = [ + 'singleLine' => true, + 'keepImportantComments' => true, + 'specialVarRx' => false, + ]; + + /** + * Constructor. Accepts asset file path or string source. + * + * @param string $input + */ + public function __construct($input) + { + if (file_exists($input)) { + $this->fromFile($input); + return; + } + + $this->fromText($input); + } + + /** + * Sets destination. Tries to guess type from it. + * + * @param string $dst + * + * @return $this + */ + public function to($dst) + { + $this->dst = $dst; + + if (!empty($this->dst) && empty($this->type)) { + $this->type($this->getExtension($this->dst)); + } + + return $this; + } + + /** + * Sets type with validation. + * + * @param string $type css|js + * + * @return $this + */ + public function type($type) + { + $type = strtolower($type); + + if (in_array($type, $this->types)) { + $this->type = $type; + } + + return $this; + } + + /** + * Sets text from string source. + * + * @param string $text + * + * @return $this + */ + protected function fromText($text) + { + $this->text = (string)$text; + unset($this->type); + + return $this; + } + + /** + * Sets text from asset file path. Tries to guess type and set default destination. + * + * @param string $path + * + * @return $this + */ + protected function fromFile($path) + { + $this->text = file_get_contents($path); + + unset($this->type); + $this->type($this->getExtension($path)); + + if (empty($this->dst) && !empty($this->type)) { + $ext_length = strlen($this->type) + 1; + $this->dst = substr($path, 0, -$ext_length) . '.min.' . $this->type; + } + + return $this; + } + + /** + * Gets file extension from path. + * + * @param string $path + * + * @return string + */ + protected function getExtension($path) + { + return pathinfo($path, PATHINFO_EXTENSION); + } + + /** + * Minifies and returns text. + * + * @return string|bool + */ + protected function getMinifiedText() + { + switch ($this->type) { + case 'css': + if (!class_exists('\CssMin')) { + return Result::errorMissingPackage($this, 'CssMin', 'natxet/CssMin'); + } + + return \CssMin::minify($this->text); + break; + + case 'js': + if (!class_exists('\JSqueeze') && !class_exists('\Patchwork\JSqueeze')) { + return Result::errorMissingPackage($this, 'Patchwork\JSqueeze', 'patchwork/jsqueeze'); + } + + if (class_exists('\JSqueeze')) { + $jsqueeze = new \JSqueeze(); + } else { + $jsqueeze = new \Patchwork\JSqueeze(); + } + + return $jsqueeze->squeeze( + $this->text, + $this->squeezeOptions['singleLine'], + $this->squeezeOptions['keepImportantComments'], + $this->squeezeOptions['specialVarRx'] + ); + break; + } + + return false; + } + + /** + * Single line option for the JS minimisation. + * + * @param bool $singleLine + * + * @return $this + */ + public function singleLine($singleLine) + { + $this->squeezeOptions['singleLine'] = (bool)$singleLine; + return $this; + } + + /** + * keepImportantComments option for the JS minimisation. + * + * @param bool $keepImportantComments + * + * @return $this + */ + public function keepImportantComments($keepImportantComments) + { + $this->squeezeOptions['keepImportantComments'] = (bool)$keepImportantComments; + return $this; + } + + /** + * specialVarRx option for the JS minimisation. + * + * @param bool $specialVarRx + * + * @return $this ; + */ + public function specialVarRx($specialVarRx) + { + $this->squeezeOptions['specialVarRx'] = (bool)$specialVarRx; + return $this; + } + + /** + * @return string + */ + public function __toString() + { + return (string) $this->getMinifiedText(); + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (empty($this->type)) { + return Result::error($this, 'Unknown asset type.'); + } + + if (empty($this->dst)) { + return Result::error($this, 'Unknown file destination.'); + } + + if (file_exists($this->dst) && !is_writable($this->dst)) { + return Result::error($this, 'Destination already exists and cannot be overwritten.'); + } + + $size_before = strlen($this->text); + $minified = $this->getMinifiedText(); + + if ($minified instanceof Result) { + return $minified; + } elseif (false === $minified) { + return Result::error($this, 'Minification failed.'); + } + + $size_after = strlen($minified); + + // Minification did not reduce file size, so use original file. + if ($size_after > $size_before) { + $minified = $this->text; + $size_after = $size_before; + } + + $dst = $this->dst . '.part'; + $write_result = file_put_contents($dst, $minified); + + if (false === $write_result) { + @unlink($dst); + return Result::error($this, 'File write failed.'); + } + // Cannot be cross-volume; should always succeed. + @rename($dst, $this->dst); + if ($size_before === 0) { + $minified_percent = 0; + } else { + $minified_percent = number_format(100 - ($size_after / $size_before * 100), 1); + } + $this->printTaskSuccess('Wrote {filepath}', ['filepath' => $this->dst]); + $context = [ + 'bytes' => $this->formatBytes($size_after), + 'reduction' => $this->formatBytes(($size_before - $size_after)), + 'percentage' => $minified_percent, + ]; + $this->printTaskSuccess('Wrote {bytes} (reduced by {reduction} / {percentage})', $context); + return Result::success($this, 'Asset minified.'); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Scss.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Scss.php new file mode 100644 index 00000000..ffd39345 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/Scss.php @@ -0,0 +1,93 @@ +taskScss([ + * 'scss/default.scss' => 'css/default.css' + * ]) + * ->importDir('assets/styles') + * ->run(); + * ?> + * ``` + * + * Use the following scss compiler in your project: + * + * ``` + * "leafo/scssphp": "~0.1", + * ``` + * + * You can implement additional compilers by extending this task and adding a + * method named after them and overloading the scssCompilers() method to + * inject the name there. + */ +class Scss extends CssPreprocessor +{ + const FORMAT_NAME = 'scss'; + + /** + * @var string[] + */ + protected $compilers = [ + 'scssphp', // https://github.com/leafo/scssphp + ]; + + /** + * scssphp compiler + * @link https://github.com/leafo/scssphp + * + * @param string $file + * + * @return string + */ + protected function scssphp($file) + { + if (!class_exists('\Leafo\ScssPhp\Compiler')) { + return Result::errorMissingPackage($this, 'scssphp', 'leafo/scssphp'); + } + + $scssCode = file_get_contents($file); + $scss = new \Leafo\ScssPhp\Compiler(); + + // set options for the scssphp compiler + if (isset($this->compilerOptions['importDirs'])) { + $scss->setImportPaths($this->compilerOptions['importDirs']); + } + + if (isset($this->compilerOptions['formatter'])) { + $scss->setFormatter($this->compilerOptions['formatter']); + } + + return $scss->compile($scssCode); + } + + /** + * Sets the formatter for scssphp + * + * The method setFormatter($formatterName) sets the current formatter to $formatterName, + * the name of a class as a string that implements the formatting interface. See the source + * for Leafo\ScssPhp\Formatter\Expanded for an example. + * + * Five formatters are included with leafo/scssphp: + * - Leafo\ScssPhp\Formatter\Expanded + * - Leafo\ScssPhp\Formatter\Nested (default) + * - Leafo\ScssPhp\Formatter\Compressed + * - Leafo\ScssPhp\Formatter\Compact + * - Leafo\ScssPhp\Formatter\Crunched + * + * @link http://leafo.github.io/scssphp/docs/#output-formatting + * + * @param string $formatterName + * + * @return $this + */ + public function setFormatter($formatterName) + { + return parent::setFormatter($formatterName); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/loadTasks.php new file mode 100644 index 00000000..12192dd8 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Assets/loadTasks.php @@ -0,0 +1,45 @@ +task(Minify::class, $input); + } + + /** + * @param string|string[] $input + * + * @return \Robo\Task\Assets\ImageMinify + */ + protected function taskImageMinify($input) + { + return $this->task(ImageMinify::class, $input); + } + + /** + * @param array $input + * + * @return \Robo\Task\Assets\Less + */ + protected function taskLess($input) + { + return $this->task(Less::class, $input); + } + + /** + * @param array $input + * + * @return \Robo\Task\Assets\Scss + */ + protected function taskScss($input) + { + return $this->task(Scss::class, $input); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/Exec.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/Exec.php new file mode 100644 index 00000000..c3e47917 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/Exec.php @@ -0,0 +1,125 @@ +taskExec('compass')->arg('watch')->run(); + * // or use shortcut + * $this->_exec('compass watch'); + * + * $this->taskExec('compass watch')->background()->run(); + * + * if ($this->taskExec('phpunit .')->run()->wasSuccessful()) { + * $this->say('tests passed'); + * } + * + * ?> + * ``` + */ +class Exec extends BaseTask implements CommandInterface, PrintedInterface, SimulatedInterface +{ + use \Robo\Common\CommandReceiver; + use \Robo\Common\ExecOneCommand; + + /** + * @var static[] + */ + protected static $instances = []; + + /** + * @var string|\Robo\Contract\CommandInterface + */ + protected $command; + + /** + * @param string|\Robo\Contract\CommandInterface $command + */ + public function __construct($command) + { + $this->command = $this->receiveCommand($command); + } + + /** + * + */ + public function __destruct() + { + $this->stop(); + } + + /** + * Executes command in background mode (asynchronously) + * + * @return $this + */ + public function background($arg = true) + { + self::$instances[] = $this; + $this->background = $arg; + return $this; + } + + /** + * {@inheritdoc} + */ + protected function getCommandDescription() + { + return $this->getCommand(); + } + /** + * {@inheritdoc} + */ + public function getCommand() + { + return trim($this->command . $this->arguments); + } + + /** + * {@inheritdoc} + */ + public function simulate($context) + { + $this->printAction($context); + } + + public static function stopRunningJobs() + { + foreach (self::$instances as $instance) { + if ($instance) { + unset($instance); + } + } + } + + /** + * {@inheritdoc} + */ + public function run() + { + // TODO: Symfony 4 requires that we supply the working directory. + $result_data = $this->execute(new Process($this->getCommand(), getcwd())); + return new Result( + $this, + $result_data->getExitCode(), + $result_data->getMessage(), + $result_data->getData() + ); + } +} + +if (function_exists('pcntl_signal')) { + pcntl_signal(SIGTERM, ['Robo\Task\Base\Exec', 'stopRunningJobs']); +} + +register_shutdown_function(['Robo\Task\Base\Exec', 'stopRunningJobs']); diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/ExecStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/ExecStack.php new file mode 100644 index 00000000..51b39ef1 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/ExecStack.php @@ -0,0 +1,23 @@ +taskExecStack() + * ->stopOnFail() + * ->exec('mkdir site') + * ->exec('cd site') + * ->run(); + * + * ?> + * ``` + */ +class ExecStack extends CommandStack +{ +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/ParallelExec.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/ParallelExec.php new file mode 100644 index 00000000..c98b7841 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/ParallelExec.php @@ -0,0 +1,199 @@ +taskParallelExec() + * ->process('php ~/demos/script.php hey') + * ->process('php ~/demos/script.php hoy') + * ->process('php ~/demos/script.php gou') + * ->run(); + * ?> + * ``` + */ +class ParallelExec extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\CommandReceiver; + + /** + * @var Process[] + */ + protected $processes = []; + + /** + * @var null|int + */ + protected $timeout = null; + + /** + * @var null|int + */ + protected $idleTimeout = null; + + /** + * @var null|int + */ + protected $waitInterval = 0; + + /** + * @var bool + */ + protected $isPrinted = false; + + /** + * {@inheritdoc} + */ + public function getPrinted() + { + return $this->isPrinted; + } + + /** + * @param bool $isPrinted + * + * @return $this + */ + public function printed($isPrinted = true) + { + $this->isPrinted = $isPrinted; + return $this; + } + + /** + * @param string|\Robo\Contract\CommandInterface $command + * + * @return $this + */ + public function process($command) + { + // TODO: Symfony 4 requires that we supply the working directory. + $this->processes[] = new Process($this->receiveCommand($command), getcwd()); + return $this; + } + + /** + * Stops process if it runs longer then `$timeout` (seconds). + * + * @param int $timeout + * + * @return $this + */ + public function timeout($timeout) + { + $this->timeout = $timeout; + return $this; + } + + /** + * Stops process if it does not output for time longer then `$timeout` (seconds). + * + * @param int $idleTimeout + * + * @return $this + */ + public function idleTimeout($idleTimeout) + { + $this->idleTimeout = $idleTimeout; + return $this; + } + + /** + * Parallel processing will wait `$waitInterval` seconds after launching each process and before + * the next one. + * + * @param int $waitInterval + * + * @return $this + */ + public function waitInterval($waitInterval) + { + $this->waitInterval = $waitInterval; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return implode(' && ', $this->processes); + } + + /** + * @return int + */ + public function progressIndicatorSteps() + { + return count($this->processes); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->startProgressIndicator(); + $running = []; + $queue = $this->processes; + $nextTime = time(); + while (true) { + if (($nextTime <= time()) && !empty($queue)) { + $process = array_shift($queue); + $process->setIdleTimeout($this->idleTimeout); + $process->setTimeout($this->timeout); + $process->start(); + $this->printTaskInfo($process->getCommandLine()); + $running[] = $process; + $nextTime = time() + $this->waitInterval; + } + foreach ($running as $k => $process) { + try { + $process->checkTimeout(); + } catch (ProcessTimedOutException $e) { + $this->printTaskWarning("Process timed out for {command}", ['command' => $process->getCommandLine(), '_style' => ['command' => 'fg=white;bg=magenta']]); + } + if (!$process->isRunning()) { + $this->advanceProgressIndicator(); + if ($this->isPrinted) { + $this->printTaskInfo("Output for {command}:\n\n{output}", ['command' => $process->getCommandLine(), 'output' => $process->getOutput(), '_style' => ['command' => 'fg=white;bg=magenta']]); + $errorOutput = $process->getErrorOutput(); + if ($errorOutput) { + $this->printTaskError(rtrim($errorOutput)); + } + } + unset($running[$k]); + } + } + if (empty($running) && empty($queue)) { + break; + } + usleep(1000); + } + $this->stopProgressIndicator(); + + $errorMessage = ''; + $exitCode = 0; + foreach ($this->processes as $p) { + if ($p->getExitCode() === 0) { + continue; + } + $errorMessage .= "'" . $p->getCommandLine() . "' exited with code ". $p->getExitCode()." \n"; + $exitCode = max($exitCode, $p->getExitCode()); + } + if (!$errorMessage) { + $this->printTaskSuccess('{process-count} processes finished running', ['process-count' => count($this->processes)]); + } + + return new Result($this, $exitCode, $errorMessage, ['time' => $this->getExecutionTime()]); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/SymfonyCommand.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/SymfonyCommand.php new file mode 100644 index 00000000..708ea845 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/SymfonyCommand.php @@ -0,0 +1,75 @@ +taskSymfonyCommand(new \Codeception\Command\Run('run')) + * ->arg('suite','acceptance') + * ->opt('debug') + * ->run(); + * + * // Artisan Command + * $this->taskSymfonyCommand(new ModelGeneratorCommand()) + * ->arg('name', 'User') + * ->run(); + * ?> + * ``` + */ +class SymfonyCommand extends BaseTask +{ + /** + * @var \Symfony\Component\Console\Command\Command + */ + protected $command; + + /** + * @var string[] + */ + protected $input; + + public function __construct(Command $command) + { + $this->command = $command; + $this->input = []; + } + + /** + * @param string $arg + * @param string $value + * + * @return $this + */ + public function arg($arg, $value) + { + $this->input[$arg] = $value; + return $this; + } + + public function opt($option, $value = null) + { + $this->input["--$option"] = $value; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running command {command}', ['command' => $this->command->getName()]); + return new Result( + $this, + $this->command->run(new ArrayInput($this->input), Robo::output()) + ); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/Watch.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/Watch.php new file mode 100644 index 00000000..d7940ac9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/Watch.php @@ -0,0 +1,89 @@ +taskWatch() + * ->monitor('composer.json', function() { + * $this->taskComposerUpdate()->run(); + * })->monitor('src', function() { + * $this->taskExec('phpunit')->run(); + * })->run(); + * ?> + * ``` + */ +class Watch extends BaseTask +{ + /** + * @var \Closure + */ + protected $closure; + + /** + * @var array + */ + protected $monitor = []; + + /** + * @var object + */ + protected $bindTo; + + /** + * @param $bindTo + */ + public function __construct($bindTo) + { + $this->bindTo = $bindTo; + } + + /** + * @param string|string[] $paths + * @param \Closure $callable + * + * @return $this + */ + public function monitor($paths, \Closure $callable) + { + if (!is_array($paths)) { + $paths = [$paths]; + } + $this->monitor[] = [$paths, $callable]; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!class_exists('Lurker\\ResourceWatcher')) { + return Result::errorMissingPackage($this, 'ResourceWatcher', 'henrikbjorn/lurker'); + } + + $watcher = new ResourceWatcher(); + + foreach ($this->monitor as $k => $monitor) { + /** @var \Closure $closure */ + $closure = $monitor[1]; + $closure->bindTo($this->bindTo); + foreach ($monitor[0] as $i => $dir) { + $watcher->track("fs.$k.$i", $dir, FilesystemEvent::MODIFY); + $this->printTaskInfo('Watching {dir} for changes...', ['dir' => $dir]); + $watcher->addListener("fs.$k.$i", $closure); + } + } + + $watcher->start(); + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/loadShortcuts.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/loadShortcuts.php new file mode 100644 index 00000000..dba0af66 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/loadShortcuts.php @@ -0,0 +1,17 @@ +taskExec($command)->run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/loadTasks.php new file mode 100644 index 00000000..ab5301bb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Base/loadTasks.php @@ -0,0 +1,48 @@ +task(Exec::class, $command); + } + + /** + * @return ExecStack + */ + protected function taskExecStack() + { + return $this->task(ExecStack::class); + } + + /** + * @return ParallelExec + */ + protected function taskParallelExec() + { + return $this->task(ParallelExec::class); + } + + /** + * @param $command + * @return SymfonyCommand + */ + protected function taskSymfonyCommand($command) + { + return $this->task(SymfonyCommand::class, $command); + } + + /** + * @return Watch + */ + protected function taskWatch() + { + return $this->task(Watch::class, $this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/BaseTask.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/BaseTask.php new file mode 100644 index 00000000..66155c09 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/BaseTask.php @@ -0,0 +1,60 @@ +logger) { + $child->setLogger($this->logger); + } + if ($child instanceof ProgressIndicatorAwareInterface && $this->progressIndicator) { + $child->setProgressIndicator($this->progressIndicator); + } + if ($child instanceof ConfigAwareInterface && $this->getConfig()) { + $child->setConfig($this->getConfig()); + } + if ($child instanceof VerbosityThresholdInterface && $this->outputAdapter()) { + $child->setOutputAdapter($this->outputAdapter()); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Base.php new file mode 100644 index 00000000..9bc614c6 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Base.php @@ -0,0 +1,88 @@ +option('allow-root'); + return $this; + } + + /** + * adds `force-latest` option to bower + * + * @return $this + */ + public function forceLatest() + { + $this->option('force-latest'); + return $this; + } + + /** + * adds `production` option to bower + * + * @return $this + */ + public function noDev() + { + $this->option('production'); + return $this; + } + + /** + * adds `offline` option to bower + * + * @return $this + */ + public function offline() + { + $this->option('offline'); + return $this; + } + + /** + * Base constructor. + * + * @param null|string $pathToBower + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToBower = null) + { + $this->command = $pathToBower; + if (!$this->command) { + $this->command = $this->findExecutable('bower'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Bower executable not found."); + } + } + + /** + * @return string + */ + public function getCommand() + { + return "{$this->command} {$this->action}{$this->arguments}"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Install.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Install.php new file mode 100644 index 00000000..c3c0ce75 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Install.php @@ -0,0 +1,36 @@ +taskBowerInstall()->run(); + * + * // prefer dist with custom path + * $this->taskBowerInstall('path/to/my/bower') + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class Install extends Base implements CommandInterface +{ + /** + * {@inheritdoc} + */ + protected $action = 'install'; + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Install Bower packages: {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Update.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Update.php new file mode 100644 index 00000000..f0dfa94e --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/Update.php @@ -0,0 +1,34 @@ +taskBowerUpdate->run(); + * + * // prefer dist with custom path + * $this->taskBowerUpdate('path/to/my/bower') + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class Update extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'update'; + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Update Bower packages: {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/loadTasks.php new file mode 100644 index 00000000..6e33f8ac --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Bower/loadTasks.php @@ -0,0 +1,25 @@ +task(Install::class, $pathToBower); + } + + /** + * @param null|string $pathToBower + * + * @return Update + */ + protected function taskBowerUpdate($pathToBower = null) + { + return $this->task(Update::class, $pathToBower); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/CommandStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/CommandStack.php new file mode 100644 index 00000000..f1cb4492 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/CommandStack.php @@ -0,0 +1,134 @@ +exec); + } + + /** + * @param string $executable + * + * @return $this + */ + public function executable($executable) + { + $this->executable = $executable; + return $this; + } + + /** + * @param string|string[] $command + * + * @return $this + */ + public function exec($command) + { + if (is_array($command)) { + $command = implode(' ', array_filter($command)); + } + + $command = $this->executable . ' ' . $this->stripExecutableFromCommand($command); + $this->exec[] = trim($command); + return $this; + } + + /** + * @param bool $stopOnFail + * + * @return $this + */ + public function stopOnFail($stopOnFail = true) + { + $this->stopOnFail = $stopOnFail; + return $this; + } + + public function result($result) + { + $this->result = $result; + return $this; + } + + /** + * @param string $command + * + * @return string + */ + protected function stripExecutableFromCommand($command) + { + $command = trim($command); + $executable = $this->executable . ' '; + if (strpos($command, $executable) === 0) { + $command = substr($command, strlen($executable)); + } + return $command; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (empty($this->exec)) { + throw new TaskException($this, 'You must add at least one command'); + } + // If 'stopOnFail' is not set, or if there is only one command to run, + // then execute the single command to run. + if (!$this->stopOnFail || (count($this->exec) == 1)) { + $this->printTaskInfo('{command}', ['command' => $this->getCommand()]); + return $this->executeCommand($this->getCommand()); + } + + // When executing multiple commands in 'stopOnFail' mode, run them + // one at a time so that the result will have the exact command + // that failed available to the caller. This is at the expense of + // losing the output from all successful commands. + $data = []; + $message = ''; + $result = null; + foreach ($this->exec as $command) { + $this->printTaskInfo("Executing {command}", ['command' => $command]); + $result = $this->executeCommand($command); + $result->accumulateExecutionTime($data); + $message = $result->accumulateMessage($message); + $data = $result->mergeData($data); + if (!$result->wasSuccessful()) { + return $result; + } + } + + return $result; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Base.php new file mode 100644 index 00000000..de3fe217 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Base.php @@ -0,0 +1,248 @@ +command = $pathToComposer; + if (!$this->command) { + $this->command = $this->findExecutablePhar('composer'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Neither local composer.phar nor global composer installation could be found."); + } + } + + /** + * adds `prefer-dist` option to composer + * + * @return $this + */ + public function preferDist($preferDist = true) + { + if (!$preferDist) { + return $this->preferSource(); + } + $this->prefer = '--prefer-dist'; + return $this; + } + + /** + * adds `prefer-source` option to composer + * + * @return $this + */ + public function preferSource() + { + $this->prefer = '--prefer-source'; + return $this; + } + + /** + * adds `dev` option to composer + * + * @return $this + */ + public function dev($dev = true) + { + if (!$dev) { + return $this->noDev(); + } + $this->dev = '--dev'; + return $this; + } + + /** + * adds `no-dev` option to composer + * + * @return $this + */ + public function noDev() + { + $this->dev = '--no-dev'; + return $this; + } + + /** + * adds `ansi` option to composer + * + * @return $this + */ + public function ansi($ansi = true) + { + if (!$ansi) { + return $this->noAnsi(); + } + $this->ansi = '--ansi'; + return $this; + } + + /** + * adds `no-ansi` option to composer + * + * @return $this + */ + public function noAnsi() + { + $this->ansi = '--no-ansi'; + return $this; + } + + public function interaction($interaction = true) + { + if (!$interaction) { + return $this->noInteraction(); + } + return $this; + } + + /** + * adds `no-interaction` option to composer + * + * @return $this + */ + public function noInteraction() + { + $this->nointeraction = '--no-interaction'; + return $this; + } + + /** + * adds `optimize-autoloader` option to composer + * + * @return $this + */ + public function optimizeAutoloader($optimize = true) + { + if ($optimize) { + $this->option('--optimize-autoloader'); + } + return $this; + } + + /** + * adds `ignore-platform-reqs` option to composer + * + * @return $this + */ + public function ignorePlatformRequirements($ignore = true) + { + $this->option('--ignore-platform-reqs'); + return $this; + } + + /** + * disable plugins + * + * @return $this + */ + public function disablePlugins($disable = true) + { + if ($disable) { + $this->option('--no-plugins'); + } + return $this; + } + + /** + * skip scripts + * + * @return $this + */ + public function noScripts($disable = true) + { + if ($disable) { + $this->option('--no-scripts'); + } + return $this; + } + + /** + * adds `--working-dir $dir` option to composer + * + * @return $this + */ + public function workingDir($dir) + { + $this->option("--working-dir", $dir); + return $this; + } + + /** + * Copy class fields into command options as directed. + */ + public function buildCommand() + { + if (!isset($this->ansi) && $this->getConfig()->get(\Robo\Config\Config::DECORATED)) { + $this->ansi(); + } + if (!isset($this->nointeraction) && !$this->getConfig()->get(\Robo\Config\Config::INTERACTIVE)) { + $this->noInteraction(); + } + $this->option($this->prefer) + ->option($this->dev) + ->option($this->nointeraction) + ->option($this->ansi); + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + if (!$this->built) { + $this->buildCommand(); + $this->built = true; + } + return "{$this->command} {$this->action}{$this->arguments}"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Config.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Config.php new file mode 100644 index 00000000..b5a6bbff --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Config.php @@ -0,0 +1,93 @@ +taskComposerConfig()->set('bin-dir', 'bin/')->run(); + * ?> + * ``` + */ +class Config extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'config'; + + /** + * Set a configuration value + * @return $this + */ + public function set($key, $value) + { + $this->arg($key); + $this->arg($value); + return $this; + } + + /** + * Operate on the global repository + * @return $this + */ + public function useGlobal($useGlobal = true) + { + if ($useGlobal) { + $this->option('global'); + } + return $this; + } + + /** + * @return $this + */ + public function repository($id, $uri, $repoType = 'vcs') + { + $this->arg("repositories.$id"); + $this->arg($repoType); + $this->arg($uri); + return $this; + } + + /** + * @return $this + */ + public function removeRepository($id) + { + $this->option('unset', "repositories.$id"); + return $this; + } + + /** + * @return $this + */ + public function disableRepository($id) + { + $this->arg("repositories.$id"); + $this->arg('false'); + return $this; + } + + /** + * @return $this + */ + public function enableRepository($id) + { + $this->arg("repositories.$id"); + $this->arg('true'); + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Configuring composer.json: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/CreateProject.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/CreateProject.php new file mode 100644 index 00000000..5f979a64 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/CreateProject.php @@ -0,0 +1,112 @@ +taskComposerCreateProject()->source('foo/bar')->target('myBar')->run(); + * ?> + * ``` + */ +class CreateProject extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'create-project'; + + protected $source; + protected $target = ''; + protected $version = ''; + + /** + * @return $this + */ + public function source($source) + { + $this->source = $source; + return $this; + } + + /** + * @return $this + */ + public function target($target) + { + $this->target = $target; + return $this; + } + + /** + * @return $this + */ + public function version($version) + { + $this->version = $version; + return $this; + } + + public function keepVcs($keep = true) + { + if ($keep) { + $this->option('--keep-vcs'); + } + return $this; + } + + public function noInstall($noInstall = true) + { + if ($noInstall) { + $this->option('--no-install'); + } + return $this; + } + + /** + * @return $this + */ + public function repository($repository) + { + if (!empty($repository)) { + $this->option('repository', $repository); + } + return $this; + } + + /** + * @return $this + */ + public function stability($stability) + { + if (!empty($stability)) { + $this->option('stability', $stability); + } + return $this; + } + + public function buildCommand() + { + $this->arg($this->source); + if (!empty($this->target)) { + $this->arg($this->target); + } + if (!empty($this->version)) { + $this->arg($this->version); + } + + return parent::buildCommand(); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Creating project: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/DumpAutoload.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/DumpAutoload.php new file mode 100644 index 00000000..55b1ea00 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/DumpAutoload.php @@ -0,0 +1,62 @@ +taskComposerDumpAutoload()->run(); + * + * // dump auto loader with custom path + * $this->taskComposerDumpAutoload('path/to/my/composer.phar') + * ->preferDist() + * ->run(); + * + * // optimize autoloader dump with custom path + * $this->taskComposerDumpAutoload('path/to/my/composer.phar') + * ->optimize() + * ->run(); + * + * // optimize autoloader dump with custom path and no dev + * $this->taskComposerDumpAutoload('path/to/my/composer.phar') + * ->optimize() + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class DumpAutoload extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'dump-autoload'; + + /** + * @var string + */ + protected $optimize; + + /** + * @return $this + */ + public function optimize($optimize = true) + { + if ($optimize) { + $this->option("--optimize"); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Dumping Autoloader: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Init.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Init.php new file mode 100644 index 00000000..c841299d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Init.php @@ -0,0 +1,115 @@ +taskComposerInit()->run(); + * ?> + * ``` + */ +class Init extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'init'; + + /** + * @return $this + */ + public function projectName($projectName) + { + $this->option('name', $projectName); + return $this; + } + + /** + * @return $this + */ + public function description($description) + { + $this->option('description', $description); + return $this; + } + + /** + * @return $this + */ + public function author($author) + { + $this->option('author', $author); + return $this; + } + + /** + * @return $this + */ + public function projectType($type) + { + $this->option('type', $type); + return $this; + } + + /** + * @return $this + */ + public function homepage($homepage) + { + $this->option('homepage', $homepage); + return $this; + } + + /** + * 'require' is a keyword, so it cannot be a method name. + * @return $this + */ + public function dependency($project, $version = null) + { + if (isset($version)) { + $project .= ":$version"; + } + $this->option('require', $project); + return $this; + } + + /** + * @return $this + */ + public function stability($stability) + { + $this->option('stability', $stability); + return $this; + } + + /** + * @return $this + */ + public function license($license) + { + $this->option('license', $license); + return $this; + } + + /** + * @return $this + */ + public function repository($repository) + { + $this->option('repository', $repository); + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Creating composer.json: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Install.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Install.php new file mode 100644 index 00000000..76cb9861 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Install.php @@ -0,0 +1,40 @@ +taskComposerInstall()->run(); + * + * // prefer dist with custom path + * $this->taskComposerInstall('path/to/my/composer.phar') + * ->preferDist() + * ->run(); + * + * // optimize autoloader with custom path + * $this->taskComposerInstall('path/to/my/composer.phar') + * ->optimizeAutoloader() + * ->run(); + * ?> + * ``` + */ +class Install extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'install'; + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Installing Packages: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Remove.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Remove.php new file mode 100644 index 00000000..b0316f05 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Remove.php @@ -0,0 +1,85 @@ +taskComposerRemove()->run(); + * ?> + * ``` + */ +class Remove extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'remove'; + + /** + * @return $this + */ + public function dev($dev = true) + { + if ($dev) { + $this->option('--dev'); + } + return $this; + } + + /** + * @return $this + */ + public function noProgress($noProgress = true) + { + if ($noProgress) { + $this->option('--no-progress'); + } + return $this; + } + + /** + * @return $this + */ + public function noUpdate($noUpdate = true) + { + if ($noUpdate) { + $this->option('--no-update'); + } + return $this; + } + + /** + * @return $this + */ + public function updateNoDev($updateNoDev = true) + { + if ($updateNoDev) { + $this->option('--update-no-dev'); + } + return $this; + } + + /** + * @return $this + */ + public function noUpdateWithDependencies($updateWithDependencies = true) + { + if ($updateWithDependencies) { + $this->option('--no-update-with-dependencies'); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Removing packages: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/RequireDependency.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/RequireDependency.php new file mode 100644 index 00000000..6cdbf613 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/RequireDependency.php @@ -0,0 +1,50 @@ +taskComposerRequire()->dependency('foo/bar', '^.2.4.8')->run(); + * ?> + * ``` + */ +class RequireDependency extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'require'; + + /** + * 'require' is a keyword, so it cannot be a method name. + * @return $this + */ + public function dependency($project, $version = null) + { + $project = (array)$project; + + if (isset($version)) { + $project = array_map( + function ($item) use ($version) { + return "$item:$version"; + }, + $project + ); + } + $this->args($project); + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Requiring packages: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Update.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Update.php new file mode 100644 index 00000000..3a0a64af --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Update.php @@ -0,0 +1,40 @@ +taskComposerUpdate()->run(); + * + * // prefer dist with custom path + * $this->taskComposerUpdate('path/to/my/composer.phar') + * ->preferDist() + * ->run(); + * + * // optimize autoloader with custom path + * $this->taskComposerUpdate('path/to/my/composer.phar') + * ->optimizeAutoloader() + * ->run(); + * ?> + * ``` + */ +class Update extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'update'; + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Updating Packages: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Validate.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Validate.php new file mode 100644 index 00000000..adb15854 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/Validate.php @@ -0,0 +1,85 @@ +taskComposerValidate()->run(); + * ?> + * ``` + */ +class Validate extends Base +{ + /** + * {@inheritdoc} + */ + protected $action = 'validate'; + + /** + * @return $this + */ + public function noCheckAll($noCheckAll = true) + { + if ($noCheckAll) { + $this->option('--no-check-all'); + } + return $this; + } + + /** + * @return $this + */ + public function noCheckLock($noCheckLock = true) + { + if ($noCheckLock) { + $this->option('--no-check-lock'); + } + return $this; + } + + /** + * @return $this + */ + public function noCheckPublish($noCheckPublish = true) + { + if ($noCheckPublish) { + $this->option('--no-check-publish'); + } + return $this; + } + + /** + * @return $this + */ + public function withDependencies($withDependencies = true) + { + if ($withDependencies) { + $this->option('--with-dependencies'); + } + return $this; + } + + /** + * @return $this + */ + public function strict($strict = true) + { + if ($strict) { + $this->option('--strict'); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Validating composer.json: {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/loadTasks.php new file mode 100644 index 00000000..6b074ba3 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Composer/loadTasks.php @@ -0,0 +1,95 @@ +task(Install::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Update + */ + protected function taskComposerUpdate($pathToComposer = null) + { + return $this->task(Update::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return DumpAutoload + */ + protected function taskComposerDumpAutoload($pathToComposer = null) + { + return $this->task(DumpAutoload::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Init + */ + protected function taskComposerInit($pathToComposer = null) + { + return $this->task(Init::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Init + */ + protected function taskComposerConfig($pathToComposer = null) + { + return $this->task(Config::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Validate + */ + protected function taskComposerValidate($pathToComposer = null) + { + return $this->task(Validate::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Remove + */ + protected function taskComposerRemove($pathToComposer = null) + { + return $this->task(Remove::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Remove + */ + protected function taskComposerRequire($pathToComposer = null) + { + return $this->task(RequireDependency::class, $pathToComposer); + } + + /** + * @param null|string $pathToComposer + * + * @return Remove + */ + protected function taskComposerCreateProject($pathToComposer = null) + { + return $this->task(CreateProject::class, $pathToComposer); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/Changelog.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/Changelog.php new file mode 100644 index 00000000..44af6d82 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/Changelog.php @@ -0,0 +1,246 @@ +taskChangelog() + * ->version($version) + * ->change("released to github") + * ->run(); + * ?> + * ``` + * + * Changes can be asked from Console + * + * ``` php + * taskChangelog() + * ->version($version) + * ->askForChanges() + * ->run(); + * ?> + * ``` + */ +class Changelog extends BaseTask implements BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var string + */ + protected $filename; + + /** + * @var array + */ + protected $log = []; + + /** + * @var string + */ + protected $anchor = "# Changelog"; + + /** + * @var string + */ + protected $version = ""; + + /** + * @var string + */ + protected $body = ""; + + /** + * @var string + */ + protected $header = ""; + + /** + * @param string $filename + * + * @return $this + */ + public function filename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * Sets the changelog body text. + * + * This method permits the raw changelog text to be set directly If this is set, $this->log changes will be ignored. + * + * @param string $body + * + * @return $this + */ + public function setBody($body) + { + $this->body = $body; + return $this; + } + + /** + * @param string $header + * + * @return $this + */ + public function setHeader($header) + { + $this->header = $header; + return $this; + } + + /** + * @param string $item + * + * @return $this + */ + public function log($item) + { + $this->log[] = $item; + return $this; + } + + /** + * @param string $anchor + * + * @return $this + */ + public function anchor($anchor) + { + $this->anchor = $anchor; + return $this; + } + + /** + * @param string $version + * + * @return $this + */ + public function version($version) + { + $this->version = $version; + return $this; + } + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * @param array $data + * + * @return $this + */ + public function changes(array $data) + { + $this->log = array_merge($this->log, $data); + return $this; + } + + /** + * @param string $change + * + * @return $this + */ + public function change($change) + { + $this->log[] = $change; + return $this; + } + + /** + * @return array + */ + public function getChanges() + { + return $this->log; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (empty($this->body)) { + if (empty($this->log)) { + return Result::error($this, "Changelog is empty"); + } + $this->body = $this->generateBody(); + } + if (empty($this->header)) { + $this->header = $this->generateHeader(); + } + + $text = $this->header . $this->body; + + if (!file_exists($this->filename)) { + $this->printTaskInfo('Creating {filename}', ['filename' => $this->filename]); + $res = file_put_contents($this->filename, $this->anchor); + if ($res === false) { + return Result::error($this, "File {filename} cant be created", ['filename' => $this->filename]); + } + } + + /** @var \Robo\Result $result */ + // trying to append to changelog for today + $result = $this->collectionBuilder()->taskReplaceInFile($this->filename) + ->from($this->header) + ->to($text) + ->run(); + + if (!isset($result['replaced']) || !$result['replaced']) { + $result = $this->collectionBuilder()->taskReplaceInFile($this->filename) + ->from($this->anchor) + ->to($this->anchor . "\n\n" . $text) + ->run(); + } + + return new Result($this, $result->getExitCode(), $result->getMessage(), $this->log); + } + + /** + * @return \Robo\Result|string + */ + protected function generateBody() + { + $text = implode("\n", array_map([$this, 'processLogRow'], $this->log)); + $text .= "\n"; + + return $text; + } + + /** + * @return string + */ + protected function generateHeader() + { + return "#### {$this->version}\n\n"; + } + + /** + * @param $i + * + * @return string + */ + public function processLogRow($i) + { + return "* $i *" . date('Y-m-d') . "*"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GenerateMarkdownDoc.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GenerateMarkdownDoc.php new file mode 100644 index 00000000..0c3ec26c --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GenerateMarkdownDoc.php @@ -0,0 +1,782 @@ +taskGenDoc('models.md') + * ->docClass('Model\User') // take class Model\User + * ->docClass('Model\Post') // take class Model\Post + * ->filterMethods(function(\ReflectionMethod $r) { + * return $r->isPublic() or $r->isProtected(); // process public and protected methods + * })->processClass(function(\ReflectionClass $r, $text) { + * return "Class ".$r->getName()."\n\n$text\n\n###Methods\n"; + * })->run(); + * ``` + * + * By default this task generates a documentation for each public method of a class. + * It combines method signature with a docblock. Both can be post-processed. + * + * ``` php + * taskGenDoc('models.md') + * ->docClass('Model\User') + * ->processClassSignature(false) // false can be passed to not include class signature + * ->processClassDocBlock(function(\ReflectionClass $r, $text) { + * return "[This is part of application model]\n" . $text; + * })->processMethodSignature(function(\ReflectionMethod $r, $text) { + * return "#### {$r->name}()"; + * })->processMethodDocBlock(function(\ReflectionMethod $r, $text) { + * return strpos($r->name, 'save')===0 ? "[Saves to the database]\n" . $text : $text; + * })->run(); + * ``` + */ +class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var string[] + */ + protected $docClass = []; + + /** + * @var callable + */ + protected $filterMethods; + + /** + * @var callable + */ + protected $filterClasses; + + /** + * @var callable + */ + protected $filterProperties; + + /** + * @var callable + */ + protected $processClass; + + /** + * @var callable|false + */ + protected $processClassSignature; + + /** + * @var callable|false + */ + protected $processClassDocBlock; + + /** + * @var callable|false + */ + protected $processMethod; + + /** + * @var callable|false + */ + protected $processMethodSignature; + + /** + * @var callable|false + */ + protected $processMethodDocBlock; + + /** + * @var callable|false + */ + protected $processProperty; + + /** + * @var callable|false + */ + protected $processPropertySignature; + + /** + * @var callable|false + */ + protected $processPropertyDocBlock; + + /** + * @var callable + */ + protected $reorder; + + /** + * @var callable + */ + protected $reorderMethods; + + /** + * @todo Unused property. + * + * @var callable + */ + protected $reorderProperties; + + /** + * @var string + */ + protected $filename; + + /** + * @var string + */ + protected $prepend = ""; + + /** + * @var string + */ + protected $append = ""; + + /** + * @var string + */ + protected $text; + + /** + * @var string[] + */ + protected $textForClass = []; + + /** + * @param string $filename + * + * @return static + */ + public static function init($filename) + { + return new static($filename); + } + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * Put a class you want to be documented. + * + * @param string $item + * + * @return $this + */ + public function docClass($item) + { + $this->docClass[] = $item; + return $this; + } + + /** + * Using a callback function filter out methods that won't be documented. + * + * @param callable $filterMethods + * + * @return $this + */ + public function filterMethods($filterMethods) + { + $this->filterMethods = $filterMethods; + return $this; + } + + /** + * Using a callback function filter out classes that won't be documented. + * + * @param callable $filterClasses + * + * @return $this + */ + public function filterClasses($filterClasses) + { + $this->filterClasses = $filterClasses; + return $this; + } + + /** + * Using a callback function filter out properties that won't be documented. + * + * @param callable $filterProperties + * + * @return $this + */ + public function filterProperties($filterProperties) + { + $this->filterProperties = $filterProperties; + return $this; + } + + /** + * Post-process class documentation. + * + * @param callable $processClass + * + * @return $this + */ + public function processClass($processClass) + { + $this->processClass = $processClass; + return $this; + } + + /** + * Post-process class signature. Provide *false* to skip. + * + * @param callable|false $processClassSignature + * + * @return $this + */ + public function processClassSignature($processClassSignature) + { + $this->processClassSignature = $processClassSignature; + return $this; + } + + /** + * Post-process class docblock contents. Provide *false* to skip. + * + * @param callable|false $processClassDocBlock + * + * @return $this + */ + public function processClassDocBlock($processClassDocBlock) + { + $this->processClassDocBlock = $processClassDocBlock; + return $this; + } + + /** + * Post-process method documentation. Provide *false* to skip. + * + * @param callable|false $processMethod + * + * @return $this + */ + public function processMethod($processMethod) + { + $this->processMethod = $processMethod; + return $this; + } + + /** + * Post-process method signature. Provide *false* to skip. + * + * @param callable|false $processMethodSignature + * + * @return $this + */ + public function processMethodSignature($processMethodSignature) + { + $this->processMethodSignature = $processMethodSignature; + return $this; + } + + /** + * Post-process method docblock contents. Provide *false* to skip. + * + * @param callable|false $processMethodDocBlock + * + * @return $this + */ + public function processMethodDocBlock($processMethodDocBlock) + { + $this->processMethodDocBlock = $processMethodDocBlock; + return $this; + } + + /** + * Post-process property documentation. Provide *false* to skip. + * + * @param callable|false $processProperty + * + * @return $this + */ + public function processProperty($processProperty) + { + $this->processProperty = $processProperty; + return $this; + } + + /** + * Post-process property signature. Provide *false* to skip. + * + * @param callable|false $processPropertySignature + * + * @return $this + */ + public function processPropertySignature($processPropertySignature) + { + $this->processPropertySignature = $processPropertySignature; + return $this; + } + + /** + * Post-process property docblock contents. Provide *false* to skip. + * + * @param callable|false $processPropertyDocBlock + * + * @return $this + */ + public function processPropertyDocBlock($processPropertyDocBlock) + { + $this->processPropertyDocBlock = $processPropertyDocBlock; + return $this; + } + + /** + * Use a function to reorder classes. + * + * @param callable $reorder + * + * @return $this + */ + public function reorder($reorder) + { + $this->reorder = $reorder; + return $this; + } + + /** + * Use a function to reorder methods in class. + * + * @param callable $reorderMethods + * + * @return $this + */ + public function reorderMethods($reorderMethods) + { + $this->reorderMethods = $reorderMethods; + return $this; + } + + /** + * @param callable $reorderProperties + * + * @return $this + */ + public function reorderProperties($reorderProperties) + { + $this->reorderProperties = $reorderProperties; + return $this; + } + + /** + * @param string $filename + * + * @return $this + */ + public function filename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * Inserts text at the beginning of markdown file. + * + * @param string $prepend + * + * @return $this + */ + public function prepend($prepend) + { + $this->prepend = $prepend; + return $this; + } + + /** + * Inserts text at the end of markdown file. + * + * @param string $append + * + * @return $this + */ + public function append($append) + { + $this->append = $append; + return $this; + } + + /** + * @param string $text + * + * @return $this + */ + public function text($text) + { + $this->text = $text; + return $this; + } + + /** + * @param string $item + * + * @return $this + */ + public function textForClass($item) + { + $this->textForClass[] = $item; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + foreach ($this->docClass as $class) { + $this->printTaskInfo("Processing {class}", ['class' => $class]); + $this->textForClass[$class] = $this->documentClass($class); + } + + if (is_callable($this->reorder)) { + $this->printTaskInfo("Applying reorder function"); + call_user_func_array($this->reorder, [$this->textForClass]); + } + + $this->text = implode("\n", $this->textForClass); + + /** @var \Robo\Result $result */ + $result = $this->collectionBuilder()->taskWriteToFile($this->filename) + ->line($this->prepend) + ->text($this->text) + ->line($this->append) + ->run(); + + $this->printTaskSuccess('{filename} created. {class-count} classes documented', ['filename' => $this->filename, 'class-count' => count($this->docClass)]); + + return new Result($this, $result->getExitCode(), $result->getMessage(), $this->textForClass); + } + + /** + * @param string $class + * + * @return null|string + */ + protected function documentClass($class) + { + if (!class_exists($class)) { + return ""; + } + $refl = new \ReflectionClass($class); + + if (is_callable($this->filterClasses)) { + $ret = call_user_func($this->filterClasses, $refl); + if (!$ret) { + return; + } + } + $doc = $this->documentClassSignature($refl); + $doc .= "\n" . $this->documentClassDocBlock($refl); + $doc .= "\n"; + + if (is_callable($this->processClass)) { + $doc = call_user_func($this->processClass, $refl, $doc); + } + + $properties = []; + foreach ($refl->getProperties() as $reflProperty) { + $properties[] = $this->documentProperty($reflProperty); + } + + $properties = array_filter($properties); + $doc .= implode("\n", $properties); + + $methods = []; + foreach ($refl->getMethods() as $reflMethod) { + $methods[$reflMethod->name] = $this->documentMethod($reflMethod); + } + if (is_callable($this->reorderMethods)) { + call_user_func_array($this->reorderMethods, [&$methods]); + } + + $methods = array_filter($methods); + + $doc .= implode("\n", $methods)."\n"; + + return $doc; + } + + /** + * @param \ReflectionClass $reflectionClass + * + * @return string + */ + protected function documentClassSignature(\ReflectionClass $reflectionClass) + { + if ($this->processClassSignature === false) { + return ""; + } + + $signature = "## {$reflectionClass->name}\n\n"; + + if ($parent = $reflectionClass->getParentClass()) { + $signature .= "* *Extends* `{$parent->name}`"; + } + $interfaces = $reflectionClass->getInterfaceNames(); + if (count($interfaces)) { + $signature .= "\n* *Implements* `" . implode('`, `', $interfaces) . '`'; + } + $traits = $reflectionClass->getTraitNames(); + if (count($traits)) { + $signature .= "\n* *Uses* `" . implode('`, `', $traits) . '`'; + } + if (is_callable($this->processClassSignature)) { + $signature = call_user_func($this->processClassSignature, $reflectionClass, $signature); + } + + return $signature; + } + + /** + * @param \ReflectionClass $reflectionClass + * + * @return string + */ + protected function documentClassDocBlock(\ReflectionClass $reflectionClass) + { + if ($this->processClassDocBlock === false) { + return ""; + } + $doc = self::indentDoc($reflectionClass->getDocComment()); + if (is_callable($this->processClassDocBlock)) { + $doc = call_user_func($this->processClassDocBlock, $reflectionClass, $doc); + } + return $doc; + } + + /** + * @param \ReflectionMethod $reflectedMethod + * + * @return string + */ + protected function documentMethod(\ReflectionMethod $reflectedMethod) + { + if ($this->processMethod === false) { + return ""; + } + if (is_callable($this->filterMethods)) { + $ret = call_user_func($this->filterMethods, $reflectedMethod); + if (!$ret) { + return ""; + } + } else { + if (!$reflectedMethod->isPublic()) { + return ""; + } + } + + $signature = $this->documentMethodSignature($reflectedMethod); + $docblock = $this->documentMethodDocBlock($reflectedMethod); + $methodDoc = "$signature $docblock"; + if (is_callable($this->processMethod)) { + $methodDoc = call_user_func($this->processMethod, $reflectedMethod, $methodDoc); + } + return $methodDoc; + } + + /** + * @param \ReflectionProperty $reflectedProperty + * + * @return string + */ + protected function documentProperty(\ReflectionProperty $reflectedProperty) + { + if ($this->processProperty === false) { + return ""; + } + if (is_callable($this->filterProperties)) { + $ret = call_user_func($this->filterProperties, $reflectedProperty); + if (!$ret) { + return ""; + } + } else { + if (!$reflectedProperty->isPublic()) { + return ""; + } + } + $signature = $this->documentPropertySignature($reflectedProperty); + $docblock = $this->documentPropertyDocBlock($reflectedProperty); + $propertyDoc = $signature . $docblock; + if (is_callable($this->processProperty)) { + $propertyDoc = call_user_func($this->processProperty, $reflectedProperty, $propertyDoc); + } + return $propertyDoc; + } + + /** + * @param \ReflectionProperty $reflectedProperty + * + * @return string + */ + protected function documentPropertySignature(\ReflectionProperty $reflectedProperty) + { + if ($this->processPropertySignature === false) { + return ""; + } + $modifiers = implode(' ', \Reflection::getModifierNames($reflectedProperty->getModifiers())); + $signature = "#### *$modifiers* {$reflectedProperty->name}"; + if (is_callable($this->processPropertySignature)) { + $signature = call_user_func($this->processPropertySignature, $reflectedProperty, $signature); + } + return $signature; + } + + /** + * @param \ReflectionProperty $reflectedProperty + * + * @return string + */ + protected function documentPropertyDocBlock(\ReflectionProperty $reflectedProperty) + { + if ($this->processPropertyDocBlock === false) { + return ""; + } + $propertyDoc = $reflectedProperty->getDocComment(); + // take from parent + if (!$propertyDoc) { + $parent = $reflectedProperty->getDeclaringClass(); + while ($parent = $parent->getParentClass()) { + if ($parent->hasProperty($reflectedProperty->name)) { + $propertyDoc = $parent->getProperty($reflectedProperty->name)->getDocComment(); + } + } + } + $propertyDoc = self::indentDoc($propertyDoc, 7); + $propertyDoc = preg_replace("~^@(.*?)([$\s])~", ' * `$1` $2', $propertyDoc); // format annotations + if (is_callable($this->processPropertyDocBlock)) { + $propertyDoc = call_user_func($this->processPropertyDocBlock, $reflectedProperty, $propertyDoc); + } + return ltrim($propertyDoc); + } + + /** + * @param \ReflectionParameter $param + * + * @return string + */ + protected function documentParam(\ReflectionParameter $param) + { + $text = ""; + if ($param->isArray()) { + $text .= 'array '; + } + if ($param->isCallable()) { + $text .= 'callable '; + } + $text .= '$' . $param->name; + if ($param->isDefaultValueAvailable()) { + if ($param->allowsNull()) { + $text .= ' = null'; + } else { + $text .= ' = ' . str_replace("\n", ' ', print_r($param->getDefaultValue(), true)); + } + } + + return $text; + } + + /** + * @param string $doc + * @param int $indent + * + * @return string + */ + public static function indentDoc($doc, $indent = 3) + { + if (!$doc) { + return $doc; + } + return implode( + "\n", + array_map( + function ($line) use ($indent) { + return substr($line, $indent); + }, + explode("\n", $doc) + ) + ); + } + + /** + * @param \ReflectionMethod $reflectedMethod + * + * @return string + */ + protected function documentMethodSignature(\ReflectionMethod $reflectedMethod) + { + if ($this->processMethodSignature === false) { + return ""; + } + $modifiers = implode(' ', \Reflection::getModifierNames($reflectedMethod->getModifiers())); + $params = implode( + ', ', + array_map( + function ($p) { + return $this->documentParam($p); + }, + $reflectedMethod->getParameters() + ) + ); + $signature = "#### *$modifiers* {$reflectedMethod->name}($params)"; + if (is_callable($this->processMethodSignature)) { + $signature = call_user_func($this->processMethodSignature, $reflectedMethod, $signature); + } + return $signature; + } + + /** + * @param \ReflectionMethod $reflectedMethod + * + * @return string + */ + protected function documentMethodDocBlock(\ReflectionMethod $reflectedMethod) + { + if ($this->processMethodDocBlock === false) { + return ""; + } + $methodDoc = $reflectedMethod->getDocComment(); + // take from parent + if (!$methodDoc) { + $parent = $reflectedMethod->getDeclaringClass(); + while ($parent = $parent->getParentClass()) { + if ($parent->hasMethod($reflectedMethod->name)) { + $methodDoc = $parent->getMethod($reflectedMethod->name)->getDocComment(); + } + } + } + // take from interface + if (!$methodDoc) { + $interfaces = $reflectedMethod->getDeclaringClass()->getInterfaces(); + foreach ($interfaces as $interface) { + $i = new \ReflectionClass($interface->name); + if ($i->hasMethod($reflectedMethod->name)) { + $methodDoc = $i->getMethod($reflectedMethod->name)->getDocComment(); + break; + } + } + } + + $methodDoc = self::indentDoc($methodDoc, 7); + $methodDoc = preg_replace("~^@(.*?) ([$\s])~m", ' * `$1` $2', $methodDoc); // format annotations + if (is_callable($this->processMethodDocBlock)) { + $methodDoc = call_user_func($this->processMethodDocBlock, $reflectedMethod, $methodDoc); + } + + return $methodDoc; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GenerateTask.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GenerateTask.php new file mode 100644 index 00000000..9d7a698e --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GenerateTask.php @@ -0,0 +1,107 @@ +taskGenerateTask('Symfony\Component\Filesystem\Filesystem', 'FilesystemStack') + * ->run(); + * ``` + */ +class GenerateTask extends BaseTask +{ + /** + * @var string + */ + protected $className; + + /** + * @var string + */ + protected $wrapperClassName; + + /** + * @param string $className + * @param string $wrapperClassName + */ + public function __construct($className, $wrapperClassName = '') + { + $this->className = $className; + $this->wrapperClassName = $wrapperClassName; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $delegate = new \ReflectionClass($this->className); + $replacements = []; + + $leadingCommentChars = " * "; + $methodDescriptions = []; + $methodImplementations = []; + $immediateMethods = []; + foreach ($delegate->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { + $methodName = $method->name; + $getter = preg_match('/^(get|has|is)/', $methodName); + $setter = preg_match('/^(set|unset)/', $methodName); + $argPrototypeList = []; + $argNameList = []; + $needsImplementation = false; + foreach ($method->getParameters() as $arg) { + $argDescription = '$' . $arg->name; + $argNameList[] = $argDescription; + if ($arg->isOptional()) { + $argDescription = $argDescription . ' = ' . str_replace("\n", "", var_export($arg->getDefaultValue(), true)); + // We will create wrapper methods for any method that + // has default parameters. + $needsImplementation = true; + } + $argPrototypeList[] = $argDescription; + } + $argPrototypeString = implode(', ', $argPrototypeList); + $argNameListString = implode(', ', $argNameList); + + if ($methodName[0] != '_') { + $methodDescriptions[] = "@method $methodName($argPrototypeString)"; + + if ($getter) { + $immediateMethods[] = " public function $methodName($argPrototypeString)\n {\n return \$this->delegate->$methodName($argNameListString);\n }"; + } elseif ($setter) { + $immediateMethods[] = " public function $methodName($argPrototypeString)\n {\n \$this->delegate->$methodName($argNameListString);\n return \$this;\n }"; + } elseif ($needsImplementation) { + // Include an implementation for the wrapper method if necessary + $methodImplementations[] = " protected function _$methodName($argPrototypeString)\n {\n \$this->delegate->$methodName($argNameListString);\n }"; + } + } + } + + $classNameParts = explode('\\', $this->className); + $delegate = array_pop($classNameParts); + $delegateNamespace = implode('\\', $classNameParts); + + if (empty($this->wrapperClassName)) { + $this->wrapperClassName = $delegate; + } + + $replacements['{delegateNamespace}'] = $delegateNamespace; + $replacements['{delegate}'] = $delegate; + $replacements['{wrapperClassName}'] = $this->wrapperClassName; + $replacements['{taskname}'] = "task$delegate"; + $replacements['{methodList}'] = $leadingCommentChars . implode("\n$leadingCommentChars", $methodDescriptions); + $replacements['{immediateMethods}'] = "\n\n" . implode("\n\n", $immediateMethods); + $replacements['{methodImplementations}'] = "\n\n" . implode("\n\n", $methodImplementations); + + $template = file_get_contents(__DIR__ . '/../../../data/Task/Development/GeneratedWrapper.tmpl'); + $template = str_replace(array_keys($replacements), array_values($replacements), $template); + + // Returning data in the $message will cause it to be printed. + return Result::success($this, $template); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GitHub.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GitHub.php new file mode 100644 index 00000000..9fc9909d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GitHub.php @@ -0,0 +1,157 @@ +repo = $repo; + return $this; + } + + /** + * @param string $owner + * + * @return $this + */ + public function owner($owner) + { + $this->owner = $owner; + return $this; + } + + /** + * @param string $uri + * + * @return $this + */ + public function uri($uri) + { + list($this->owner, $this->repo) = explode('/', $uri); + return $this; + } + + /** + * @return string + */ + protected function getUri() + { + return $this->owner . '/' . $this->repo; + } + + /** + * @param string $user + * + * @return $this + */ + public function user($user) + { + $this->user = $user; + return $this; + } + + /** + * @param $password + * + * @return $this + */ + public function password($password) + { + $this->password = $password; + return $this; + } + + /** + * @param $accessToken + * + * @return $this + */ + public function accessToken($token) + { + $this->accessToken = $token; + return $this; + } + + /** + * @param string $uri + * @param array $params + * @param string $method + * + * @return array + * + * @throws \Robo\Exception\TaskException + */ + protected function sendRequest($uri, $params = [], $method = 'POST') + { + if (!$this->owner or !$this->repo) { + throw new TaskException($this, 'Repo URI is not set'); + } + + $ch = curl_init(); + $url = sprintf('%s/repos/%s/%s', self::GITHUB_URL, $this->getUri(), $uri); + $this->printTaskInfo($url); + $this->printTaskInfo('{method} {url}', ['method' => $method, 'url' => $url]); + + if (!empty($this->user)) { + curl_setopt($ch, CURLOPT_USERPWD, $this->user . ':' . $this->password); + } + + if (!empty($this->accessToken)) { + $url .= "?access_token=" . $this->accessToken; + } + + curl_setopt_array( + $ch, + array( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => $method != 'GET', + CURLOPT_POSTFIELDS => json_encode($params), + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_USERAGENT => "Robo" + ) + ); + + $output = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $response = json_decode($output); + + $this->printTaskInfo($output); + return [$code, $response]; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GitHubRelease.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GitHubRelease.php new file mode 100644 index 00000000..bf7a4889 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/GitHubRelease.php @@ -0,0 +1,208 @@ +taskGitHubRelease('0.1.0') + * ->uri('consolidation-org/Robo') + * ->description('Add stuff people need.') + * ->change('Fix #123') + * ->change('Add frobulation method to all widgets') + * ->run(); + * ?> + * ``` + */ +class GitHubRelease extends GitHub +{ + /** + * @var string + */ + protected $tag; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $description = ''; + + /** + * @var string[] + */ + protected $changes = []; + + /** + * @var bool + */ + protected $draft = false; + + /** + * @var bool + */ + protected $prerelease = false; + + /** + * @var string + */ + protected $comittish = 'master'; + + /** + * @param string $tag + */ + public function __construct($tag) + { + $this->tag = $tag; + } + + /** + * @param string $tag + * + * @return $this + */ + public function tag($tag) + { + $this->tag = $tag; + return $this; + } + + /** + * @param bool $draft + * + * @return $this + */ + public function draft($draft) + { + $this->draft = $draft; + return $this; + } + + /** + * @param string $name + * + * @return $this + */ + public function name($name) + { + $this->name = $name; + return $this; + } + + /** + * @param string $description + * + * @return $this + */ + public function description($description) + { + $this->description = $description; + return $this; + } + + /** + * @param bool $prerelease + * + * @return $this + */ + public function prerelease($prerelease) + { + $this->prerelease = $prerelease; + return $this; + } + + /** + * @param string $comittish + * + * @return $this + */ + public function comittish($comittish) + { + $this->comittish = $comittish; + return $this; + } + + /** + * @param string $description + * + * @return $this + */ + public function appendDescription($description) + { + if (!empty($this->description)) { + $this->description .= "\n\n"; + } + $this->description .= $description; + return $this; + } + + public function changes(array $changes) + { + $this->changes = array_merge($this->changes, $changes); + return $this; + } + + /** + * @param string $change + * + * @return $this + */ + public function change($change) + { + $this->changes[] = $change; + return $this; + } + + /** + * @return string + */ + protected function getBody() + { + $body = $this->description; + if (!empty($this->changes)) { + $changes = array_map( + function ($line) { + return "* $line"; + }, + $this->changes + ); + $changesText = implode("\n", $changes); + $body .= "### Changelog \n\n$changesText"; + } + return $body; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Releasing {tag}', ['tag' => $this->tag]); + $this->startTimer(); + list($code, $data) = $this->sendRequest( + 'releases', + [ + "tag_name" => $this->tag, + "target_commitish" => $this->comittish, + "name" => $this->name, + "body" => $this->getBody(), + "draft" => $this->draft, + "prerelease" => $this->prerelease + ] + ); + $this->stopTimer(); + + return new Result( + $this, + in_array($code, [200, 201]) ? 0 : 1, + isset($data->message) ? $data->message : '', + ['response' => $data, 'time' => $this->getExecutionTime()] + ); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/OpenBrowser.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/OpenBrowser.php new file mode 100644 index 00000000..ea01b326 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/OpenBrowser.php @@ -0,0 +1,80 @@ +taskOpenBrowser('http://localhost') + * ->run(); + * + * // open two browser windows + * $this->taskOpenBrowser([ + * 'http://localhost/mysite', + * 'http://localhost/mysite2' + * ]) + * ->run(); + * ``` + */ +class OpenBrowser extends BaseTask +{ + /** + * @var string[] + */ + protected $urls = []; + + /** + * @param string|array $url + */ + public function __construct($url) + { + $this->urls = (array) $url; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $openCommand = $this->getOpenCommand(); + + if (empty($openCommand)) { + return Result::error($this, 'no suitable browser opening command found'); + } + + foreach ($this->urls as $url) { + passthru(sprintf($openCommand, ProcessUtils::escapeArgument($url))); + $this->printTaskInfo('Opened {url}', ['url' => $url]); + } + + return Result::success($this); + } + + /** + * @return null|string + */ + private function getOpenCommand() + { + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + return 'start "web" explorer "%s"'; + } + + passthru('which xdg-open', $linux); + passthru('which open', $osx); + + if (0 === $linux) { + return 'xdg-open %s'; + } + + if (0 === $osx) { + return 'open %s'; + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/PackPhar.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/PackPhar.php new file mode 100644 index 00000000..6d0a04d7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/PackPhar.php @@ -0,0 +1,252 @@ +taskPackPhar('package/codecept.phar') + * ->compress() + * ->stub('package/stub.php'); + * + * $finder = Finder::create() + * ->name('*.php') + * ->in('src'); + * + * foreach ($finder as $file) { + * $pharTask->addFile('src/'.$file->getRelativePathname(), $file->getRealPath()); + * } + * + * $finder = Finder::create()->files() + * ->name('*.php') + * ->in('vendor'); + * + * foreach ($finder as $file) { + * $pharTask->addStripped('vendor/'.$file->getRelativePathname(), $file->getRealPath()); + * } + * $pharTask->run(); + * + * // verify Phar is packed correctly + * $code = $this->_exec('php package/codecept.phar'); + * ?> + * ``` + */ +class PackPhar extends BaseTask implements PrintedInterface, ProgressIndicatorAwareInterface +{ + /** + * @var \Phar + */ + protected $phar; + + /** + * @var null|string + */ + protected $compileDir = null; + + /** + * @var string + */ + protected $filename; + + /** + * @var bool + */ + protected $compress = false; + + protected $stub; + + protected $bin; + + /** + * @var string + */ + protected $stubTemplate = <<filename = $filename; + if (file_exists($file->getRealPath())) { + @unlink($file->getRealPath()); + } + $this->phar = new \Phar($file->getPathname(), 0, $file->getFilename()); + } + + /** + * @param bool $compress + * + * @return $this + */ + public function compress($compress = true) + { + $this->compress = $compress; + return $this; + } + + /** + * @param string $stub + * + * @return $this + */ + public function stub($stub) + { + $this->phar->setStub(file_get_contents($stub)); + return $this; + } + + /** + * {@inheritdoc} + */ + public function progressIndicatorSteps() + { + // run() will call advanceProgressIndicator() once for each + // file, one after calling stopBuffering, and again after compression. + return count($this->files)+2; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Creating {filename}', ['filename' => $this->filename]); + $this->phar->setSignatureAlgorithm(\Phar::SHA1); + $this->phar->startBuffering(); + + $this->printTaskInfo('Packing {file-count} files into phar', ['file-count' => count($this->files)]); + + $this->startProgressIndicator(); + foreach ($this->files as $path => $content) { + $this->phar->addFromString($path, $content); + $this->advanceProgressIndicator(); + } + $this->phar->stopBuffering(); + $this->advanceProgressIndicator(); + + if ($this->compress and in_array('GZ', \Phar::getSupportedCompression())) { + if (count($this->files) > 1000) { + $this->printTaskInfo('Too many files. Compression DISABLED'); + } else { + $this->printTaskInfo('{filename} compressed', ['filename' => $this->filename]); + $this->phar = $this->phar->compressFiles(\Phar::GZ); + } + } + $this->advanceProgressIndicator(); + $this->stopProgressIndicator(); + $this->printTaskSuccess('{filename} produced', ['filename' => $this->filename]); + return Result::success($this, '', ['time' => $this->getExecutionTime()]); + } + + /** + * @param string $path + * @param string $file + * + * @return $this + */ + public function addStripped($path, $file) + { + $this->files[$path] = $this->stripWhitespace(file_get_contents($file)); + return $this; + } + + /** + * @param string $path + * @param string $file + * + * @return $this + */ + public function addFile($path, $file) + { + $this->files[$path] = file_get_contents($file); + return $this; + } + + /** + * @param \Symfony\Component\Finder\SplFileInfo[] $files + */ + public function addFiles($files) + { + foreach ($files as $file) { + $this->addFile($file->getRelativePathname(), $file->getRealPath()); + } + } + + /** + * @param string $file + * + * @return $this + */ + public function executable($file) + { + $source = file_get_contents($file); + if (strpos($source, '#!/usr/bin/env php') === 0) { + $source = substr($source, strpos($source, 'phar->setStub(sprintf($this->stubTemplate, $source)); + return $this; + } + + /** + * Strips whitespace from source. Taken from composer + * + * @param string $source + * + * @return string + */ + private function stripWhitespace($source) + { + if (!function_exists('token_get_all')) { + return $source; + } + + $output = ''; + foreach (token_get_all($source) as $token) { + if (is_string($token)) { + $output .= $token; + } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { + // $output .= $token[1]; + $output .= str_repeat("\n", substr_count($token[1], "\n")); + } elseif (T_WHITESPACE === $token[0]) { + // reduce wide spaces + $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]); + // normalize newlines to \n + $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace); + // trim leading spaces + $whitespace = preg_replace('{\n +}', "\n", $whitespace); + $output .= $whitespace; + } else { + $output .= $token[1]; + } + } + + return $output; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/PhpServer.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/PhpServer.php new file mode 100644 index 00000000..6dd36680 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/PhpServer.php @@ -0,0 +1,86 @@ +taskServer(8000) + * ->dir('public') + * ->run(); + * + * // run with IP 0.0.0.0 + * $this->taskServer(8000) + * ->host('0.0.0.0') + * ->run(); + * + * // execute server in background + * $this->taskServer(8000) + * ->background() + * ->run(); + * ?> + * ``` + */ +class PhpServer extends Exec +{ + /** + * @var int + */ + protected $port; + + /** + * @var string + */ + protected $host = '127.0.0.1'; + + /** + * {@inheritdoc} + */ + protected $command = 'php -S %s:%d '; + + /** + * @param int $port + */ + public function __construct($port) + { + $this->port = $port; + + if (strtolower(PHP_OS) === 'linux') { + $this->command = 'exec php -S %s:%d '; + } + } + + /** + * @param string $host + * + * @return $this + */ + public function host($host) + { + $this->host = $host; + return $this; + } + + /** + * @param string $path + * + * @return $this + */ + public function dir($path) + { + $this->command .= "-t $path"; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return sprintf($this->command . $this->arguments, $this->host, $this->port); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/SemVer.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/SemVer.php new file mode 100644 index 00000000..6c807d89 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/SemVer.php @@ -0,0 +1,255 @@ +taskSemVer('.semver') + * ->increment() + * ->run(); + * ?> + * ``` + * + */ +class SemVer implements TaskInterface +{ + const SEMVER = "---\n:major: %d\n:minor: %d\n:patch: %d\n:special: '%s'\n:metadata: '%s'"; + + const REGEX = "/^\-\-\-\n:major:\s(0|[1-9]\d*)\n:minor:\s(0|[1-9]\d*)\n:patch:\s(0|[1-9]\d*)\n:special:\s'([a-zA-z0-9]*\.?(?:0|[1-9]\d*)?)'\n:metadata:\s'((?:0|[1-9]\d*)?(?:\.[a-zA-z0-9\.]*)?)'/"; + + const REGEX_STRING = '/^(?[0-9]+)\.(?[0-9]+)\.(?[0-9]+)(|-(?[0-9a-zA-Z.]+))(|\+(?[0-9a-zA-Z.]+))$/'; + + /** + * @var string + */ + protected $format = 'v%M.%m.%p%s'; + + /** + * @var string + */ + protected $specialSeparator = '-'; + + /** + * @var string + */ + protected $metadataSeparator = '+'; + + /** + * @var string + */ + protected $path; + + /** + * @var array + */ + protected $version = [ + 'major' => 0, + 'minor' => 0, + 'patch' => 0, + 'special' => '', + 'metadata' => '' + ]; + + /** + * @param string $filename + */ + public function __construct($filename = '') + { + $this->path = $filename; + + if (file_exists($this->path)) { + $semverFileContents = file_get_contents($this->path); + $this->parseFile($semverFileContents); + } + } + + /** + * @return string + */ + public function __toString() + { + $search = ['%M', '%m', '%p', '%s']; + $replace = $this->version + ['extra' => '']; + + foreach (['special', 'metadata'] as $key) { + if (!empty($replace[$key])) { + $separator = $key . 'Separator'; + $replace['extra'] .= $this->{$separator} . $replace[$key]; + } + unset($replace[$key]); + } + + return str_replace($search, $replace, $this->format); + } + + public function version($version) + { + $this->parseString($version); + return $this; + } + + /** + * @param string $format + * + * @return $this + */ + public function setFormat($format) + { + $this->format = $format; + return $this; + } + + /** + * @param string $separator + * + * @return $this + */ + public function setMetadataSeparator($separator) + { + $this->metadataSeparator = $separator; + return $this; + } + + /** + * @param string $separator + * + * @return $this + */ + public function setPrereleaseSeparator($separator) + { + $this->specialSeparator = $separator; + return $this; + } + + /** + * @param string $what + * + * @return $this + * + * @throws \Robo\Exception\TaskException + */ + public function increment($what = 'patch') + { + switch ($what) { + case 'major': + $this->version['major']++; + $this->version['minor'] = 0; + $this->version['patch'] = 0; + break; + case 'minor': + $this->version['minor']++; + $this->version['patch'] = 0; + break; + case 'patch': + $this->version['patch']++; + break; + default: + throw new TaskException( + $this, + 'Bad argument, only one of the following is allowed: major, minor, patch' + ); + } + return $this; + } + + /** + * @param string $tag + * + * @return $this + * + * @throws \Robo\Exception\TaskException + */ + public function prerelease($tag = 'RC') + { + if (!is_string($tag)) { + throw new TaskException($this, 'Bad argument, only strings allowed.'); + } + + $number = 0; + + if (!empty($this->version['special'])) { + list($current, $number) = explode('.', $this->version['special']); + if ($tag != $current) { + $number = 0; + } + } + + $number++; + + $this->version['special'] = implode('.', [$tag, $number]); + return $this; + } + + /** + * @param array|string $data + * + * @return $this + */ + public function metadata($data) + { + if (is_array($data)) { + $data = implode('.', $data); + } + + $this->version['metadata'] = $data; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $written = $this->dump(); + return new Result($this, (int)($written === false), $this->__toString()); + } + + /** + * @return bool + * + * @throws \Robo\Exception\TaskException + */ + protected function dump() + { + if (empty($this->path)) { + return true; + } + extract($this->version); + $semver = sprintf(self::SEMVER, $major, $minor, $patch, $special, $metadata); + if (is_writeable($this->path) === false || file_put_contents($this->path, $semver) === false) { + throw new TaskException($this, 'Failed to write semver file.'); + } + return true; + } + + protected function parseString($semverString) + { + if (!preg_match_all(self::REGEX_STRING, $semverString, $matches)) { + throw new TaskException($this, 'Bad semver value: ' . $semverString); + } + + $this->version = array_intersect_key($matches, $this->version); + $this->version = array_map(function ($item) { + return $item[0]; + }, $this->version); + } + + /** + * @throws \Robo\Exception\TaskException + */ + protected function parseFile($semverFileContents) + { + if (!preg_match_all(self::REGEX, $semverFileContents, $matches)) { + throw new TaskException($this, 'Bad semver file.'); + } + + list(, $major, $minor, $patch, $special, $metadata) = array_map('current', $matches); + $this->version = compact('major', 'minor', 'patch', 'special', 'metadata'); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/loadTasks.php new file mode 100644 index 00000000..e3dc49a3 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Development/loadTasks.php @@ -0,0 +1,86 @@ +task(Changelog::class, $filename); + } + + /** + * @param string $filename + * + * @return GenerateMarkdownDoc + */ + protected function taskGenDoc($filename) + { + return $this->task(GenerateMarkdownDoc::class, $filename); + } + + /** + * @param string $className + * @param string $wrapperClassName + * + * @return \Robo\Task\Development\GenerateTask + */ + protected function taskGenTask($className, $wrapperClassName = '') + { + return $this->task(GenerateTask::class, $className, $wrapperClassName); + } + + /** + * @param string $pathToSemVer + * + * @return SemVer + */ + protected function taskSemVer($pathToSemVer = '.semver') + { + return $this->task(SemVer::class, $pathToSemVer); + } + + /** + * @param int $port + * + * @return PhpServer + */ + protected function taskServer($port = 8000) + { + return $this->task(PhpServer::class, $port); + } + + /** + * @param string $filename + * + * @return PackPhar + */ + protected function taskPackPhar($filename) + { + return $this->task(PackPhar::class, $filename); + } + + /** + * @param string $tag + * + * @return GitHubRelease + */ + protected function taskGitHubRelease($tag) + { + return $this->task(GitHubRelease::class, $tag); + } + + /** + * @param string|array $url + * + * @return OpenBrowser + */ + protected function taskOpenBrowser($url) + { + return $this->task(OpenBrowser::class, $url); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Base.php new file mode 100644 index 00000000..135f39e7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Base.php @@ -0,0 +1,28 @@ +getCommand(); + return $this->executeCommand($command); + } + + abstract public function getCommand(); +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Build.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Build.php new file mode 100644 index 00000000..11eb92ab --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Build.php @@ -0,0 +1,55 @@ +taskDockerBuild()->run(); + * + * $this->taskDockerBuild('path/to/dir') + * ->tag('database') + * ->run(); + * + * ?> + * + * ``` + * + * Class Build + * @package Robo\Task\Docker + */ +class Build extends Base +{ + /** + * @var string + */ + protected $path; + + /** + * @param string $path + */ + public function __construct($path = '.') + { + $this->command = "docker build"; + $this->path = $path; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments . ' ' . $this->path; + } + + /** + * @param string $tag + * + * @return $this + */ + public function tag($tag) + { + return $this->option('-t', $tag); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Commit.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Commit.php new file mode 100644 index 00000000..302f1920 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Commit.php @@ -0,0 +1,66 @@ +taskDockerCommit($containerId) + * ->name('my/database') + * ->run(); + * + * // alternatively you can take the result from DockerRun task: + * + * $result = $this->taskDockerRun('db') + * ->exec('./prepare_database.sh') + * ->run(); + * + * $task->dockerCommit($result) + * ->name('my/database') + * ->run(); + * ``` + */ +class Commit extends Base +{ + /** + * @var string + */ + protected $command = "docker commit"; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $cid; + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + */ + public function __construct($cidOrResult) + { + $this->cid = $cidOrResult instanceof Result ? $cidOrResult->getCid() : $cidOrResult; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->cid . ' ' . $this->name . ' ' . $this->arguments; + } + + /** + * @param $name + * + * @return $this + */ + public function name($name) + { + $this->name = $name; + return $this; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Exec.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Exec.php new file mode 100644 index 00000000..fa67c8da --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Exec.php @@ -0,0 +1,95 @@ +taskDockerRun('test_env') + * ->detached() + * ->run(); + * + * $this->taskDockerExec($test) + * ->interactive() + * ->exec('./runtests') + * ->run(); + * + * // alternatively use commands from other tasks + * + * $this->taskDockerExec($test) + * ->interactive() + * ->exec($this->taskCodecept()->suite('acceptance')) + * ->run(); + * ?> + * ``` + * + */ +class Exec extends Base +{ + use CommandReceiver; + + /** + * @var string + */ + protected $command = "docker exec"; + + /** + * @var string + */ + protected $cid; + + /** + * @var string + */ + protected $run = ''; + + /** + * @param string|\Robo\Result $cidOrResult + */ + public function __construct($cidOrResult) + { + $this->cid = $cidOrResult instanceof Result ? $cidOrResult->getCid() : $cidOrResult; + } + + /** + * @return $this + */ + public function detached() + { + $this->option('-d'); + return $this; + } + + /** + * {@inheritdoc)} + */ + public function interactive($interactive = true) + { + if ($interactive) { + $this->option('-i'); + } + return parent::interactive($interactive); + } + + /** + * @param string|\Robo\Contract\CommandInterface $command + * + * @return $this + */ + public function exec($command) + { + $this->run = $this->receiveCommand($command); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments . ' ' . $this->cid.' '.$this->run; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Pull.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Pull.php new file mode 100644 index 00000000..32ba5b40 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Pull.php @@ -0,0 +1,33 @@ +taskDockerPull('wordpress') + * ->run(); + * + * ?> + * ``` + * + */ +class Pull extends Base +{ + /** + * @param string $image + */ + public function __construct($image) + { + $this->command = "docker pull $image "; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Remove.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Remove.php new file mode 100644 index 00000000..0a8c0ac6 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Remove.php @@ -0,0 +1,32 @@ +taskDockerRemove($container) + * ->run(); + * ?> + * ``` + * + */ +class Remove extends Base +{ + /** + * @param string $container + */ + public function __construct($container) + { + $this->command = "docker rm $container "; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Result.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Result.php new file mode 100644 index 00000000..0533159a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Result.php @@ -0,0 +1,35 @@ +taskDockerRun('mysql')->run(); + * + * $result = $this->taskDockerRun('my_db_image') + * ->env('DB', 'database_name') + * ->volume('/path/to/data', '/data') + * ->detached() + * ->publish(3306) + * ->name('my_mysql') + * ->run(); + * + * // retrieve container's cid: + * $this->say("Running container ".$result->getCid()); + * + * // execute script inside container + * $result = $this->taskDockerRun('db') + * ->exec('prepare_test_data.sh') + * ->run(); + * + * $this->taskDockerCommit($result) + * ->name('test_db') + * ->run(); + * + * // link containers + * $mysql = $this->taskDockerRun('mysql') + * ->name('wp_db') // important to set name for linked container + * ->env('MYSQL_ROOT_PASSWORD', '123456') + * ->run(); + * + * $this->taskDockerRun('wordpress') + * ->link($mysql) + * ->publish(80, 8080) + * ->detached() + * ->run(); + * + * ?> + * ``` + * + */ +class Run extends Base +{ + use CommandReceiver; + + /** + * @var string + */ + protected $image = ''; + + /** + * @var string + */ + protected $run = ''; + + /** + * @var string + */ + protected $cidFile; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $dir; + + /** + * @param string $image + */ + public function __construct($image) + { + $this->image = $image; + } + + /** + * {@inheritdoc} + */ + public function getPrinted() + { + return $this->isPrinted; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + if ($this->isPrinted) { + $this->option('-i'); + } + if ($this->cidFile) { + $this->option('cidfile', $this->cidFile); + } + return trim('docker run ' . $this->arguments . ' ' . $this->image . ' ' . $this->run); + } + + /** + * @return $this + */ + public function detached() + { + $this->option('-d'); + return $this; + } + + /** + * {@inheritdoc)} + */ + public function interactive($interactive = true) + { + if ($interactive) { + $this->option('-i'); + } + return parent::interactive($interactive); + } + + /** + * @param string|\Robo\Contract\CommandInterface $run + * + * @return $this + */ + public function exec($run) + { + $this->run = $this->receiveCommand($run); + return $this; + } + + /** + * @param string $from + * @param null|string $to + * + * @return $this + */ + public function volume($from, $to = null) + { + $volume = $to ? "$from:$to" : $from; + $this->option('-v', $volume); + return $this; + } + + /** + * Set environment variables. + * n.b. $this->env($variable, $value) also available here, + * inherited from ExecTrait. + * + * @param array $env + * @return type + */ + public function envVars(array $env) + { + foreach ($env as $variable => $value) { + $this->setDockerEnv($variable, $value); + } + return $this; + } + + /** + * @param string $variable + * @param null|string $value + * + * @return $this + */ + protected function setDockerEnv($variable, $value = null) + { + $env = $value ? "$variable=$value" : $variable; + return $this->option("-e", $env); + } + + /** + * @param null|int $port + * @param null|int $portTo + * + * @return $this + */ + public function publish($port = null, $portTo = null) + { + if (!$port) { + return $this->option('-P'); + } + if ($portTo) { + $port = "$port:$portTo"; + } + return $this->option('-p', $port); + } + + /** + * @param string $dir + * + * @return $this + */ + public function containerWorkdir($dir) + { + return $this->option('-w', $dir); + } + + /** + * @param string $user + * + * @return $this + */ + public function user($user) + { + return $this->option('-u', $user); + } + + /** + * @return $this + */ + public function privileged() + { + return $this->option('--privileged'); + } + + /** + * @param string $name + * + * @return $this + */ + public function name($name) + { + $this->name = $name; + return $this->option('name', $name); + } + + /** + * @param string|\Robo\Task\Docker\Result $name + * @param string $alias + * + * @return $this + */ + public function link($name, $alias) + { + if ($name instanceof Result) { + $name = $name->getContainerName(); + } + $this->option('link', "$name:$alias"); + return $this; + } + + /** + * @param string $dir + * + * @return $this + */ + public function tmpDir($dir) + { + $this->dir = $dir; + return $this; + } + + /** + * @return string + */ + public function getTmpDir() + { + return $this->dir ? $this->dir : sys_get_temp_dir(); + } + + /** + * @return string + */ + public function getUniqId() + { + return uniqid(); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->cidFile = $this->getTmpDir() . '/docker_' . $this->getUniqId() . '.cid'; + $result = parent::run(); + $result['cid'] = $this->getCid(); + return $result; + } + + /** + * @return null|string + */ + protected function getCid() + { + if (!$this->cidFile || !file_exists($this->cidFile)) { + return null; + } + $cid = trim(file_get_contents($this->cidFile)); + @unlink($this->cidFile); + return $cid; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Start.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Start.php new file mode 100644 index 00000000..ef19d74d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Start.php @@ -0,0 +1,41 @@ +taskDockerStart($cidOrResult) + * ->run(); + * ?> + * ``` + */ +class Start extends Base +{ + /** + * @var string + */ + protected $command = "docker start"; + + /** + * @var null|string + */ + protected $cid; + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + */ + public function __construct($cidOrResult) + { + $this->cid = $cidOrResult instanceof Result ? $cidOrResult->getCid() : $cidOrResult; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments . ' ' . $this->cid; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Stop.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Stop.php new file mode 100644 index 00000000..4d0d436d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/Stop.php @@ -0,0 +1,41 @@ +taskDockerStop($cidOrResult) + * ->run(); + * ?> + * ``` + */ +class Stop extends Base +{ + /** + * @var string + */ + protected $command = "docker stop"; + + /** + * @var null|string + */ + protected $cid; + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + */ + public function __construct($cidOrResult) + { + $this->cid = $cidOrResult instanceof Result ? $cidOrResult->getCid() : $cidOrResult; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . ' ' . $this->arguments . ' ' . $this->cid; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/loadTasks.php new file mode 100644 index 00000000..e58f5ef0 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Docker/loadTasks.php @@ -0,0 +1,85 @@ +task(Run::class, $image); + } + + /** + * @param string $image + * + * @return \Robo\Task\Docker\Pull + */ + protected function taskDockerPull($image) + { + return $this->task(Pull::class, $image); + } + + /** + * @param string $path + * + * @return \Robo\Task\Docker\Build + */ + protected function taskDockerBuild($path = '.') + { + return $this->task(Build::class, $path); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Stop + */ + protected function taskDockerStop($cidOrResult) + { + return $this->task(Stop::class, $cidOrResult); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Commit + */ + protected function taskDockerCommit($cidOrResult) + { + return $this->task(Commit::class, $cidOrResult); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Start + */ + protected function taskDockerStart($cidOrResult) + { + return $this->task(Start::class, $cidOrResult); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Remove + */ + protected function taskDockerRemove($cidOrResult) + { + return $this->task(Remove::class, $cidOrResult); + } + + /** + * @param string|\Robo\Task\Docker\Result $cidOrResult + * + * @return \Robo\Task\Docker\Exec + */ + protected function taskDockerExec($cidOrResult) + { + return $this->task(Exec::class, $cidOrResult); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Concat.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Concat.php new file mode 100644 index 00000000..12b1eca0 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Concat.php @@ -0,0 +1,101 @@ +taskConcat([ + * 'web/assets/screen.css', + * 'web/assets/print.css', + * 'web/assets/theme.css' + * ]) + * ->to('web/assets/style.css') + * ->run() + * ?> + * ``` + */ +class Concat extends BaseTask +{ + use ResourceExistenceChecker; + + /** + * @var array|Iterator + */ + protected $files; + + /** + * @var string + */ + protected $dst; + + /** + * Constructor. + * + * @param array|Iterator $files + */ + public function __construct($files) + { + $this->files = $files; + } + + /** + * set the destination file + * + * @param string $dst + * + * @return $this + */ + public function to($dst) + { + $this->dst = $dst; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (is_null($this->dst) || "" === $this->dst) { + return Result::error($this, 'You must specify a destination file with to() method.'); + } + + if (!$this->checkResources($this->files, 'file')) { + return Result::error($this, 'Source files are missing!'); + } + + if (file_exists($this->dst) && !is_writable($this->dst)) { + return Result::error($this, 'Destination already exists and cannot be overwritten.'); + } + + $dump = ''; + + foreach ($this->files as $path) { + foreach (glob($path) as $file) { + $dump .= file_get_contents($file) . "\n"; + } + } + + $this->printTaskInfo('Writing {destination}', ['destination' => $this->dst]); + + $dst = $this->dst . '.part'; + $write_result = file_put_contents($dst, $dump); + + if (false === $write_result) { + @unlink($dst); + return Result::error($this, 'File write failed.'); + } + // Cannot be cross-volume; should always succeed. + @rename($dst, $this->dst); + + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Replace.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Replace.php new file mode 100644 index 00000000..0107df13 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Replace.php @@ -0,0 +1,141 @@ +taskReplaceInFile('VERSION') + * ->from('0.2.0') + * ->to('0.3.0') + * ->run(); + * + * $this->taskReplaceInFile('README.md') + * ->from(date('Y')-1) + * ->to(date('Y')) + * ->run(); + * + * $this->taskReplaceInFile('config.yml') + * ->regex('~^service:~') + * ->to('services:') + * ->run(); + * + * $this->taskReplaceInFile('box/robo.txt') + * ->from(array('##dbname##', '##dbhost##')) + * ->to(array('robo', 'localhost')) + * ->run(); + * ?> + * ``` + */ +class Replace extends BaseTask +{ + /** + * @var string + */ + protected $filename; + + /** + * @var string|string[] + */ + protected $from; + + /** + * @var string|string[] + */ + protected $to; + + /** + * @var string + */ + protected $regex; + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * @param string $filename + * + * @return $this + */ + public function filename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * String(s) to be replaced. + * + * @param string|string[] $from + * + * @return $this + */ + public function from($from) + { + $this->from = $from; + return $this; + } + + /** + * Value(s) to be set as a replacement. + * + * @param string|string[] $to + * + * @return $this + */ + public function to($to) + { + $this->to = $to; + return $this; + } + + /** + * Regex to match string to be replaced. + * + * @param string $regex + * + * @return $this + */ + public function regex($regex) + { + $this->regex = $regex; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!file_exists($this->filename)) { + $this->printTaskError('File {filename} does not exist', ['filename' => $this->filename]); + return false; + } + + $text = file_get_contents($this->filename); + if ($this->regex) { + $text = preg_replace($this->regex, $this->to, $text, -1, $count); + } else { + $text = str_replace($this->from, $this->to, $text, $count); + } + if ($count > 0) { + $res = file_put_contents($this->filename, $text); + if ($res === false) { + return Result::error($this, "Error writing to file {filename}.", ['filename' => $this->filename]); + } + $this->printTaskSuccess("{filename} updated. {count} items replaced", ['filename' => $this->filename, 'count' => $count]); + } else { + $this->printTaskInfo("{filename} unchanged. {count} items replaced", ['filename' => $this->filename, 'count' => $count]); + } + return Result::success($this, '', ['replaced' => $count]); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/TmpFile.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/TmpFile.php new file mode 100644 index 00000000..4a18691d --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/TmpFile.php @@ -0,0 +1,72 @@ +collectionBuilder(); + * $tmpFilePath = $collection->taskTmpFile() + * ->line('-----') + * ->line(date('Y-m-d').' '.$title) + * ->line('----') + * ->getPath(); + * $collection->run(); + * ?> + * ``` + */ +class TmpFile extends Write implements CompletionInterface +{ + /** + * @param string $filename + * @param string $extension + * @param string $baseDir + * @param bool $includeRandomPart + */ + public function __construct($filename = 'tmp', $extension = '', $baseDir = '', $includeRandomPart = true) + { + if (empty($baseDir)) { + $baseDir = sys_get_temp_dir(); + } + if ($includeRandomPart) { + $random = static::randomString(); + $filename = "{$filename}_{$random}"; + } + $filename .= $extension; + parent::__construct("{$baseDir}/{$filename}"); + } + + /** + * Generate a suitably random string to use as the suffix for our + * temporary file. + * + * @param int $length + * + * @return string + */ + private static function randomString($length = 12) + { + return substr(str_shuffle('23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'), 0, $length); + } + + /** + * Delete this file when our collection completes. + * If this temporary file is not part of a collection, + * then it will be deleted when the program terminates, + * presuming that it was created by taskTmpFile() or _tmpFile(). + */ + public function complete() + { + unlink($this->getPath()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Write.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Write.php new file mode 100644 index 00000000..dc2199f9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/Write.php @@ -0,0 +1,335 @@ +taskWriteToFile('blogpost.md') + * ->line('-----') + * ->line(date('Y-m-d').' '.$title) + * ->line('----') + * ->run(); + * ?> + * ``` + */ +class Write extends BaseTask +{ + /** + * @var array + */ + protected $stack = []; + + /** + * @var string + */ + protected $filename; + + /** + * @var bool + */ + protected $append = false; + + /** + * @var null|string + */ + protected $originalContents = null; + + /** + * @param string $filename + */ + public function __construct($filename) + { + $this->filename = $filename; + } + + /** + * @param string $filename + * + * @return $this + */ + public function filename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * @param bool $append + * + * @return $this + */ + public function append($append = true) + { + $this->append = $append; + return $this; + } + + /** + * add a line. + * + * @param string $line + * + * @return $this The current instance + */ + public function line($line) + { + $this->text($line . "\n"); + return $this; + } + + /** + * add more lines. + * + * @param array $lines + * + * @return $this The current instance + */ + public function lines(array $lines) + { + $this->text(implode("\n", $lines) . "\n"); + return $this; + } + + /** + * add a text. + * + * @param string $text + * + * @return $this The current instance + */ + public function text($text) + { + $this->stack[] = array_merge([__FUNCTION__ . 'Collect'], func_get_args()); + return $this; + } + + /** + * add a text from a file. + * + * Note that the file is read in the run() method of this task. + * To load text from the current state of a file (e.g. one that may + * be deleted or altered by other tasks prior the execution of this one), + * use: + * $task->text(file_get_contents($filename)); + * + * @param string $filename + * + * @return $this The current instance + */ + public function textFromFile($filename) + { + $this->stack[] = array_merge([__FUNCTION__ . 'Collect'], func_get_args()); + return $this; + } + + /** + * substitute a placeholder with value, placeholder must be enclosed by `{}`. + * + * @param string $name + * @param string $val + * + * @return $this The current instance + */ + public function place($name, $val) + { + $this->replace('{'.$name.'}', $val); + + return $this; + } + + /** + * replace any string with value. + * + * @param string $string + * @param string $replacement + * + * @return $this The current instance + */ + public function replace($string, $replacement) + { + $this->stack[] = array_merge([__FUNCTION__ . 'Collect'], func_get_args()); + return $this; + } + + /** + * replace any string with value using regular expression. + * + * @param string $pattern + * @param string $replacement + * + * @return $this The current instance + */ + public function regexReplace($pattern, $replacement) + { + $this->stack[] = array_merge([__FUNCTION__ . 'Collect'], func_get_args()); + return $this; + } + + /** + * Append the provided text to the end of the buffer if the provided + * regex pattern matches any text already in the buffer. + * + * @param string $pattern + * @param string $text + * + * @return $this + */ + public function appendIfMatches($pattern, $text) + { + $this->stack[] = array_merge(['appendIfMatchesCollect'], [$pattern, $text, true]); + return $this; + } + + /** + * Append the provided text to the end of the buffer unless the provided + * regex pattern matches any text already in the buffer. + * + * @param string $pattern + * @param string $text + * + * @return $this + */ + public function appendUnlessMatches($pattern, $text) + { + $this->stack[] = array_merge(['appendIfMatchesCollect'], [$pattern, $text, false]); + return $this; + } + + /** + * @param $contents string + * @param $filename string + * + * @return string + */ + protected function textFromFileCollect($contents, $filename) + { + if (file_exists($filename)) { + $contents .= file_get_contents($filename); + } + return $contents; + } + + /** + * @param string|string[] $contents + * @param string|string[] $string + * @param string|string[] $replacement + * + * @return string|string[] + */ + protected function replaceCollect($contents, $string, $replacement) + { + return str_replace($string, $replacement, $contents); + } + + /** + * @param string|string[] $contents + * @param string|string[] $pattern + * @param string|string[] $replacement + * + * @return string|string[] + */ + protected function regexReplaceCollect($contents, $pattern, $replacement) + { + return preg_replace($pattern, $replacement, $contents); + } + + /** + * @param string $contents + * @param string $text + * + * @return string + */ + protected function textCollect($contents, $text) + { + return $contents . $text; + } + + /** + * @param string $contents + * @param string $pattern + * @param string $text + * @param bool $shouldMatch + * + * @return string + */ + protected function appendIfMatchesCollect($contents, $pattern, $text, $shouldMatch) + { + if (preg_match($pattern, $contents) == $shouldMatch) { + $contents .= $text; + } + return $contents; + } + + /** + * @return string + */ + public function originalContents() + { + if (!isset($this->originalContents)) { + $this->originalContents = ''; + if (file_exists($this->filename)) { + $this->originalContents = file_get_contents($this->filename); + } + } + return $this->originalContents; + } + + /** + * @return bool + */ + public function wouldChange() + { + return $this->originalContents() != $this->getContentsToWrite(); + } + + /** + * @return string + */ + protected function getContentsToWrite() + { + $contents = ""; + if ($this->append) { + $contents = $this->originalContents(); + } + foreach ($this->stack as $action) { + $command = array_shift($action); + if (method_exists($this, $command)) { + array_unshift($action, $contents); + $contents = call_user_func_array([$this, $command], $action); + } + } + return $contents; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo("Writing to {filename}.", ['filename' => $this->filename]); + $contents = $this->getContentsToWrite(); + if (!file_exists(dirname($this->filename))) { + mkdir(dirname($this->filename), 0777, true); + } + $res = file_put_contents($this->filename, $contents); + if ($res === false) { + return Result::error($this, "File {$this->filename} couldn't be created"); + } + + return Result::success($this); + } + + /** + * @return string + */ + public function getPath() + { + return $this->filename; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/loadTasks.php new file mode 100644 index 00000000..c5f39c95 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/File/loadTasks.php @@ -0,0 +1,48 @@ +task(Concat::class, $files); + } + + /** + * @param string $file + * + * @return \Robo\Task\File\Replace + */ + protected function taskReplaceInFile($file) + { + return $this->task(Replace::class, $file); + } + + /** + * @param string $file + * + * @return \Robo\Task\File\Write + */ + protected function taskWriteToFile($file) + { + return $this->task(Write::class, $file); + } + + /** + * @param string $filename + * @param string $extension + * @param string $baseDir + * @param bool $includeRandomPart + * + * @return \Robo\Task\File\TmpFile + */ + protected function taskTmpFile($filename = 'tmp', $extension = '', $baseDir = '', $includeRandomPart = true) + { + return $this->task(TmpFile::class, $filename, $extension, $baseDir, $includeRandomPart); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/BaseDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/BaseDir.php new file mode 100644 index 00000000..434334d7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/BaseDir.php @@ -0,0 +1,30 @@ +dirs = $dirs + : $this->dirs[] = $dirs; + + $this->fs = new sfFilesystem(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/CleanDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/CleanDir.php new file mode 100644 index 00000000..762f8550 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/CleanDir.php @@ -0,0 +1,63 @@ +taskCleanDir(['tmp','logs'])->run(); + * // as shortcut + * $this->_cleanDir('app/cache'); + * ?> + * ``` + */ +class CleanDir extends BaseDir +{ + use ResourceExistenceChecker; + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->checkResources($this->dirs, 'dir')) { + return Result::error($this, 'Source directories are missing!'); + } + foreach ($this->dirs as $dir) { + $this->emptyDir($dir); + $this->printTaskInfo("Cleaned {dir}", ['dir' => $dir]); + } + return Result::success($this); + } + + /** + * @param string $path + */ + protected function emptyDir($path) + { + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($path), + \RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach ($iterator as $path) { + if ($path->isDir()) { + $dir = (string)$path; + if (basename($dir) === '.' || basename($dir) === '..') { + continue; + } + $this->fs->remove($dir); + } else { + $file = (string)$path; + if (basename($file) === '.gitignore' || basename($file) === '.gitkeep') { + continue; + } + $this->fs->remove($file); + } + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/CopyDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/CopyDir.php new file mode 100644 index 00000000..08482222 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/CopyDir.php @@ -0,0 +1,162 @@ +taskCopyDir(['dist/config' => 'config'])->run(); + * // as shortcut + * $this->_copyDir('dist/config', 'config'); + * ?> + * ``` + */ +class CopyDir extends BaseDir +{ + use ResourceExistenceChecker; + + /** + * Explicitly declare our consturctor, so that + * our copyDir() method does not look like a php4 constructor. + */ + public function __construct($dirs) + { + parent::__construct($dirs); + } + + /** + * @var int + */ + protected $chmod = 0755; + + /** + * Files to exclude on copying. + * + * @var string[] + */ + protected $exclude = []; + + /** + * Overwrite destination files newer than source files. + */ + protected $overwrite = true; + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->checkResources($this->dirs, 'dir')) { + return Result::error($this, 'Source directories are missing!'); + } + foreach ($this->dirs as $src => $dst) { + $this->copyDir($src, $dst); + $this->printTaskInfo('Copied from {source} to {destination}', ['source' => $src, 'destination' => $dst]); + } + return Result::success($this); + } + + /** + * Sets the default folder permissions for the destination if it doesn't exist + * + * @link http://en.wikipedia.org/wiki/Chmod + * @link http://php.net/manual/en/function.mkdir.php + * @link http://php.net/manual/en/function.chmod.php + * + * @param int $value + * + * @return $this + */ + public function dirPermissions($value) + { + $this->chmod = (int)$value; + return $this; + } + + /** + * List files to exclude. + * + * @param string[] $exclude + * + * @return $this + */ + public function exclude($exclude = []) + { + $this->exclude = $this->simplifyForCompare($exclude); + return $this; + } + + /** + * Destination files newer than source files are overwritten. + * + * @param bool $overwrite + * + * @return $this + */ + public function overwrite($overwrite) + { + $this->overwrite = $overwrite; + return $this; + } + + /** + * Copies a directory to another location. + * + * @param string $src Source directory + * @param string $dst Destination directory + * @param string $parent Parent directory + * + * @throws \Robo\Exception\TaskException + */ + protected function copyDir($src, $dst, $parent = '') + { + $dir = @opendir($src); + if (false === $dir) { + throw new TaskException($this, "Cannot open source directory '" . $src . "'"); + } + if (!is_dir($dst)) { + mkdir($dst, $this->chmod, true); + } + while (false !== ($file = readdir($dir))) { + // Support basename and full path exclusion. + if ($this->excluded($file, $src, $parent)) { + continue; + } + $srcFile = $src . '/' . $file; + $destFile = $dst . '/' . $file; + if (is_dir($srcFile)) { + $this->copyDir($srcFile, $destFile, $parent . $file . DIRECTORY_SEPARATOR); + } else { + $this->fs->copy($srcFile, $destFile, $this->overwrite); + } + } + closedir($dir); + } + + /** + * Check to see if the current item is excluded. + */ + protected function excluded($file, $src, $parent) + { + return + ($file == '.') || + ($file == '..') || + in_array($file, $this->exclude) || + in_array($this->simplifyForCompare($parent . $file), $this->exclude) || + in_array($this->simplifyForCompare($src . DIRECTORY_SEPARATOR . $file), $this->exclude); + } + + /** + * Avoid problems comparing paths on Windows that may have a + * combination of DIRECTORY_SEPARATOR and /. + */ + protected function simplifyForCompare($item) + { + return str_replace(DIRECTORY_SEPARATOR, '/', $item); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/DeleteDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/DeleteDir.php new file mode 100644 index 00000000..25cf007b --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/DeleteDir.php @@ -0,0 +1,36 @@ +taskDeleteDir('tmp')->run(); + * // as shortcut + * $this->_deleteDir(['tmp', 'log']); + * ?> + * ``` + */ +class DeleteDir extends BaseDir +{ + use ResourceExistenceChecker; + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->checkResources($this->dirs, 'dir')) { + return Result::error($this, 'Source directories are missing!'); + } + foreach ($this->dirs as $dir) { + $this->fs->remove($dir); + $this->printTaskInfo("Deleted {dir}...", ['dir' => $dir]); + } + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/FilesystemStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/FilesystemStack.php new file mode 100644 index 00000000..8663e245 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/FilesystemStack.php @@ -0,0 +1,154 @@ +taskFilesystemStack() + * ->mkdir('logs') + * ->touch('logs/.gitignore') + * ->chgrp('www', 'www-data') + * ->symlink('/var/log/nginx/error.log', 'logs/error.log') + * ->run(); + * + * // one line + * $this->_touch('.gitignore'); + * $this->_mkdir('logs'); + * + * ?> + * ``` + * + * @method $this mkdir(string|array|\Traversable $dir, int $mode = 0777) + * @method $this touch(string|array|\Traversable $file, int $time = null, int $atime = null) + * @method $this copy(string $from, string $to, bool $force = false) + * @method $this chmod(string|array|\Traversable $file, int $permissions, int $umask = 0000, bool $recursive = false) + * @method $this chgrp(string|array|\Traversable $file, string $group, bool $recursive = false) + * @method $this chown(string|array|\Traversable $file, string $user, bool $recursive = false) + * @method $this remove(string|array|\Traversable $file) + * @method $this rename(string $from, string $to, bool $force = false) + * @method $this symlink(string $from, string $to, bool $copyOnWindows = false) + * @method $this mirror(string $from, string $to, \Traversable $iterator = null, array $options = []) + */ +class FilesystemStack extends StackBasedTask implements BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var \Symfony\Component\Filesystem\Filesystem + */ + protected $fs; + + public function __construct() + { + $this->fs = new sfFilesystem(); + } + + /** + * @return \Symfony\Component\Filesystem\Filesystem + */ + protected function getDelegate() + { + return $this->fs; + } + + /** + * @param string $from + * @param string $to + * @param bool $force + */ + protected function _copy($from, $to, $force = false) + { + $this->fs->copy($from, $to, $force); + } + + /** + * @param string|string[]|\Traversable $file + * @param int $permissions + * @param int $umask + * @param bool $recursive + */ + protected function _chmod($file, $permissions, $umask = 0000, $recursive = false) + { + $this->fs->chmod($file, $permissions, $umask, $recursive); + } + + /** + * @param string|string[]|\Traversable $file + * @param string $group + * @param bool $recursive + */ + protected function _chgrp($file, $group, $recursive = null) + { + $this->fs->chgrp($file, $group, $recursive); + } + + /** + * @param string|string[]|\Traversable $file + * @param string $user + * @param bool $recursive + */ + protected function _chown($file, $user, $recursive = null) + { + $this->fs->chown($file, $user, $recursive); + } + + /** + * @param string $origin + * @param string $target + * @param bool $overwrite + * + * @return null|true|\Robo\Result + */ + protected function _rename($origin, $target, $overwrite = false) + { + // we check that target does not exist + if ((!$overwrite && is_readable($target)) || (file_exists($target) && !is_writable($target))) { + throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); + } + + // Due to a bug (limitation) in PHP, cross-volume renames do not work. + // See: https://bugs.php.net/bug.php?id=54097 + if (true !== @rename($origin, $target)) { + return $this->crossVolumeRename($origin, $target); + } + return true; + } + + /** + * @param string $origin + * @param string $target + * + * @return null|\Robo\Result + */ + protected function crossVolumeRename($origin, $target) + { + // First step is to try to get rid of the target. If there + // is a single, deletable file, then we will just unlink it. + if (is_file($target)) { + unlink($target); + } + // If the target still exists, we will try to delete it. + // TODO: Note that if this fails partway through, then we cannot + // adequately rollback. Perhaps we need to preflight the operation + // and determine if everything inside of $target is writable. + if (file_exists($target)) { + $this->fs->remove($target); + } + + /** @var \Robo\Result $result */ + $result = $this->collectionBuilder()->taskCopyDir([$origin => $target])->run(); + if (!$result->wasSuccessful()) { + return $result; + } + $this->fs->remove($origin); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/FlattenDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/FlattenDir.php new file mode 100644 index 00000000..6e885112 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/FlattenDir.php @@ -0,0 +1,294 @@ +taskFlattenDir(['assets/*.min.js' => 'dist'])->run(); + * // or use shortcut + * $this->_flattenDir('assets/*.min.js', 'dist'); + * ?> + * ``` + * + * You can also define the target directory with an additional method, instead of + * key/value pairs. More similar to the gulp-flatten syntax: + * + * ``` php + * taskFlattenDir(['assets/*.min.js']) + * ->to('dist') + * ->run(); + * ?> + * ``` + * + * You can also append parts of the parent directories to the target path. If you give + * the value `1` to the `includeParents()` method, then the top parent will be appended + * to the target directory resulting in a path such as `dist/assets/asset-library1.min.js`. + * + * If you give a negative number, such as `-1` (the same as specifying `array(0, 1)` then + * the bottom parent will be appended, resulting in a path such as + * `dist/asset-library1/asset-library1.min.js`. + * + * The top parent directory will always be starting from the relative path to the current + * directory. You can override that with the `parentDir()` method. If in the above example + * you would specify `assets`, then the top parent directory would be `asset-library1`. + * + * ``` php + * taskFlattenDir(['assets/*.min.js' => 'dist']) + * ->parentDir('assets') + * ->includeParents(1) + * ->run(); + * ?> + * ``` + */ +class FlattenDir extends BaseDir +{ + /** + * @var int + */ + protected $chmod = 0755; + + /** + * @var int[] + */ + protected $parents = array(0, 0); + + /** + * @var string + */ + protected $parentDir = ''; + + /** + * @var string + */ + protected $to; + + /** + * {@inheritdoc} + */ + public function __construct($dirs) + { + parent::__construct($dirs); + $this->parentDir = getcwd(); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // find the files + $files = $this->findFiles($this->dirs); + + // copy the files + $this->copyFiles($files); + + $fileNoun = count($files) == 1 ? ' file' : ' files'; + $this->printTaskSuccess("Copied {count} $fileNoun to {destination}", ['count' => count($files), 'destination' => $this->to]); + + return Result::success($this); + } + + /** + * Sets the default folder permissions for the destination if it does not exist. + * + * @link http://en.wikipedia.org/wiki/Chmod + * @link http://php.net/manual/en/function.mkdir.php + * @link http://php.net/manual/en/function.chmod.php + * + * @param int $permission + * + * @return $this + */ + public function dirPermissions($permission) + { + $this->chmod = (int) $permission; + + return $this; + } + + /** + * Sets the value from which direction and how much parent dirs should be included. + * Accepts a positive or negative integer or an array with two integer values. + * + * @param int|int[] $parents + * + * @return $this + * + * @throws TaskException + */ + public function includeParents($parents) + { + if (is_int($parents)) { + // if an integer is given check whether it is for top or bottom parent + if ($parents >= 0) { + $this->parents[0] = $parents; + return $this; + } + $this->parents[1] = 0 - $parents; + return $this; + } + + if (is_array($parents)) { + // check if the array has two values no more, no less + if (count($parents) == 2) { + $this->parents = $parents; + return $this; + } + } + + throw new TaskException($this, 'includeParents expects an integer or an array with two values'); + } + + /** + * Sets the parent directory from which the relative parent directories will be calculated. + * + * @param string $dir + * + * @return $this + */ + public function parentDir($dir) + { + if (!$this->fs->isAbsolutePath($dir)) { + // attach the relative path to current working directory + $dir = getcwd().'/'.$dir; + } + $this->parentDir = $dir; + + return $this; + } + + /** + * Sets the target directory where the files will be copied to. + * + * @param string $target + * + * @return $this + */ + public function to($target) + { + $this->to = rtrim($target, '/'); + + return $this; + } + + /** + * @param array $dirs + * + * @return array|\Robo\Result + * + * @throws \Robo\Exception\TaskException + */ + protected function findFiles($dirs) + { + $files = array(); + + // find the files + foreach ($dirs as $k => $v) { + // reset finder + $finder = new Finder(); + + $dir = $k; + $to = $v; + // check if target was given with the to() method instead of key/value pairs + if (is_int($k)) { + $dir = $v; + if (isset($this->to)) { + $to = $this->to; + } else { + throw new TaskException($this, 'target directory is not defined'); + } + } + + try { + $finder->files()->in($dir); + } catch (\InvalidArgumentException $e) { + // if finder cannot handle it, try with in()->name() + if (strpos($dir, '/') === false) { + $dir = './'.$dir; + } + $parts = explode('/', $dir); + $new_dir = implode('/', array_slice($parts, 0, -1)); + try { + $finder->files()->in($new_dir)->name(array_pop($parts)); + } catch (\InvalidArgumentException $e) { + return Result::fromException($this, $e); + } + } + + foreach ($finder as $file) { + // store the absolute path as key and target as value in the files array + $files[$file->getRealpath()] = $this->getTarget($file->getRealPath(), $to); + } + $fileNoun = count($files) == 1 ? ' file' : ' files'; + $this->printTaskInfo("Found {count} $fileNoun in {dir}", ['count' => count($files), 'dir' => $dir]); + } + + return $files; + } + + /** + * @param string $file + * @param string $to + * + * @return string + */ + protected function getTarget($file, $to) + { + $target = $to.'/'.basename($file); + if ($this->parents !== array(0, 0)) { + // if the parent is set, create additional directories inside target + // get relative path to parentDir + $rel_path = $this->fs->makePathRelative(dirname($file), $this->parentDir); + // get top parents and bottom parents + $parts = explode('/', rtrim($rel_path, '/')); + $prefix_dir = ''; + $prefix_dir .= ($this->parents[0] > 0 ? implode('/', array_slice($parts, 0, $this->parents[0])).'/' : ''); + $prefix_dir .= ($this->parents[1] > 0 ? implode('/', array_slice($parts, (0 - $this->parents[1]), $this->parents[1])) : ''); + $prefix_dir = rtrim($prefix_dir, '/'); + $target = $to.'/'.$prefix_dir.'/'.basename($file); + } + + return $target; + } + + /** + * @param array $files + */ + protected function copyFiles($files) + { + // copy the files + foreach ($files as $from => $to) { + // check if target dir exists + if (!is_dir(dirname($to))) { + $this->fs->mkdir(dirname($to), $this->chmod); + } + $this->fs->copy($from, $to); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/MirrorDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/MirrorDir.php new file mode 100644 index 00000000..4eda9097 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/MirrorDir.php @@ -0,0 +1,40 @@ +taskMirrorDir(['dist/config/' => 'config/'])->run(); + * // or use shortcut + * $this->_mirrorDir('dist/config/', 'config/'); + * + * ?> + * ``` + */ +class MirrorDir extends BaseDir +{ + /** + * {@inheritdoc} + */ + public function run() + { + foreach ($this->dirs as $src => $dst) { + $this->fs->mirror( + $src, + $dst, + null, + [ + 'override' => true, + 'copy_on_windows' => true, + 'delete' => true + ] + ); + $this->printTaskInfo("Mirrored from {source} to {destination}", ['source' => $src, 'destination' => $dst]); + } + return Result::success($this); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/TmpDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/TmpDir.php new file mode 100644 index 00000000..104318de --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/TmpDir.php @@ -0,0 +1,173 @@ +run(). + * $collection = $this->collectionBuilder(); + * $tmpPath = $collection->tmpDir()->getPath(); + * $collection->taskFilesystemStack() + * ->mkdir("$tmpPath/log") + * ->touch("$tmpPath/log/error.txt"); + * $collection->run(); + * // as shortcut (deleted when program exits) + * $tmpPath = $this->_tmpDir(); + * ?> + * ``` + */ +class TmpDir extends BaseDir implements CompletionInterface +{ + /** + * @var string + */ + protected $base; + + /** + * @var string + */ + protected $prefix; + + /** + * @var bool + */ + protected $cwd; + + /** + * @var string + */ + protected $savedWorkingDirectory; + + /** + * @param string $prefix + * @param string $base + * @param bool $includeRandomPart + */ + public function __construct($prefix = 'tmp', $base = '', $includeRandomPart = true) + { + if (empty($base)) { + $base = sys_get_temp_dir(); + } + $path = "{$base}/{$prefix}"; + if ($includeRandomPart) { + $path = static::randomLocation($path); + } + parent::__construct(["$path"]); + } + + /** + * Add a random part to a path, ensuring that the directory does + * not (currently) exist. + * + * @param string $path The base/prefix path to add a random component to + * @param int $length Number of digits in the random part + * + * @return string + */ + protected static function randomLocation($path, $length = 12) + { + $random = static::randomString($length); + while (is_dir("{$path}_{$random}")) { + $random = static::randomString($length); + } + return "{$path}_{$random}"; + } + + /** + * Generate a suitably random string to use as the suffix for our + * temporary directory. + * + * @param int $length + * + * @return string + */ + protected static function randomString($length = 12) + { + return substr(str_shuffle('23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'), 0, max($length, 3)); + } + + /** + * Flag that we should cwd to the temporary directory when it is + * created, and restore the old working directory when it is deleted. + * + * @param bool $shouldChangeWorkingDirectory + * + * @return $this + */ + public function cwd($shouldChangeWorkingDirectory = true) + { + $this->cwd = $shouldChangeWorkingDirectory; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Save the current working directory + $this->savedWorkingDirectory = getcwd(); + foreach ($this->dirs as $dir) { + $this->fs->mkdir($dir); + $this->printTaskInfo("Created {dir}...", ['dir' => $dir]); + + // Change the current working directory, if requested + if ($this->cwd) { + chdir($dir); + } + } + + return Result::success($this, '', ['path' => $this->getPath()]); + } + + protected function restoreWorkingDirectory() + { + // Restore the current working directory, if we redirected it. + if ($this->cwd) { + chdir($this->savedWorkingDirectory); + } + } + + protected function deleteTmpDir() + { + foreach ($this->dirs as $dir) { + $this->fs->remove($dir); + } + } + + /** + * Delete this directory when our collection completes. + * If this temporary directory is not part of a collection, + * then it will be deleted when the program terminates, + * presuming that it was created by taskTmpDir() or _tmpDir(). + */ + public function complete() + { + $this->restoreWorkingDirectory(); + $this->deleteTmpDir(); + } + + /** + * Get a reference to the path to the temporary directory, so that + * it may be used to create other tasks. Note that the directory + * is not actually created until the task runs. + * + * @return string + */ + public function getPath() + { + return $this->dirs[0]; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/WorkDir.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/WorkDir.php new file mode 100644 index 00000000..4b75c6ed --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/WorkDir.php @@ -0,0 +1,126 @@ +collectionBuilder(); + * $workingPath = $collection->workDir("build")->getPath(); + * $collection->taskFilesystemStack() + * ->mkdir("$workingPath/log") + * ->touch("$workingPath/log/error.txt"); + * $collection->run(); + * ?> + * ``` + */ +class WorkDir extends TmpDir implements RollbackInterface, BuilderAwareInterface +{ + use BuilderAwareTrait; + + /** + * @var string + */ + protected $finalDestination; + + /** + * @param string $finalDestination + */ + public function __construct($finalDestination) + { + $this->finalDestination = $finalDestination; + + // Create a temporary directory to work in. We will place our + // temporary directory in the same location as the final destination + // directory, so that the work directory can be moved into place + // without having to be copied, e.g. in a cross-volume rename scenario. + parent::__construct(basename($finalDestination), dirname($finalDestination)); + } + + /** + * Create our working directory. + * + * @return \Robo\Result + */ + public function run() + { + // Destination cannot be empty + if (empty($this->finalDestination)) { + return Result::error($this, "Destination directory not specified."); + } + + // Before we do anything else, ensure that any directory in the + // final destination is writable, so that we can at a minimum + // move it out of the way before placing our results there. + if (is_dir($this->finalDestination)) { + if (!is_writable($this->finalDestination)) { + return Result::error($this, "Destination directory {dir} exists and cannot be overwritten.", ['dir' => $this->finalDestination]); + } + } + + return parent::run(); + } + + /** + * Move our working directory into its final destination once the + * collection it belongs to completes. + */ + public function complete() + { + $this->restoreWorkingDirectory(); + + // Delete the final destination, if it exists. + // Move it out of the way first, in case it cannot + // be completely deleted. + if (file_exists($this->finalDestination)) { + $temporaryLocation = static::randomLocation($this->finalDestination . '_TO_DELETE_'); + // This should always work, because we already created a temporary + // folder in the parent directory of the final destination, and we + // have already checked to confirm that the final destination is + // writable. + rename($this->finalDestination, $temporaryLocation); + // This may silently fail, leaving artifacts behind, if there + // are permissions problems with some items somewhere inside + // the folder being deleted. + $this->fs->remove($temporaryLocation); + } + + // Move our working directory over the final destination. + // This should never be a cross-volume rename, so this should + // always succeed. + $workDir = reset($this->dirs); + if (file_exists($workDir)) { + rename($workDir, $this->finalDestination); + } + } + + /** + * Delete our working directory + */ + public function rollback() + { + $this->restoreWorkingDirectory(); + $this->deleteTmpDir(); + } + + /** + * Get a reference to the path to the temporary directory, so that + * it may be used to create other tasks. Note that the directory + * is not actually created until the task runs. + * + * @return string + */ + public function getPath() + { + return $this->dirs[0]; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/loadShortcuts.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/loadShortcuts.php new file mode 100644 index 00000000..fe72ce5a --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/loadShortcuts.php @@ -0,0 +1,159 @@ +taskCopyDir([$src => $dst])->run(); + } + + /** + * @param string $src + * @param string $dst + * + * @return \Robo\Result + */ + protected function _mirrorDir($src, $dst) + { + return $this->taskMirrorDir([$src => $dst])->run(); + } + + /** + * @param string|string[] $dir + * + * @return \Robo\Result + */ + protected function _deleteDir($dir) + { + return $this->taskDeleteDir($dir)->run(); + } + + /** + * @param string|string[] $dir + * + * @return \Robo\Result + */ + protected function _cleanDir($dir) + { + return $this->taskCleanDir($dir)->run(); + } + + /** + * @param string $from + * @param string $to + * @param bool $overwrite + * + * @return \Robo\Result + */ + protected function _rename($from, $to, $overwrite = false) + { + return $this->taskFilesystemStack()->rename($from, $to, $overwrite)->run(); + } + + /** + * @param string|string[] $dir + * + * @return \Robo\Result + */ + protected function _mkdir($dir) + { + return $this->taskFilesystemStack()->mkdir($dir)->run(); + } + + /** + * @param string $prefix + * @param string $base + * @param bool $includeRandomPart + * + * @return string + */ + protected function _tmpDir($prefix = 'tmp', $base = '', $includeRandomPart = true) + { + $result = $this->taskTmpDir($prefix, $base, $includeRandomPart)->run(); + return isset($result['path']) ? $result['path'] : ''; + } + + /** + * @param string $file + * + * @return \Robo\Result + */ + protected function _touch($file) + { + return $this->taskFilesystemStack()->touch($file)->run(); + } + + /** + * @param string|string[] $file + * + * @return \Robo\Result + */ + protected function _remove($file) + { + return $this->taskFilesystemStack()->remove($file)->run(); + } + + /** + * @param string|string[] $file + * @param string $group + * + * @return \Robo\Result + */ + protected function _chgrp($file, $group) + { + return $this->taskFilesystemStack()->chgrp($file, $group)->run(); + } + + /** + * @param string|string[] $file + * @param int $permissions + * @param int $umask + * @param bool $recursive + * + * @return \Robo\Result + */ + protected function _chmod($file, $permissions, $umask = 0000, $recursive = false) + { + return $this->taskFilesystemStack()->chmod($file, $permissions, $umask, $recursive)->run(); + } + + /** + * @param string $from + * @param string $to + * + * @return \Robo\Result + */ + protected function _symlink($from, $to) + { + return $this->taskFilesystemStack()->symlink($from, $to)->run(); + } + + /** + * @param string $from + * @param string $to + * + * @return \Robo\Result + */ + protected function _copy($from, $to) + { + return $this->taskFilesystemStack()->copy($from, $to)->run(); + } + + /** + * @param string $from + * @param string $to + * + * @return \Robo\Result + */ + protected function _flattenDir($from, $to) + { + return $this->taskFlattenDir([$from => $to])->run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/loadTasks.php new file mode 100644 index 00000000..8fecaaff --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Filesystem/loadTasks.php @@ -0,0 +1,85 @@ +task(CleanDir::class, $dirs); + } + + /** + * @param string|string[] $dirs + * + * @return \Robo\Task\Filesystem\DeleteDir + */ + protected function taskDeleteDir($dirs) + { + return $this->task(DeleteDir::class, $dirs); + } + + /** + * @param string $prefix + * @param string $base + * @param bool $includeRandomPart + * + * @return \Robo\Task\Filesystem\WorkDir + */ + protected function taskTmpDir($prefix = 'tmp', $base = '', $includeRandomPart = true) + { + return $this->task(TmpDir::class, $prefix, $base, $includeRandomPart); + } + + /** + * @param string $finalDestination + * + * @return \Robo\Task\Filesystem\TmpDir + */ + protected function taskWorkDir($finalDestination) + { + return $this->task(WorkDir::class, $finalDestination); + } + + /** + * @param string|string[] $dirs + * + * @return \Robo\Task\Filesystem\CopyDir + */ + protected function taskCopyDir($dirs) + { + return $this->task(CopyDir::class, $dirs); + } + + /** + * @param string|string[] $dirs + * + * @return \Robo\Task\Filesystem\MirrorDir + */ + protected function taskMirrorDir($dirs) + { + return $this->task(MirrorDir::class, $dirs); + } + + /** + * @param string|string[] $dirs + * + * @return \Robo\Task\Filesystem\FlattenDir + */ + protected function taskFlattenDir($dirs) + { + return $this->task(FlattenDir::class, $dirs); + } + + /** + * @return \Robo\Task\Filesystem\FilesystemStack + */ + protected function taskFilesystemStack() + { + return $this->task(FilesystemStack::class); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/Base.php new file mode 100644 index 00000000..42728673 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/Base.php @@ -0,0 +1,97 @@ +option('silent'); + return $this; + } + + /** + * adds `--no-color` option to gulp + * + * @return $this + */ + public function noColor() + { + $this->option('no-color'); + return $this; + } + + /** + * adds `--color` option to gulp + * + * @return $this + */ + public function color() + { + $this->option('color'); + return $this; + } + + /** + * adds `--tasks-simple` option to gulp + * + * @return $this + */ + public function simple() + { + $this->option('tasks-simple'); + return $this; + } + + /** + * @param string $task + * @param null|string $pathToGulp + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($task, $pathToGulp = null) + { + $this->task = $task; + $this->command = $pathToGulp; + if (!$this->command) { + $this->command = $this->findExecutable('gulp'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Gulp executable not found."); + } + } + + /** + * @return string + */ + public function getCommand() + { + return "{$this->command} " . ProcessUtils::escapeArgument($this->task) . "{$this->arguments}"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/Run.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/Run.php new file mode 100644 index 00000000..8f2077b5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/Run.php @@ -0,0 +1,35 @@ +taskGulpRun()->run(); + * + * // run task 'clean' with --silent option + * $this->taskGulpRun('clean') + * ->silent() + * ->run(); + * ?> + * ``` + */ +class Run extends Base implements CommandInterface +{ + /** + * {@inheritdoc} + */ + public function run() + { + if (strlen($this->arguments)) { + $this->printTaskInfo('Running Gulp task: {gulp_task} with arguments: {arguments}', ['gulp_task' => $this->task, 'arguments' => $this->arguments]); + } else { + $this->printTaskInfo('Running Gulp task: {gulp_task} without arguments', ['gulp_task' => $this->task]); + } + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/loadTasks.php new file mode 100644 index 00000000..6fdc6ca7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Gulp/loadTasks.php @@ -0,0 +1,16 @@ +task(Run::class, $task, $pathToGulp); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Base.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Base.php new file mode 100644 index 00000000..35ff9c48 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Base.php @@ -0,0 +1,60 @@ +option('production'); + return $this; + } + + /** + * @param null|string $pathToNpm + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToNpm = null) + { + $this->command = $pathToNpm; + if (!$this->command) { + $this->command = $this->findExecutable('npm'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Npm executable not found."); + } + } + + /** + * @return string + */ + public function getCommand() + { + return "{$this->command} {$this->action}{$this->arguments}"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Install.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Install.php new file mode 100644 index 00000000..65cbe618 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Install.php @@ -0,0 +1,36 @@ +taskNpmInstall()->run(); + * + * // prefer dist with custom path + * $this->taskNpmInstall('path/to/my/npm') + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class Install extends Base implements CommandInterface +{ + /** + * @var string + */ + protected $action = 'install'; + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Install Npm packages: {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Update.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Update.php new file mode 100644 index 00000000..75421b30 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/Update.php @@ -0,0 +1,34 @@ +taskNpmUpdate()->run(); + * + * // prefer dist with custom path + * $this->taskNpmUpdate('path/to/my/npm') + * ->noDev() + * ->run(); + * ?> + * ``` + */ +class Update extends Base +{ + /** + * @var string + */ + protected $action = 'update'; + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Update Npm packages: {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/loadTasks.php new file mode 100644 index 00000000..4d9a26eb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Npm/loadTasks.php @@ -0,0 +1,25 @@ +task(Install::class, $pathToNpm); + } + + /** + * @param null|string $pathToNpm + * + * @return \Robo\Task\Npm\Update + */ + protected function taskNpmUpdate($pathToNpm = null) + { + return $this->task(Update::class, $pathToNpm); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/Rsync.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/Rsync.php new file mode 100644 index 00000000..5c334af4 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/Rsync.php @@ -0,0 +1,484 @@ +taskRsync() + * ->fromPath('src/') + * ->toHost('localhost') + * ->toUser('dev') + * ->toPath('/var/www/html/app/') + * ->remoteShell('ssh -i public_key') + * ->recursive() + * ->excludeVcs() + * ->checksum() + * ->wholeFile() + * ->verbose() + * ->progress() + * ->humanReadable() + * ->stats() + * ->run(); + * ``` + * + * You could also clone the task and do a dry-run first: + * + * ``` php + * $rsync = $this->taskRsync() + * ->fromPath('src/') + * ->toPath('example.com:/var/www/html/app/') + * ->archive() + * ->excludeVcs() + * ->progress() + * ->stats(); + * + * $dryRun = clone $rsync; + * $dryRun->dryRun()->run(); + * if ('y' === $this->ask('Do you want to run (y/n)')) { + * $rsync->run(); + * } + * ``` + */ +class Rsync extends BaseTask implements CommandInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * @var string + */ + protected $fromUser; + + /** + * @var string + */ + protected $fromHost; + + /** + * @var string + */ + protected $fromPath; + + /** + * @var string + */ + protected $toUser; + + /** + * @var string + */ + protected $toHost; + + /** + * @var string + */ + protected $toPath; + + /** + * @return static + */ + public static function init() + { + return new static(); + } + + public function __construct() + { + $this->command = 'rsync'; + } + + /** + * This can either be a full rsync path spec (user@host:path) or just a path. + * In case of the former do not specify host and user. + * + * @param string|array $path + * + * @return $this + */ + public function fromPath($path) + { + $this->fromPath = $path; + + return $this; + } + + /** + * This can either be a full rsync path spec (user@host:path) or just a path. + * In case of the former do not specify host and user. + * + * @param string $path + * + * @return $this + */ + public function toPath($path) + { + $this->toPath = $path; + + return $this; + } + + /** + * @param string $fromUser + * + * @return $this + */ + public function fromUser($fromUser) + { + $this->fromUser = $fromUser; + return $this; + } + + /** + * @param string $fromHost + * + * @return $this + */ + public function fromHost($fromHost) + { + $this->fromHost = $fromHost; + return $this; + } + + /** + * @param string $toUser + * + * @return $this + */ + public function toUser($toUser) + { + $this->toUser = $toUser; + return $this; + } + + /** + * @param string $toHost + * + * @return $this + */ + public function toHost($toHost) + { + $this->toHost = $toHost; + return $this; + } + + /** + * @return $this + */ + public function progress() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function stats() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function recursive() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function verbose() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function checksum() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function archive() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function compress() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function owner() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function group() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function times() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @return $this + */ + public function delete() + { + $this->option(__FUNCTION__); + + return $this; + } + + /** + * @param int $seconds + * + * @return $this + */ + public function timeout($seconds) + { + $this->option(__FUNCTION__, $seconds); + + return $this; + } + + /** + * @return $this + */ + public function humanReadable() + { + $this->option('human-readable'); + + return $this; + } + + /** + * @return $this + */ + public function wholeFile() + { + $this->option('whole-file'); + + return $this; + } + + /** + * @return $this + */ + public function dryRun() + { + $this->option('dry-run'); + + return $this; + } + + /** + * @return $this + */ + public function itemizeChanges() + { + $this->option('itemize-changes'); + + return $this; + } + + /** + * Excludes .git, .svn and .hg items at any depth. + * + * @return $this + */ + public function excludeVcs() + { + return $this->exclude([ + '.git', + '.svn', + '.hg', + ]); + } + + /** + * @param array|string $pattern + * + * @return $this + */ + public function exclude($pattern) + { + return $this->optionList(__FUNCTION__, $pattern); + } + + /** + * @param string $file + * + * @return $this + * + * @throws \Robo\Exception\TaskException + */ + public function excludeFrom($file) + { + if (!is_readable($file)) { + throw new TaskException($this, "Exclude file $file is not readable"); + } + + return $this->option('exclude-from', $file); + } + + /** + * @param array|string $pattern + * + * @return $this + */ + public function includeFilter($pattern) + { + return $this->optionList('include', $pattern); + } + + /** + * @param array|string $pattern + * + * @return $this + */ + public function filter($pattern) + { + return $this->optionList(__FUNCTION__, $pattern); + } + + /** + * @param string $file + * + * @return $this + * + * @throws \Robo\Exception\TaskException + */ + public function filesFrom($file) + { + if (!is_readable($file)) { + throw new TaskException($this, "Files-from file $file is not readable"); + } + + return $this->option('files-from', $file); + } + + /** + * @param string $command + * + * @return $this + */ + public function remoteShell($command) + { + $this->option('rsh', "'$command'"); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + + return $this->executeCommand($command); + } + + /** + * Returns command that can be executed. + * This method is used to pass generated command from one task to another. + * + * @return string + */ + public function getCommand() + { + foreach ((array)$this->fromPath as $from) { + $this->option(null, $this->getFromPathSpec($from)); + } + $this->option(null, $this->getToPathSpec()); + + return $this->command . $this->arguments; + } + + /** + * @return string + */ + protected function getFromPathSpec($from) + { + return $this->getPathSpec($this->fromHost, $this->fromUser, $from); + } + + /** + * @return string + */ + protected function getToPathSpec() + { + return $this->getPathSpec($this->toHost, $this->toUser, $this->toPath); + } + + /** + * @param string $host + * @param string $user + * @param string $path + * + * @return string + */ + protected function getPathSpec($host, $user, $path) + { + $spec = isset($path) ? $path : ''; + if (!empty($host)) { + $spec = "{$host}:{$spec}"; + } + if (!empty($user)) { + $spec = "{$user}@{$spec}"; + } + + return $spec; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/Ssh.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/Ssh.php new file mode 100644 index 00000000..69df9fe2 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/Ssh.php @@ -0,0 +1,273 @@ +taskSshExec('remote.example.com', 'user') + * ->remoteDir('/var/www/html') + * ->exec('ls -la') + * ->exec('chmod g+x logs') + * ->run(); + * + * ``` + * + * You can even exec other tasks (which implement CommandInterface): + * + * ```php + * $gitTask = $this->taskGitStack() + * ->checkout('master') + * ->pull(); + * + * $this->taskSshExec('remote.example.com') + * ->remoteDir('/var/www/html/site') + * ->exec($gitTask) + * ->run(); + * ``` + * + * You can configure the remote directory for all future calls: + * + * ```php + * \Robo\Task\Remote\Ssh::configure('remoteDir', '/some-dir'); + * ``` + */ +class Ssh extends BaseTask implements CommandInterface, SimulatedInterface +{ + use \Robo\Common\CommandReceiver; + use \Robo\Common\ExecOneCommand; + + /** + * @var null|string + */ + protected $hostname; + + /** + * @var null|string + */ + protected $user; + + /** + * @var bool + */ + protected $stopOnFail = true; + + /** + * @var array + */ + protected $exec = []; + + /** + * Changes to the given directory before running commands. + * + * @var string + */ + protected $remoteDir; + + /** + * @param null|string $hostname + * @param null|string $user + */ + public function __construct($hostname = null, $user = null) + { + $this->hostname = $hostname; + $this->user = $user; + } + + /** + * @param string $hostname + * + * @return $this + */ + public function hostname($hostname) + { + $this->hostname = $hostname; + return $this; + } + + /** + * @param string $user + * + * @return $this + */ + public function user($user) + { + $this->user = $user; + return $this; + } + + /** + * Whether or not to chain commands together with && and stop the chain if one command fails. + * + * @param bool $stopOnFail + * + * @return $this + */ + public function stopOnFail($stopOnFail = true) + { + $this->stopOnFail = $stopOnFail; + return $this; + } + + /** + * Changes to the given directory before running commands. + * + * @param string $remoteDir + * + * @return $this + */ + public function remoteDir($remoteDir) + { + $this->remoteDir = $remoteDir; + return $this; + } + + /** + * @param string $filename + * + * @return $this + */ + public function identityFile($filename) + { + $this->option('-i', $filename); + + return $this; + } + + /** + * @param int $port + * + * @return $this + */ + public function port($port) + { + $this->option('-p', $port); + + return $this; + } + + /** + * @return $this + */ + public function forcePseudoTty() + { + $this->option('-t'); + + return $this; + } + + /** + * @return $this + */ + public function quiet() + { + $this->option('-q'); + + return $this; + } + + /** + * @return $this + */ + public function verbose() + { + $this->option('-v'); + + return $this; + } + + /** + * @param string|string[]|CommandInterface $command + * + * @return $this + */ + public function exec($command) + { + if (is_array($command)) { + $command = implode(' ', array_filter($command)); + } + + $this->exec[] = $command; + + return $this; + } + + /** + * Returns command that can be executed. + * This method is used to pass generated command from one task to another. + * + * @return string + */ + public function getCommand() + { + $commands = []; + foreach ($this->exec as $command) { + $commands[] = $this->receiveCommand($command); + } + + $remoteDir = $this->remoteDir ? $this->remoteDir : $this->getConfigValue('remoteDir'); + if (!empty($remoteDir)) { + array_unshift($commands, sprintf('cd "%s"', $remoteDir)); + } + $command = implode($this->stopOnFail ? ' && ' : ' ; ', $commands); + + return $this->sshCommand($command); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->validateParameters(); + $command = $this->getCommand(); + return $this->executeCommand($command); + } + + /** + * {@inheritdoc} + */ + public function simulate($context) + { + $command = $this->getCommand(); + $this->printTaskInfo("Running {command}", ['command' => $command] + $context); + } + + protected function validateParameters() + { + if (empty($this->hostname)) { + throw new TaskException($this, 'Please set a hostname'); + } + if (empty($this->exec)) { + throw new TaskException($this, 'Please add at least one command'); + } + } + + /** + * Returns an ssh command string running $command on the remote. + * + * @param string|CommandInterface $command + * + * @return string + */ + protected function sshCommand($command) + { + $command = $this->receiveCommand($command); + $sshOptions = $this->arguments; + $hostSpec = $this->hostname; + if ($this->user) { + $hostSpec = $this->user . '@' . $hostSpec; + } + + return "ssh{$sshOptions} {$hostSpec} '{$command}'"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/loadTasks.php new file mode 100644 index 00000000..092d2a55 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Remote/loadTasks.php @@ -0,0 +1,24 @@ +task(Rsync::class); + } + + /** + * @param null|string $hostname + * @param null|string $user + * + * @return \Robo\Task\Remote\Ssh + */ + protected function taskSshExec($hostname = null, $user = null) + { + return $this->task(Ssh::class, $hostname, $user); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Simulator.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Simulator.php new file mode 100644 index 00000000..e69d23fa --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Simulator.php @@ -0,0 +1,168 @@ +task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; + $this->constructorParameters = $constructorParameters; + } + + /** + * @param string $function + * @param array $args + * + * @return \Robo\Result|\Robo\Task\Simulator + */ + public function __call($function, $args) + { + $this->stack[] = array_merge([$function], $args); + $result = call_user_func_array([$this->task, $function], $args); + return $result == $this->task ? $this : $result; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $callchain = ''; + foreach ($this->stack as $action) { + $command = array_shift($action); + $parameters = $this->formatParameters($action); + $callchain .= "\n ->$command($parameters)"; + } + $context = $this->getTaskContext( + [ + '_level' => RoboLogLevel::SIMULATED_ACTION, + 'simulated' => TaskInfo::formatTaskName($this->task), + 'parameters' => $this->formatParameters($this->constructorParameters), + '_style' => ['simulated' => 'fg=blue;options=bold'], + ] + ); + + // RoboLogLevel::SIMULATED_ACTION + $this->printTaskInfo( + "Simulating {simulated}({parameters})$callchain", + $context + ); + + $result = null; + if ($this->task instanceof SimulatedInterface) { + $result = $this->task->simulate($context); + } + if (!isset($result)) { + $result = Result::success($this); + } + + return $result; + } + + /** + * Danger: reach through the simulated wrapper and pull out the command + * to be executed. This is used when using a simulated task with another + * simulated task that runs commands, e.g. the Remote\Ssh task. Using + * a simulated CommandInterface task with a non-simulated task may produce + * unexpected results (e.g. execution!). + * + * @return string + * + * @throws \Robo\Exception\TaskException + */ + public function getCommand() + { + if (!$this->task instanceof CommandInterface) { + throw new TaskException($this->task, 'Simulated task that is not a CommandInterface used as a CommandInterface.'); + } + return $this->task->getCommand(); + } + + /** + * @param string $action + * + * @return string + */ + protected function formatParameters($action) + { + $parameterList = array_map([$this, 'convertParameter'], $action); + return implode(', ', $parameterList); + } + + /** + * @param mixed $item + * + * @return string + */ + protected function convertParameter($item) + { + if (is_callable($item)) { + return 'inline_function(...)'; + } + if (is_array($item)) { + return $this->shortenParameter(var_export($item, true)); + } + if (is_object($item)) { + return '[' . get_class($item). ' object]'; + } + if (is_string($item)) { + return $this->shortenParameter("'$item'"); + } + if (is_null($item)) { + return 'null'; + } + return $item; + } + + /** + * @param string $item + * @param string $shortForm + * + * @return string + */ + protected function shortenParameter($item, $shortForm = '') + { + $maxLength = 80; + $tailLength = 20; + if (strlen($item) < $maxLength) { + return $item; + } + if (!empty($shortForm)) { + return $shortForm; + } + $item = trim($item); + $tail = preg_replace("#.*\n#ms", '', substr($item, -$tailLength)); + $head = preg_replace("#\n.*#ms", '', substr($item, 0, $maxLength - (strlen($tail) + 5))); + return "$head ... $tail"; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/StackBasedTask.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/StackBasedTask.php new file mode 100644 index 00000000..91659f33 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/StackBasedTask.php @@ -0,0 +1,236 @@ +friz() + * ->fraz() + * ->frob(); + * + * We presume that the existing library throws an exception on error. + * + * You want: + * + * $result = $this->taskFrobinator($a, $b, $c) + * ->friz() + * ->fraz() + * ->frob() + * ->run(); + * + * Execution is deferred until run(), and a Robo\Result instance is + * returned. Additionally, using Robo will covert Exceptions + * into RoboResult objects. + * + * To create a new Robo task: + * + * - Make a new class that extends StackBasedTask + * - Give it a constructor that creates a new Frobinator + * - Override getDelegate(), and return the Frobinator instance + * + * Finally, add your new class to loadTasks.php as usual, + * and you are all done. + * + * If you need to add any methods to your task that should run + * immediately (e.g. to set parameters used at run() time), just + * implement them in your derived class. + * + * If you need additional methods that should run deferred, just + * define them as 'protected function _foo()'. Then, users may + * call $this->taskFrobinator()->foo() to get deferred execution + * of _foo(). + */ +abstract class StackBasedTask extends BaseTask +{ + /** + * @var array + */ + protected $stack = []; + + /** + * @var bool + */ + protected $stopOnFail = true; + + /** + * @param bool $stop + * + * @return $this + */ + public function stopOnFail($stop = true) + { + $this->stopOnFail = $stop; + return $this; + } + + /** + * Derived classes should override the getDelegate() method, and + * return an instance of the API class being wrapped. When this + * is done, any method of the delegate is available as a method of + * this class. Calling one of the delegate's methods will defer + * execution until the run() method is called. + * + * @return null + */ + protected function getDelegate() + { + return null; + } + + /** + * Derived classes that have more than one delegate may override + * getCommandList to add as many delegate commands as desired to + * the list of potential functions that __call() tried to find. + * + * @param string $function + * + * @return array + */ + protected function getDelegateCommandList($function) + { + return [[$this, "_$function"], [$this->getDelegate(), $function]]; + } + + /** + * Print progress about the commands being executed + * + * @param string $command + * @param string $action + */ + protected function printTaskProgress($command, $action) + { + $this->printTaskInfo('{command} {action}', ['command' => "{$command[1]}", 'action' => json_encode($action, JSON_UNESCAPED_SLASHES)]); + } + + /** + * Derived classes can override processResult to add more + * logic to result handling from functions. By default, it + * is assumed that if a function returns in int, then + * 0 == success, and any other value is the error code. + * + * @param int|\Robo\Result $function_result + * + * @return \Robo\Result + */ + protected function processResult($function_result) + { + if (is_int($function_result)) { + if ($function_result) { + return Result::error($this, $function_result); + } + } + return Result::success($this); + } + + /** + * Record a function to call later. + * + * @param string $command + * @param array $args + * + * @return $this + */ + protected function addToCommandStack($command, $args) + { + $this->stack[] = array_merge([$command], $args); + return $this; + } + + /** + * Any API function provided by the delegate that executes immediately + * may be handled by __call automatically. These operations will all + * be deferred until this task's run() method is called. + * + * @param string $function + * @param array $args + * + * @return $this + */ + public function __call($function, $args) + { + foreach ($this->getDelegateCommandList($function) as $command) { + if (method_exists($command[0], $command[1])) { + // Otherwise, we'll defer calling this function + // until run(), and return $this. + $this->addToCommandStack($command, $args); + return $this; + } + } + + $message = "Method $function does not exist.\n"; + throw new \BadMethodCallException($message); + } + + /** + * @return int + */ + public function progressIndicatorSteps() + { + // run() will call advanceProgressIndicator() once for each + // file, one after calling stopBuffering, and again after compression. + return count($this->stack); + } + + /** + * Run all of the queued objects on the stack + * + * @return \Robo\Result + */ + public function run() + { + $this->startProgressIndicator(); + $result = Result::success($this); + + foreach ($this->stack as $action) { + $command = array_shift($action); + $this->printTaskProgress($command, $action); + $this->advanceProgressIndicator(); + // TODO: merge data from the result on this call + // with data from the result on the previous call? + // For now, the result always comes from the last function. + $result = $this->callTaskMethod($command, $action); + if ($this->stopOnFail && $result && !$result->wasSuccessful()) { + break; + } + } + + $this->stopProgressIndicator(); + + // todo: add timing information to the result + return $result; + } + + /** + * Execute one task method + * + * @param string $command + * @param string $action + * + * @return \Robo\Result + */ + protected function callTaskMethod($command, $action) + { + try { + $function_result = call_user_func_array($command, $action); + return $this->processResult($function_result); + } catch (\Exception $e) { + $this->printTaskError($e->getMessage()); + return Result::fromException($this, $e); + } + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Atoum.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Atoum.php new file mode 100644 index 00000000..56b47d84 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Atoum.php @@ -0,0 +1,184 @@ +taskAtoum() + * ->files('path/to/test.php') + * ->configFile('config/dev.php') + * ->run() + * + * ?> + * ``` + */ +class Atoum extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * Atoum constructor. + * + * @param null|string $pathToAtoum + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToAtoum = null) + { + $this->command = $pathToAtoum; + if (!$this->command) { + $this->command = $this->findExecutable('atoum'); + } + if (!$this->command) { + throw new \Robo\Exception\TaskException(__CLASS__, "Neither local atoum nor global composer installation not found"); + } + } + + /** + * Tag or Tags to filter. + * + * @param string|array $tags + * + * @return $this + */ + public function tags($tags) + { + return $this->addMultipleOption('tags', $tags); + } + + /** + * Display result using the light reporter. + * + * @return $this + */ + public function lightReport() + { + $this->option("--use-light-report"); + + return $this; + } + + /** + * Display result using the tap reporter. + * + * @return $this + */ + public function tap() + { + $this->option("use-tap-report"); + + return $this; + } + + /** + * Path to the bootstrap file. + + * @param string $file + * + * @return $this + */ + public function bootstrap($file) + { + $this->option("bootstrap", $file); + + return $this; + } + + /** + * Path to the config file. + * + * @param string $file + * + * @return $this + */ + public function configFile($file) + { + $this->option('-c', $file); + + return $this; + } + + /** + * Use atoum's debug mode. + * + * @return $this + */ + public function debug() + { + $this->option("debug"); + + return $this; + } + + /** + * Test file or test files to run. + * + * @param string|array + * + * @return $this + */ + public function files($files) + { + return $this->addMultipleOption('f', $files); + } + + /** + * Test directory or directories to run. + * + * @param string|array A single directory or a list of directories. + * + * @return $this + */ + public function directories($directories) + { + return $this->addMultipleOption('directories', $directories); + } + + /** + * @param string $option + * @param string|array $values + * + * @return $this + */ + protected function addMultipleOption($option, $values) + { + if (is_string($values)) { + $values = [$values]; + } + + foreach ($values as $value) { + $this->option($option, $value); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . $this->arguments; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running atoum ' . $this->arguments); + + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Behat.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Behat.php new file mode 100644 index 00000000..7e4f1d41 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Behat.php @@ -0,0 +1,163 @@ +taskBehat() + * ->format('pretty') + * ->noInteraction() + * ->run(); + * ?> + * ``` + * + */ +class Behat extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * @var string[] $formaters available formaters for format option + */ + protected $formaters = ['progress', 'pretty', 'junit']; + + /** + * @var string[] $verbose_levels available verbose levels + */ + protected $verbose_levels = ['v', 'vv']; + + /** + * Behat constructor. + * + * @param null|string $pathToBehat + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToBehat = null) + { + $this->command = $pathToBehat; + if (!$this->command) { + $this->command = $this->findExecutable('behat'); + } + if (!$this->command) { + throw new \Robo\Exception\TaskException(__CLASS__, "Neither composer nor phar installation of Behat found"); + } + } + + /** + * @return $this + */ + public function stopOnFail() + { + $this->option('stop-on-failure'); + return $this; + } + + /** + * @return $this + */ + public function noInteraction() + { + $this->option('no-interaction'); + return $this; + } + + /** + * @param $config_file + * + * @return $this + */ + public function config($config_file) + { + $this->option('config', $config_file); + return $this; + } + + /** + * @return $this + */ + public function colors() + { + $this->option('colors'); + return $this; + } + + /** + * @return $this + */ + public function noColors() + { + $this->option('no-colors'); + return $this; + } + + /** + * @param string $suite + * + * @return $this + */ + public function suite($suite) + { + $this->option('suite', $suite); + return $this; + } + + /** + * @param string $level + * + * @return $this + */ + public function verbose($level = 'v') + { + if (!in_array($level, $this->verbose_levels)) { + throw new \InvalidArgumentException('expected ' . implode(',', $this->verbose_levels)); + } + $this->option('-' . $level); + return $this; + } + + /** + * @param string $formater + * + * @return $this + */ + public function format($formater) + { + if (!in_array($formater, $this->formaters)) { + throw new \InvalidArgumentException('expected ' . implode(',', $this->formaters)); + } + $this->option('format', $formater); + return $this; + } + + /** + * Returns command that can be executed. + * This method is used to pass generated command from one task to another. + * + * @return string + */ + public function getCommand() + { + return $this->command . $this->arguments; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running behat {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Codecept.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Codecept.php new file mode 100644 index 00000000..1f8cce70 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Codecept.php @@ -0,0 +1,271 @@ +taskCodecept() + * ->suite('acceptance') + * ->env('chrome') + * ->group('admin') + * ->xml() + * ->html() + * ->run(); + * + * ?> + * ``` + * + */ +class Codecept extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * @param string $pathToCodeception + * + * @throws \Robo\Exception\TaskException + */ + public function __construct($pathToCodeception = '') + { + $this->command = $pathToCodeception; + if (!$this->command) { + $this->command = $this->findExecutable('codecept'); + } + if (!$this->command) { + throw new TaskException(__CLASS__, "Neither composer nor phar installation of Codeception found."); + } + $this->command .= ' run'; + } + + /** + * @param string $suite + * + * @return $this + */ + public function suite($suite) + { + $this->option(null, $suite); + return $this; + } + + /** + * @param string $testName + * + * @return $this + */ + public function test($testName) + { + $this->option(null, $testName); + return $this; + } + + /** + * set group option. Can be called multiple times + * + * @param string $group + * + * @return $this + */ + public function group($group) + { + $this->option("group", $group); + return $this; + } + + /** + * @param string $group + * + * @return $this + */ + public function excludeGroup($group) + { + $this->option("skip-group", $group); + return $this; + } + + /** + * generate json report + * + * @param string $file + * + * @return $this + */ + public function json($file = null) + { + $this->option("json", $file); + return $this; + } + + /** + * generate xml JUnit report + * + * @param string $file + * + * @return $this + */ + public function xml($file = null) + { + $this->option("xml", $file); + return $this; + } + + /** + * Generate html report + * + * @param string $dir + * + * @return $this + */ + public function html($dir = null) + { + $this->option("html", $dir); + return $this; + } + + /** + * generate tap report + * + * @param string $file + * + * @return $this + */ + public function tap($file = null) + { + $this->option("tap", $file); + return $this; + } + + /** + * provides config file other then default `codeception.yml` with `-c` option + * + * @param string $file + * + * @return $this + */ + public function configFile($file) + { + $this->option("-c", $file); + return $this; + } + + /** + * collect codecoverage in raw format. You may pass name of cov file to save results + * + * @param null|string $cov + * + * @return $this + */ + public function coverage($cov = null) + { + $this->option("coverage", $cov); + return $this; + } + + /** + * execute in silent mode + * + * @return $this + */ + public function silent() + { + $this->option("silent"); + return $this; + } + + /** + * collect code coverage in xml format. You may pass name of xml file to save results + * + * @param string $xml + * + * @return $this + */ + public function coverageXml($xml = null) + { + $this->option("coverage-xml", $xml); + return $this; + } + + /** + * collect code coverage and generate html report. You may pass + * + * @param string $html + * + * @return $this + */ + public function coverageHtml($html = null) + { + $this->option("coverage-html", $html); + return $this; + } + + /** + * @param string $env + * + * @return $this + */ + public function env($env) + { + $this->option("env", $env); + return $this; + } + + /** + * @return $this + */ + public function debug() + { + $this->option("debug"); + return $this; + } + + /** + * @return $this + */ + public function noRebuild() + { + $this->option("no-rebuild"); + return $this; + } + + /** + * @param string $failGroup + * @return $this + */ + public function failGroup($failGroup) + { + $this->option('override', "extensions: config: Codeception\\Extension\\RunFailed: fail-group: {$failGroup}"); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . $this->arguments; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $command = $this->getCommand(); + $this->printTaskInfo('Executing {command}', ['command' => $command]); + return $this->executeCommand($command); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/PHPUnit.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/PHPUnit.php new file mode 100644 index 00000000..df67e1c7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/PHPUnit.php @@ -0,0 +1,199 @@ +taskPHPUnit() + * ->group('core') + * ->bootstrap('test/bootstrap.php') + * ->run() + * + * ?> + * ``` + */ +class PHPUnit extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * Directory of test files or single test file to run. Appended to + * the command and arguments. + * + * @var string + */ + protected $files = ''; + + public function __construct($pathToPhpUnit = null) + { + $this->command = $pathToPhpUnit; + if (!$this->command) { + $this->command = $this->findExecutablePhar('phpunit'); + } + if (!$this->command) { + throw new \Robo\Exception\TaskException(__CLASS__, "Neither local phpunit nor global composer installation not found"); + } + } + + /** + * @param string $filter + * + * @return $this + */ + public function filter($filter) + { + $this->option('filter', $filter); + return $this; + } + + /** + * @param string $group + * + * @return $this + */ + public function group($group) + { + $this->option("group", $group); + return $this; + } + + /** + * @param string $group + * + * @return $this + */ + public function excludeGroup($group) + { + $this->option("exclude-group", $group); + return $this; + } + + /** + * adds `log-json` option to runner + * + * @param string $file + * + * @return $this + */ + public function json($file = null) + { + $this->option("log-json", $file); + return $this; + } + + /** + * adds `log-junit` option + * + * @param string $file + * + * @return $this + */ + public function xml($file = null) + { + $this->option("log-junit", $file); + return $this; + } + + /** + * @param string $file + * + * @return $this + */ + public function tap($file = "") + { + $this->option("log-tap", $file); + return $this; + } + + /** + * @param string $file + * + * @return $this + */ + public function bootstrap($file) + { + $this->option("bootstrap", $file); + return $this; + } + + /** + * @param string $file + * + * @return $this + */ + public function configFile($file) + { + $this->option('-c', $file); + return $this; + } + + /** + * @return $this + */ + public function debug() + { + $this->option("debug"); + return $this; + } + + /** + * Directory of test files or single test file to run. + * + * @param string $files A single test file or a directory containing test files. + * + * @return $this + * + * @throws \Robo\Exception\TaskException + * + * @deprecated Use file() or dir() method instead + */ + public function files($files) + { + if (!empty($this->files) || is_array($files)) { + throw new \Robo\Exception\TaskException(__CLASS__, "Only one file or directory may be provided."); + } + $this->files = ' ' . $files; + + return $this; + } + + /** + * Test the provided file. + * + * @param string $file path to file to test + * + * @return $this + */ + public function file($file) + { + return $this->files($file); + } + + /** + * {@inheritdoc} + */ + public function getCommand() + { + return $this->command . $this->arguments . $this->files; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running PHPUnit {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Phpspec.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Phpspec.php new file mode 100644 index 00000000..dd6a5ae7 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/Phpspec.php @@ -0,0 +1,116 @@ +taskPhpspec() + * ->format('pretty') + * ->noInteraction() + * ->run(); + * ?> + * ``` + * + */ +class Phpspec extends BaseTask implements CommandInterface, PrintedInterface +{ + use \Robo\Common\ExecOneCommand; + + /** + * @var string + */ + protected $command; + + /** + * @var string[] $formaters available formaters for format option + */ + protected $formaters = ['progress', 'html', 'pretty', 'junit', 'dot', 'tap']; + + /** + * @var array $verbose_levels available verbose levels + */ + protected $verbose_levels = ['v', 'vv', 'vvv']; + + public function __construct($pathToPhpspec = null) + { + $this->command = $pathToPhpspec; + if (!$this->command) { + $this->command = $this->findExecutable('phpspec'); + } + if (!$this->command) { + throw new \Robo\Exception\TaskException(__CLASS__, "Neither composer nor phar installation of Phpspec found"); + } + $this->arg('run'); + } + + public function stopOnFail() + { + $this->option('stop-on-failure'); + return $this; + } + + public function noCodeGeneration() + { + $this->option('no-code-generation'); + return $this; + } + + public function quiet() + { + $this->option('quiet'); + return $this; + } + + public function verbose($level = 'v') + { + if (!in_array($level, $this->verbose_levels)) { + throw new \InvalidArgumentException('expected ' . implode(',', $this->verbose_levels)); + } + $this->option('-' . $level); + return $this; + } + + public function noAnsi() + { + $this->option('no-ansi'); + return $this; + } + + public function noInteraction() + { + $this->option('no-interaction'); + return $this; + } + + public function config($config_file) + { + $this->option('config', $config_file); + return $this; + } + + public function format($formater) + { + if (!in_array($formater, $this->formaters)) { + throw new \InvalidArgumentException('expected ' . implode(',', $this->formaters)); + } + $this->option('format', $formater); + return $this; + } + + public function getCommand() + { + return $this->command . $this->arguments; + } + + public function run() + { + $this->printTaskInfo('Running phpspec {arguments}', ['arguments' => $this->arguments]); + return $this->executeCommand($this->getCommand()); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/loadTasks.php new file mode 100644 index 00000000..43145b9b --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Testing/loadTasks.php @@ -0,0 +1,55 @@ +task(Codecept::class, $pathToCodeception); + } + + /** + * @param null|string $pathToPhpUnit + * + * @return \Robo\Task\Testing\PHPUnit + */ + protected function taskPhpUnit($pathToPhpUnit = null) + { + return $this->task(PHPUnit::class, $pathToPhpUnit); + } + + /** + * @param null $pathToPhpspec + * + * @return \Robo\Task\Testing\Phpspec + */ + protected function taskPhpspec($pathToPhpspec = null) + { + return $this->task(Phpspec::class, $pathToPhpspec); + } + + /** + * @param null $pathToAtoum + * + * @return \Robo\Task\Testing\Atoum + */ + protected function taskAtoum($pathToAtoum = null) + { + return $this->task(Atoum::class, $pathToAtoum); + } + + /** + * @param null $pathToBehat + * + * @return \Robo\Task\Testing\Behat + */ + protected function taskBehat($pathToBehat = null) + { + return $this->task(Behat::class, $pathToBehat); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/GitStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/GitStack.php new file mode 100644 index 00000000..6cb1783f --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/GitStack.php @@ -0,0 +1,177 @@ +taskGitStack() + * ->stopOnFail() + * ->add('-A') + * ->commit('adding everything') + * ->push('origin','master') + * ->tag('0.6.0') + * ->push('origin','0.6.0') + * ->run() + * + * $this->taskGitStack() + * ->stopOnFail() + * ->add('doc/*') + * ->commit('doc updated') + * ->push() + * ->run(); + * ?> + * ``` + */ +class GitStack extends CommandStack +{ + /** + * @param string $pathToGit + */ + public function __construct($pathToGit = 'git') + { + $this->executable = $pathToGit; + } + + /** + * Executes `git clone` + * + * @param string $repo + * @param string $to + * + * @return $this + */ + public function cloneRepo($repo, $to = "", $branch = "") + { + $cmd = ['clone', $repo, $to]; + if (!empty($branch)) { + $cmd[] = "--branch $branch"; + } + return $this->exec($cmd); + } + + /** + * Executes `git clone` with depth 1 as default + * + * @param string $repo + * @param string $to + * @param string $branch + * @param int $depth + * + * @return $this + */ + public function cloneShallow($repo, $to = '', $branch = "", $depth = 1) + { + $cmd = ["clone --depth $depth", $repo, $to]; + if (!empty($branch)) { + $cmd[] = "--branch $branch"; + } + + return $this->exec($cmd); + } + + /** + * Executes `git add` command with files to add pattern + * + * @param string $pattern + * + * @return $this + */ + public function add($pattern) + { + return $this->exec([__FUNCTION__, $pattern]); + } + + /** + * Executes `git commit` command with a message + * + * @param string $message + * @param string $options + * + * @return $this + */ + public function commit($message, $options = "") + { + $message = ProcessUtils::escapeArgument($message); + return $this->exec([__FUNCTION__, "-m $message", $options]); + } + + /** + * Executes `git pull` command. + * + * @param string $origin + * @param string $branch + * + * @return $this + */ + public function pull($origin = '', $branch = '') + { + return $this->exec([__FUNCTION__, $origin, $branch]); + } + + /** + * Executes `git push` command + * + * @param string $origin + * @param string $branch + * + * @return $this + */ + public function push($origin = '', $branch = '') + { + return $this->exec([__FUNCTION__, $origin, $branch]); + } + + /** + * Performs git merge + * + * @param string $branch + * + * @return $this + */ + public function merge($branch) + { + return $this->exec([__FUNCTION__, $branch]); + } + + /** + * Executes `git checkout` command + * + * @param string $branch + * + * @return $this + */ + public function checkout($branch) + { + return $this->exec([__FUNCTION__, $branch]); + } + + /** + * Executes `git tag` command + * + * @param string $tag_name + * @param string $message + * + * @return $this + */ + public function tag($tag_name, $message = "") + { + if ($message != "") { + $message = "-m '$message'"; + } + return $this->exec([__FUNCTION__, $message, $tag_name]); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo("Running git commands..."); + return parent::run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/HgStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/HgStack.php new file mode 100644 index 00000000..71cc0ca9 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/HgStack.php @@ -0,0 +1,153 @@ +hgStack + * ->cloneRepo('https://bitbucket.org/durin42/hgsubversion') + * ->pull() + * ->add() + * ->commit('changed') + * ->push() + * ->tag('0.6.0') + * ->push('0.6.0') + * ->run(); + * ?> + * ``` + */ +class HgStack extends CommandStack +{ + + /** + * @param string $pathToHg + */ + public function __construct($pathToHg = 'hg') + { + $this->executable = $pathToHg; + } + + /** + * Executes `hg clone` + * + * @param string $repo + * @param string $to + * + * @return $this + */ + public function cloneRepo($repo, $to = '') + { + return $this->exec(['clone', $repo, $to]); + } + + /** + * Executes `hg add` command with files to add by pattern + * + * @param string $include + * @param string $exclude + * + * @return $this + */ + public function add($include = '', $exclude = '') + { + if (strlen($include) > 0) { + $include = "-I {$include}"; + } + + if (strlen($exclude) > 0) { + $exclude = "-X {$exclude}"; + } + + return $this->exec([__FUNCTION__, $include, $exclude]); + } + + /** + * Executes `hg commit` command with a message + * + * @param string $message + * @param string $options + * + * @return $this + */ + public function commit($message, $options = '') + { + return $this->exec([__FUNCTION__, "-m '{$message}'", $options]); + } + + /** + * Executes `hg pull` command. + * + * @param string $branch + * + * @return $this + */ + public function pull($branch = '') + { + if (strlen($branch) > 0) { + $branch = "-b '{$branch}''"; + } + + return $this->exec([__FUNCTION__, $branch]); + } + + /** + * Executes `hg push` command + * + * @param string $branch + * + * @return $this + */ + public function push($branch = '') + { + if (strlen($branch) > 0) { + $branch = "-b '{$branch}'"; + } + + return $this->exec([__FUNCTION__, $branch]); + } + + /** + * Performs hg merge + * + * @param string $revision + * + * @return $this + */ + public function merge($revision = '') + { + if (strlen($revision) > 0) { + $revision = "-r {$revision}"; + } + + return $this->exec([__FUNCTION__, $revision]); + } + + /** + * Executes `hg tag` command + * + * @param string $tag_name + * @param string $message + * + * @return $this + */ + public function tag($tag_name, $message = '') + { + if ($message !== '') { + $message = "-m '{$message}'"; + } + return $this->exec([__FUNCTION__, $message, $tag_name]); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->printTaskInfo('Running hg commands...'); + return parent::run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/SvnStack.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/SvnStack.php new file mode 100644 index 00000000..ec719b53 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/SvnStack.php @@ -0,0 +1,106 @@ +taskSvnStack() + * ->checkout('http://svn.collab.net/repos/svn/trunk') + * ->run() + * + * // alternatively + * $this->_svnCheckout('http://svn.collab.net/repos/svn/trunk'); + * + * $this->taskSvnStack('username', 'password') + * ->stopOnFail() + * ->update() + * ->add('doc/*') + * ->commit('doc updated') + * ->run(); + * ?> + * ``` + */ +class SvnStack extends CommandStack implements CommandInterface +{ + /** + * @var bool + */ + protected $stopOnFail = false; + + /** + * @var \Robo\Result + */ + protected $result; + + /** + * @param string $username + * @param string $password + * @param string $pathToSvn + */ + public function __construct($username = '', $password = '', $pathToSvn = 'svn') + { + $this->executable = $pathToSvn; + if (!empty($username)) { + $this->executable .= " --username $username"; + } + if (!empty($password)) { + $this->executable .= " --password $password"; + } + $this->result = Result::success($this); + } + + /** + * Updates `svn update` command + * + * @param string $path + * + * @return $this; + */ + public function update($path = '') + { + return $this->exec("update $path"); + } + + /** + * Executes `svn add` command with files to add pattern + * + * @param string $pattern + * + * @return $this + */ + public function add($pattern = '') + { + return $this->exec("add $pattern"); + } + + /** + * Executes `svn commit` command with a message + * + * @param string $message + * @param string $options + * + * @return $this + */ + public function commit($message, $options = "") + { + return $this->exec("commit -m '$message' $options"); + } + + /** + * Executes `svn checkout` command + * + * @param string $branch + * + * @return $this + */ + public function checkout($branch) + { + return $this->exec("checkout $branch"); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/loadShortcuts.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/loadShortcuts.php new file mode 100644 index 00000000..7d64ab58 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/loadShortcuts.php @@ -0,0 +1,35 @@ +taskSvnStack()->checkout($url)->run(); + } + + /** + * @param string $url + * + * @return \Robo\Result + */ + protected function _gitClone($url) + { + return $this->taskGitStack()->cloneRepo($url)->run(); + } + + /** + * @param string $url + * + * @return \Robo\Result + */ + protected function _hgClone($url) + { + return $this->taskHgStack()->cloneRepo($url)->run(); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/loadTasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/loadTasks.php new file mode 100644 index 00000000..6dd06228 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Task/Vcs/loadTasks.php @@ -0,0 +1,37 @@ +task(SvnStack::class, $username, $password, $pathToSvn); + } + + /** + * @param string $pathToGit + * + * @return \Robo\Task\Vcs\GitStack + */ + protected function taskGitStack($pathToGit = 'git') + { + return $this->task(GitStack::class, $pathToGit); + } + + /** + * @param string $pathToHg + * + * @return \Robo\Task\Vcs\HgStack + */ + protected function taskHgStack($pathToHg = 'hg') + { + return $this->task(HgStack::class, $pathToHg); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/TaskAccessor.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/TaskAccessor.php new file mode 100644 index 00000000..e65cd3eb --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/TaskAccessor.php @@ -0,0 +1,47 @@ +task(Foo::class, $a, $b); + * + * instead of: + * + * $this->taskFoo($a, $b); + * + * The later form is preferred. + * + * @return \Robo\Collection\CollectionBuilder + */ + protected function task() + { + $args = func_get_args(); + $name = array_shift($args); + + $collectionBuilder = $this->collectionBuilder(); + return $collectionBuilder->build($name, $args); + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/TaskInfo.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/TaskInfo.php new file mode 100644 index 00000000..ce59c2d5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/TaskInfo.php @@ -0,0 +1,35 @@ + TaskInfo::formatTaskName($task), + 'task' => $task, + ]; + } + + /** + * @param object $task + * + * @return string + */ + public static function formatTaskName($task) + { + $name = get_class($task); + $name = preg_replace('~Stack^~', '', $name); + $name = str_replace('Robo\\Task\Base\\', '', $name); + $name = str_replace('Robo\\Task\\', '', $name); + $name = str_replace('Robo\\Collection\\', '', $name); + return $name; + } +} diff --git a/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Tasks.php b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Tasks.php new file mode 100644 index 00000000..2822d7d5 --- /dev/null +++ b/core/lib/composer/vendor/consolidation/robo/scenarios/symfony4/src/Tasks.php @@ -0,0 +1,23 @@ +export(); + } + + /** + * Performs the actual property expansion. + * + * @param Data $data + * A data object, containing the $array. + * @param array $array + * The original, unmodified array. + * @param string $parent_keys + * The parent keys of the current key in dot notation. This is used to + * track the absolute path to the current key in recursive cases. + * @param Data|null $reference_data + * A reference data object. This is not operated upon but is used as a + * reference to provide supplemental values for property expansion. + */ + protected static function doExpandArrayProperties( + $data, + $array, + $parent_keys = '', + $reference_data = null + ) { + foreach ($array as $key => $value) { + // Boundary condition(s). + if (is_null($value) || is_bool($value)) { + continue; + } + // Recursive case. + if (is_array($value)) { + self::doExpandArrayProperties($data, $value, $parent_keys . "$key.", $reference_data); + } // Base case. + else { + self::expandStringProperties($data, $parent_keys, $reference_data, $value, $key); + } + } + } + + /** + * Expand a single property. + * + * @param Data $data + * A data object, containing the $array. + * @param string $parent_keys + * The parent keys of the current key in dot notation. This is used to + * track the absolute path to the current key in recursive cases. + * @param Data|null $reference_data + * A reference data object. This is not operated upon but is used as a + * reference to provide supplemental values for property expansion. + * @param string $value + * The unexpanded property value. + * @param string $key + * The immediate key of the property. + * + * @return mixed + */ + protected static function expandStringProperties( + $data, + $parent_keys, + $reference_data, + $value, + $key + ) { + // We loop through all placeholders in a given string. + // E.g., '${placeholder1} ${placeholder2}' requires two replacements. + while (strpos($value, '${') !== false) { + $original_value = $value; + $value = preg_replace_callback( + '/\$\{([^\$}]+)\}/', + function ($matches) use ($data, $reference_data) { + return self::expandStringPropertiesCallback( + $matches, + $data, + $reference_data + ); + }, + $value + ); + + // If no replacement occurred at all, break to prevent + // infinite loop. + if ($original_value == $value) { + break; + } + + // Set value on $data object. + if ($parent_keys) { + $full_key = $parent_keys . "$key"; + } else { + $full_key = $key; + } + $data->set($full_key, $value); + } + return $value; + } + + /** + * Expansion callback used by preg_replace_callback() in expandProperty(). + * + * @param array $matches + * An array of matches created by preg_replace_callback(). + * @param Data $data + * A data object containing the complete array being operated upon. + * @param Data|null $reference_data + * A reference data object. This is not operated upon but is used as a + * reference to provide supplemental values for property expansion. + * + * @return mixed + */ + public static function expandStringPropertiesCallback( + $matches, + $data, + $reference_data = null + ) { + $property_name = $matches[1]; + $unexpanded_value = $matches[0]; + + // Use only values within the subject array's data. + if (!$reference_data) { + return self::expandProperty($property_name, $unexpanded_value, $data); + } // Search both the subject array's data and the reference data for a value. + else { + return self::expandPropertyWithReferenceData( + $property_name, + $unexpanded_value, + $data, + $reference_data + ); + } + } + + /** + * Searches both the subject data and the reference data for value. + * + * @param string $property_name + * The name of the value for which to search. + * @param string $unexpanded_value + * The original, unexpanded value, containing the placeholder. + * @param Data $data + * A data object containing the complete array being operated upon. + * @param Data|null $reference_data + * A reference data object. This is not operated upon but is used as a + * reference to provide supplemental values for property expansion. + * + * @return string + * The expanded string. + */ + public static function expandPropertyWithReferenceData( + $property_name, + $unexpanded_value, + $data, + $reference_data + ) { + $expanded_value = self::expandProperty( + $property_name, + $unexpanded_value, + $data + ); + // If the string was not changed using the subject data, try using + // the reference data. + if ($expanded_value == $unexpanded_value) { + $expanded_value = self::expandProperty( + $property_name, + $unexpanded_value, + $reference_data + ); + } + + return $expanded_value; + } + + /** + * Searches a data object for a value. + * + * @param string $property_name + * The name of the value for which to search. + * @param string $unexpanded_value + * The original, unexpanded value, containing the placeholder. + * @param Data $data + * A data object containing possible replacement values. + * + * @return mixed + */ + public static function expandProperty($property_name, $unexpanded_value, $data) + { + if (strpos($property_name, "env.") === 0 && + !$data->has($property_name)) { + $env_key = substr($property_name, 4); + if (getenv($env_key)) { + $data->set($property_name, getenv($env_key)); + } + } + + if (!$data->has($property_name)) { + self::log("Property \${'$property_name'} could not be expanded."); + return $unexpanded_value; + } else { + $expanded_value = $data->get($property_name); + if (is_array($expanded_value)) { + $expanded_value = Yaml::dump($expanded_value, 0); + return $expanded_value; + } + self::log("Expanding property \${'$property_name'} => $expanded_value."); + return $expanded_value; + } + } + + /** + * @param $message + */ + public static function log($message) + { + // print "$message\n"; + } +} diff --git a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests deleted file mode 120000 index c2ebfe53..00000000 --- a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests +++ /dev/null @@ -1 +0,0 @@ -../../tests \ No newline at end of file diff --git a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests/phpunit/ExpanderTest.php b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests/phpunit/ExpanderTest.php new file mode 100644 index 00000000..291d00cc --- /dev/null +++ b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests/phpunit/ExpanderTest.php @@ -0,0 +1,99 @@ +assertEquals('gomjabbar', $expanded['env-test']); + $this->assertEquals('Frank Herbert 1965', $expanded['book']['copyright']); + $this->assertEquals('Paul Atreides', $expanded['book']['protaganist']); + $this->assertEquals('Dune by Frank Herbert', $expanded['summary']); + $this->assertEquals('${book.media.1}, hardcover', $expanded['available-products']); + $this->assertEquals('Dune', $expanded['product-name']); + $this->assertEquals(Yaml::dump($array['inline-array'], 0), $expanded['expand-array']); + + $expanded = Expander::expandArrayProperties($array, $reference_array); + $this->assertEquals('Dune Messiah, and others.', $expanded['sequels']); + $this->assertEquals('Dune Messiah', $expanded['book']['nested-reference']); + } + + /** + * Tests Expander::parse(). + * + * @param string $filename + * @param array $reference_array + * + * @dataProvider providerYaml + */ + public function testParse($filename, $reference_array) + { + $yaml_string = file_get_contents(__DIR__ . "/../resources/$filename"); + $expanded = Expander::parse($yaml_string); + $this->assertEquals('Frank Herbert 1965', $expanded['book']['copyright']); + $this->assertEquals('Paul Atreides', $expanded['book']['protaganist']); + $this->assertEquals('Dune by Frank Herbert', $expanded['summary']); + $this->assertEquals('${book.media.1}, hardcover', $expanded['available-products']); + + $expanded = Expander::parse($yaml_string, $reference_array); + $this->assertEquals('Dune Messiah, and others.', $expanded['sequels']); + $this->assertEquals('Dune Messiah', $expanded['book']['nested-reference']); + } + + /** + * @return array + * An array of values to test. + */ + public function providerYaml() + { + return [ + ['valid.yml', [ + 'book' => [ + 'sequel' => 'Dune Messiah' + ] + ]], + ]; + } + + /** + * Tests Expander::expandProperty(). + * + * @dataProvider providerTestExpandProperty + */ + public function testExpandProperty($array, $property_name, $unexpanded_string, $expected) + { + $data = new Data($array); + $expanded_value = Expander::expandProperty($property_name, $unexpanded_string, $data); + + $this->assertEquals($expected, $expanded_value); + } + + /** + * @return array + */ + public function providerTestExpandProperty() + { + return [ + [ ['author' => 'Frank Herbert'], 'author', '${author}', 'Frank Herbert' ], + [ ['book' => ['author' => 'Frank Herbert' ]], 'book.author', '${book.author}', 'Frank Herbert' ], + ]; + } +} diff --git a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests/resources/valid.yml b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests/resources/valid.yml new file mode 100644 index 00000000..78e4bc61 --- /dev/null +++ b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony2/tests/resources/valid.yml @@ -0,0 +1,35 @@ +# This file should contain only valid YAML. +type: book +book: + title: Dune + author: Frank Herbert + copyright: ${book.author} 1965 + protaganist: ${characters.0.name} + media: + - hardcover + # Use a nested key to reference an external value. + nested-reference: ${book.sequel} +characters: + - name: Paul Atreides + occupation: Kwisatz Haderach + aliases: + - Usul + - Muad'Dib + - The Preacher + - name: Duncan Idaho + occupation: Swordmaster +summary: ${book.title} by ${book.author} +# This is a complete fake property. +publisher: ${not.real.property} +# series.books is not defined in this YAML file, but is passed in to the parser by the application. +sequels: ${book.sequel}, and others. +# Reference one real value and one fake value. +available-products: ${book.media.1}, ${book.media.0} +# Nested property, should resolve to ${book.title} and then 'Dune'. +product-name: ${${type}.title} +# Represent a few more data types and formats. +boolean-value: true +null-value: null +inline-array: [ one, two, three ] +expand-array: ${inline-array} +env-test: ${env.test} \ No newline at end of file diff --git a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/src b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/src deleted file mode 120000 index 929cb3dc..00000000 --- a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/src +++ /dev/null @@ -1 +0,0 @@ -../../src \ No newline at end of file diff --git a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/src/Expander.php b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/src/Expander.php new file mode 100644 index 00000000..d922db59 --- /dev/null +++ b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/src/Expander.php @@ -0,0 +1,273 @@ +export(); + } + + /** + * Performs the actual property expansion. + * + * @param Data $data + * A data object, containing the $array. + * @param array $array + * The original, unmodified array. + * @param string $parent_keys + * The parent keys of the current key in dot notation. This is used to + * track the absolute path to the current key in recursive cases. + * @param Data|null $reference_data + * A reference data object. This is not operated upon but is used as a + * reference to provide supplemental values for property expansion. + */ + protected static function doExpandArrayProperties( + $data, + $array, + $parent_keys = '', + $reference_data = null + ) { + foreach ($array as $key => $value) { + // Boundary condition(s). + if (is_null($value) || is_bool($value)) { + continue; + } + // Recursive case. + if (is_array($value)) { + self::doExpandArrayProperties($data, $value, $parent_keys . "$key.", $reference_data); + } // Base case. + else { + self::expandStringProperties($data, $parent_keys, $reference_data, $value, $key); + } + } + } + + /** + * Expand a single property. + * + * @param Data $data + * A data object, containing the $array. + * @param string $parent_keys + * The parent keys of the current key in dot notation. This is used to + * track the absolute path to the current key in recursive cases. + * @param Data|null $reference_data + * A reference data object. This is not operated upon but is used as a + * reference to provide supplemental values for property expansion. + * @param string $value + * The unexpanded property value. + * @param string $key + * The immediate key of the property. + * + * @return mixed + */ + protected static function expandStringProperties( + $data, + $parent_keys, + $reference_data, + $value, + $key + ) { + // We loop through all placeholders in a given string. + // E.g., '${placeholder1} ${placeholder2}' requires two replacements. + while (strpos($value, '${') !== false) { + $original_value = $value; + $value = preg_replace_callback( + '/\$\{([^\$}]+)\}/', + function ($matches) use ($data, $reference_data) { + return self::expandStringPropertiesCallback( + $matches, + $data, + $reference_data + ); + }, + $value + ); + + // If no replacement occurred at all, break to prevent + // infinite loop. + if ($original_value == $value) { + break; + } + + // Set value on $data object. + if ($parent_keys) { + $full_key = $parent_keys . "$key"; + } else { + $full_key = $key; + } + $data->set($full_key, $value); + } + return $value; + } + + /** + * Expansion callback used by preg_replace_callback() in expandProperty(). + * + * @param array $matches + * An array of matches created by preg_replace_callback(). + * @param Data $data + * A data object containing the complete array being operated upon. + * @param Data|null $reference_data + * A reference data object. This is not operated upon but is used as a + * reference to provide supplemental values for property expansion. + * + * @return mixed + */ + public static function expandStringPropertiesCallback( + $matches, + $data, + $reference_data = null + ) { + $property_name = $matches[1]; + $unexpanded_value = $matches[0]; + + // Use only values within the subject array's data. + if (!$reference_data) { + return self::expandProperty($property_name, $unexpanded_value, $data); + } // Search both the subject array's data and the reference data for a value. + else { + return self::expandPropertyWithReferenceData( + $property_name, + $unexpanded_value, + $data, + $reference_data + ); + } + } + + /** + * Searches both the subject data and the reference data for value. + * + * @param string $property_name + * The name of the value for which to search. + * @param string $unexpanded_value + * The original, unexpanded value, containing the placeholder. + * @param Data $data + * A data object containing the complete array being operated upon. + * @param Data|null $reference_data + * A reference data object. This is not operated upon but is used as a + * reference to provide supplemental values for property expansion. + * + * @return string + * The expanded string. + */ + public static function expandPropertyWithReferenceData( + $property_name, + $unexpanded_value, + $data, + $reference_data + ) { + $expanded_value = self::expandProperty( + $property_name, + $unexpanded_value, + $data + ); + // If the string was not changed using the subject data, try using + // the reference data. + if ($expanded_value == $unexpanded_value) { + $expanded_value = self::expandProperty( + $property_name, + $unexpanded_value, + $reference_data + ); + } + + return $expanded_value; + } + + /** + * Searches a data object for a value. + * + * @param string $property_name + * The name of the value for which to search. + * @param string $unexpanded_value + * The original, unexpanded value, containing the placeholder. + * @param Data $data + * A data object containing possible replacement values. + * + * @return mixed + */ + public static function expandProperty($property_name, $unexpanded_value, $data) + { + if (strpos($property_name, "env.") === 0 && + !$data->has($property_name)) { + $env_key = substr($property_name, 4); + if (getenv($env_key)) { + $data->set($property_name, getenv($env_key)); + } + } + + if (!$data->has($property_name)) { + self::log("Property \${'$property_name'} could not be expanded."); + return $unexpanded_value; + } else { + $expanded_value = $data->get($property_name); + if (is_array($expanded_value)) { + $expanded_value = Yaml::dump($expanded_value, 0); + return $expanded_value; + } + self::log("Expanding property \${'$property_name'} => $expanded_value."); + return $expanded_value; + } + } + + /** + * @param $message + */ + public static function log($message) + { + // print "$message\n"; + } +} diff --git a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests deleted file mode 120000 index c2ebfe53..00000000 --- a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests +++ /dev/null @@ -1 +0,0 @@ -../../tests \ No newline at end of file diff --git a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests/phpunit/ExpanderTest.php b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests/phpunit/ExpanderTest.php new file mode 100644 index 00000000..291d00cc --- /dev/null +++ b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests/phpunit/ExpanderTest.php @@ -0,0 +1,99 @@ +assertEquals('gomjabbar', $expanded['env-test']); + $this->assertEquals('Frank Herbert 1965', $expanded['book']['copyright']); + $this->assertEquals('Paul Atreides', $expanded['book']['protaganist']); + $this->assertEquals('Dune by Frank Herbert', $expanded['summary']); + $this->assertEquals('${book.media.1}, hardcover', $expanded['available-products']); + $this->assertEquals('Dune', $expanded['product-name']); + $this->assertEquals(Yaml::dump($array['inline-array'], 0), $expanded['expand-array']); + + $expanded = Expander::expandArrayProperties($array, $reference_array); + $this->assertEquals('Dune Messiah, and others.', $expanded['sequels']); + $this->assertEquals('Dune Messiah', $expanded['book']['nested-reference']); + } + + /** + * Tests Expander::parse(). + * + * @param string $filename + * @param array $reference_array + * + * @dataProvider providerYaml + */ + public function testParse($filename, $reference_array) + { + $yaml_string = file_get_contents(__DIR__ . "/../resources/$filename"); + $expanded = Expander::parse($yaml_string); + $this->assertEquals('Frank Herbert 1965', $expanded['book']['copyright']); + $this->assertEquals('Paul Atreides', $expanded['book']['protaganist']); + $this->assertEquals('Dune by Frank Herbert', $expanded['summary']); + $this->assertEquals('${book.media.1}, hardcover', $expanded['available-products']); + + $expanded = Expander::parse($yaml_string, $reference_array); + $this->assertEquals('Dune Messiah, and others.', $expanded['sequels']); + $this->assertEquals('Dune Messiah', $expanded['book']['nested-reference']); + } + + /** + * @return array + * An array of values to test. + */ + public function providerYaml() + { + return [ + ['valid.yml', [ + 'book' => [ + 'sequel' => 'Dune Messiah' + ] + ]], + ]; + } + + /** + * Tests Expander::expandProperty(). + * + * @dataProvider providerTestExpandProperty + */ + public function testExpandProperty($array, $property_name, $unexpanded_string, $expected) + { + $data = new Data($array); + $expanded_value = Expander::expandProperty($property_name, $unexpanded_string, $data); + + $this->assertEquals($expected, $expanded_value); + } + + /** + * @return array + */ + public function providerTestExpandProperty() + { + return [ + [ ['author' => 'Frank Herbert'], 'author', '${author}', 'Frank Herbert' ], + [ ['book' => ['author' => 'Frank Herbert' ]], 'book.author', '${book.author}', 'Frank Herbert' ], + ]; + } +} diff --git a/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests/resources/valid.yml b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests/resources/valid.yml new file mode 100644 index 00000000..78e4bc61 --- /dev/null +++ b/core/lib/composer/vendor/grasmash/yaml-expander/scenarios/symfony4/tests/resources/valid.yml @@ -0,0 +1,35 @@ +# This file should contain only valid YAML. +type: book +book: + title: Dune + author: Frank Herbert + copyright: ${book.author} 1965 + protaganist: ${characters.0.name} + media: + - hardcover + # Use a nested key to reference an external value. + nested-reference: ${book.sequel} +characters: + - name: Paul Atreides + occupation: Kwisatz Haderach + aliases: + - Usul + - Muad'Dib + - The Preacher + - name: Duncan Idaho + occupation: Swordmaster +summary: ${book.title} by ${book.author} +# This is a complete fake property. +publisher: ${not.real.property} +# series.books is not defined in this YAML file, but is passed in to the parser by the application. +sequels: ${book.sequel}, and others. +# Reference one real value and one fake value. +available-products: ${book.media.1}, ${book.media.0} +# Nested property, should resolve to ${book.title} and then 'Dune'. +product-name: ${${type}.title} +# Represent a few more data types and formats. +boolean-value: true +null-value: null +inline-array: [ one, two, three ] +expand-array: ${inline-array} +env-test: ${env.test} \ No newline at end of file diff --git a/core/lib/composer/vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep b/core/lib/composer/vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/core/lib/composer/vendor/neitanod/forceutf8/README.md b/core/lib/composer/vendor/neitanod/forceutf8/README.md new file mode 100644 index 00000000..765c637d --- /dev/null +++ b/core/lib/composer/vendor/neitanod/forceutf8/README.md @@ -0,0 +1,61 @@ +forceutf8 +========= + +PHP Class Encoding featuring popular \ForceUTF8\Encoding::toUTF8() function --formerly known as forceUTF8()-- that fixes mixed encoded strings. + +Description +=========== + +If you apply the PHP function utf8_encode() to an already-UTF8 string it will return a garbled UTF8 string. + +This class addresses this issue and provides a handy static function called \ForceUTF8\Encoding::toUTF8(). + +You don't need to know what the encoding of your strings is. It can be Latin1 (iso 8859-1), Windows-1252 or UTF8, or the string can have a mix of them. \ForceUTF8\Encoding::toUTF8() will convert everything to UTF8. + +Sometimes you have to deal with services that are unreliable in terms of encoding, possibly mixing UTF8 and Latin1 in the same string. + +Update: + +I've included another function, \ForceUTF8\Encoding::fixUTF8(), which will fix the double (or multiple) encoded UTF8 string that looks garbled. + +Usage: +====== + + use \ForceUTF8\Encoding; + + $utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string); + + $latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string); + +also: + + $utf8_string = Encoding::fixUTF8($garbled_utf8_string); + +Examples: + + use \ForceUTF8\Encoding; + + echo Encoding::fixUTF8("Fédération Camerounaise de Football\n"); + echo Encoding::fixUTF8("Fédération Camerounaise de Football\n"); + echo Encoding::fixUTF8("Fédération Camerounaise de Football\n"); + echo Encoding::fixUTF8("Fédération Camerounaise de Football\n"); + +will output: + + Fédération Camerounaise de Football + Fédération Camerounaise de Football + Fédération Camerounaise de Football + Fédération Camerounaise de Football + +Install via composer: +===================== +Edit your composer.json file to include the following: + +```json +{ + "require": { + "neitanod/forceutf8": "~2.0" + } +} +``` + diff --git a/core/lib/composer/vendor/neitanod/forceutf8/composer.json b/core/lib/composer/vendor/neitanod/forceutf8/composer.json new file mode 100644 index 00000000..aff71afa --- /dev/null +++ b/core/lib/composer/vendor/neitanod/forceutf8/composer.json @@ -0,0 +1,20 @@ +{ + "name": "neitanod/forceutf8", + "homepage": "https://github.com/neitanod/forceutf8", + "type": "library", + "description": "PHP Class Encoding featuring popular Encoding::toUTF8() function --formerly known as forceUTF8()-- that fixes mixed encoded strings.", + "require": { + "php": ">=5.3.0" + }, + "authors": [ + { + "name": "Sebastián Grignoli", + "email": "grignoli@gmail.com" + } + ], + "autoload": { + "psr-0": { + "ForceUTF8\\": "src/" + } + } +} diff --git a/core/lib/composer/vendor/neitanod/forceutf8/src/ForceUTF8/Encoding.php b/core/lib/composer/vendor/neitanod/forceutf8/src/ForceUTF8/Encoding.php new file mode 100644 index 00000000..65305767 --- /dev/null +++ b/core/lib/composer/vendor/neitanod/forceutf8/src/ForceUTF8/Encoding.php @@ -0,0 +1,347 @@ + + * @package Encoding + * @version 2.0 + * @link https://github.com/neitanod/forceutf8 + * @example https://github.com/neitanod/forceutf8 + * @license Revised BSD + */ + +namespace ForceUTF8; + +class Encoding { + + const ICONV_TRANSLIT = "TRANSLIT"; + const ICONV_IGNORE = "IGNORE"; + const WITHOUT_ICONV = ""; + + protected static $win1252ToUtf8 = array( + 128 => "\xe2\x82\xac", + + 130 => "\xe2\x80\x9a", + 131 => "\xc6\x92", + 132 => "\xe2\x80\x9e", + 133 => "\xe2\x80\xa6", + 134 => "\xe2\x80\xa0", + 135 => "\xe2\x80\xa1", + 136 => "\xcb\x86", + 137 => "\xe2\x80\xb0", + 138 => "\xc5\xa0", + 139 => "\xe2\x80\xb9", + 140 => "\xc5\x92", + + 142 => "\xc5\xbd", + + + 145 => "\xe2\x80\x98", + 146 => "\xe2\x80\x99", + 147 => "\xe2\x80\x9c", + 148 => "\xe2\x80\x9d", + 149 => "\xe2\x80\xa2", + 150 => "\xe2\x80\x93", + 151 => "\xe2\x80\x94", + 152 => "\xcb\x9c", + 153 => "\xe2\x84\xa2", + 154 => "\xc5\xa1", + 155 => "\xe2\x80\xba", + 156 => "\xc5\x93", + + 158 => "\xc5\xbe", + 159 => "\xc5\xb8" + ); + + protected static $brokenUtf8ToUtf8 = array( + "\xc2\x80" => "\xe2\x82\xac", + + "\xc2\x82" => "\xe2\x80\x9a", + "\xc2\x83" => "\xc6\x92", + "\xc2\x84" => "\xe2\x80\x9e", + "\xc2\x85" => "\xe2\x80\xa6", + "\xc2\x86" => "\xe2\x80\xa0", + "\xc2\x87" => "\xe2\x80\xa1", + "\xc2\x88" => "\xcb\x86", + "\xc2\x89" => "\xe2\x80\xb0", + "\xc2\x8a" => "\xc5\xa0", + "\xc2\x8b" => "\xe2\x80\xb9", + "\xc2\x8c" => "\xc5\x92", + + "\xc2\x8e" => "\xc5\xbd", + + + "\xc2\x91" => "\xe2\x80\x98", + "\xc2\x92" => "\xe2\x80\x99", + "\xc2\x93" => "\xe2\x80\x9c", + "\xc2\x94" => "\xe2\x80\x9d", + "\xc2\x95" => "\xe2\x80\xa2", + "\xc2\x96" => "\xe2\x80\x93", + "\xc2\x97" => "\xe2\x80\x94", + "\xc2\x98" => "\xcb\x9c", + "\xc2\x99" => "\xe2\x84\xa2", + "\xc2\x9a" => "\xc5\xa1", + "\xc2\x9b" => "\xe2\x80\xba", + "\xc2\x9c" => "\xc5\x93", + + "\xc2\x9e" => "\xc5\xbe", + "\xc2\x9f" => "\xc5\xb8" + ); + + protected static $utf8ToWin1252 = array( + "\xe2\x82\xac" => "\x80", + + "\xe2\x80\x9a" => "\x82", + "\xc6\x92" => "\x83", + "\xe2\x80\x9e" => "\x84", + "\xe2\x80\xa6" => "\x85", + "\xe2\x80\xa0" => "\x86", + "\xe2\x80\xa1" => "\x87", + "\xcb\x86" => "\x88", + "\xe2\x80\xb0" => "\x89", + "\xc5\xa0" => "\x8a", + "\xe2\x80\xb9" => "\x8b", + "\xc5\x92" => "\x8c", + + "\xc5\xbd" => "\x8e", + + + "\xe2\x80\x98" => "\x91", + "\xe2\x80\x99" => "\x92", + "\xe2\x80\x9c" => "\x93", + "\xe2\x80\x9d" => "\x94", + "\xe2\x80\xa2" => "\x95", + "\xe2\x80\x93" => "\x96", + "\xe2\x80\x94" => "\x97", + "\xcb\x9c" => "\x98", + "\xe2\x84\xa2" => "\x99", + "\xc5\xa1" => "\x9a", + "\xe2\x80\xba" => "\x9b", + "\xc5\x93" => "\x9c", + + "\xc5\xbe" => "\x9e", + "\xc5\xb8" => "\x9f" + ); + + static function toUTF8($text){ + /** + * Function \ForceUTF8\Encoding::toUTF8 + * + * This function leaves UTF8 characters alone, while converting almost all non-UTF8 to UTF8. + * + * It assumes that the encoding of the original string is either Windows-1252 or ISO 8859-1. + * + * It may fail to convert characters to UTF-8 if they fall into one of these scenarios: + * + * 1) when any of these characters: ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖרÙÚÛÜÃÞß + * are followed by any of these: ("group B") + * ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶•¸¹º»¼½¾¿ + * For example: %ABREPRESENT%C9%BB. «REPRESENTÉ» + * The "«" (%AB) character will be converted, but the "É" followed by "»" (%C9%BB) + * is also a valid unicode character, and will be left unchanged. + * + * 2) when any of these: àáâãäåæçèéêëìíîï are followed by TWO chars from group B, + * 3) when any of these: ðñòó are followed by THREE chars from group B. + * + * @name toUTF8 + * @param string $text Any string. + * @return string The same string, UTF8 encoded + * + */ + + if(is_array($text)) + { + foreach($text as $k => $v) + { + $text[$k] = self::toUTF8($v); + } + return $text; + } + + if(!is_string($text)) { + return $text; + } + + $max = self::strlen($text); + + $buf = ""; + for($i = 0; $i < $max; $i++){ + $c1 = $text{$i}; + if($c1>="\xc0"){ //Should be converted to UTF8, if it's not UTF8 already + $c2 = $i+1 >= $max? "\x00" : $text{$i+1}; + $c3 = $i+2 >= $max? "\x00" : $text{$i+2}; + $c4 = $i+3 >= $max? "\x00" : $text{$i+3}; + if($c1 >= "\xc0" & $c1 <= "\xdf"){ //looks like 2 bytes UTF8 + if($c2 >= "\x80" && $c2 <= "\xbf"){ //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2; + $i++; + } else { //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } elseif($c1 >= "\xe0" & $c1 <= "\xef"){ //looks like 3 bytes UTF8 + if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf"){ //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2 . $c3; + $i = $i + 2; + } else { //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } elseif($c1 >= "\xf0" & $c1 <= "\xf7"){ //looks like 4 bytes UTF8 + if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf"){ //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2 . $c3 . $c4; + $i = $i + 3; + } else { //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } else { //doesn't look like UTF8, but should be converted + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = (($c1 & "\x3f") | "\x80"); + $buf .= $cc1 . $cc2; + } + } elseif(($c1 & "\xc0") == "\x80"){ // needs conversion + if(isset(self::$win1252ToUtf8[ord($c1)])) { //found in Windows-1252 special cases + $buf .= self::$win1252ToUtf8[ord($c1)]; + } else { + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = (($c1 & "\x3f") | "\x80"); + $buf .= $cc1 . $cc2; + } + } else { // it doesn't need conversion + $buf .= $c1; + } + } + return $buf; + } + + static function toWin1252($text, $option = self::WITHOUT_ICONV) { + if(is_array($text)) { + foreach($text as $k => $v) { + $text[$k] = self::toWin1252($v, $option); + } + return $text; + } elseif(is_string($text)) { + return static::utf8_decode($text, $option); + } else { + return $text; + } + } + + static function toISO8859($text) { + return self::toWin1252($text); + } + + static function toLatin1($text) { + return self::toWin1252($text); + } + + static function fixUTF8($text, $option = self::WITHOUT_ICONV){ + if(is_array($text)) { + foreach($text as $k => $v) { + $text[$k] = self::fixUTF8($v, $option); + } + return $text; + } + + $last = ""; + while($last <> $text){ + $last = $text; + $text = self::toUTF8(static::utf8_decode($text, $option)); + } + $text = self::toUTF8(static::utf8_decode($text, $option)); + return $text; + } + + static function UTF8FixWin1252Chars($text){ + // If you received an UTF-8 string that was converted from Windows-1252 as it was ISO8859-1 + // (ignoring Windows-1252 chars from 80 to 9F) use this function to fix it. + // See: http://en.wikipedia.org/wiki/Windows-1252 + + return str_replace(array_keys(self::$brokenUtf8ToUtf8), array_values(self::$brokenUtf8ToUtf8), $text); + } + + static function removeBOM($str=""){ + if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) { + $str=substr($str, 3); + } + return $str; + } + + protected static function strlen($text){ + return (function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload')) & 2) ? + mb_strlen($text,'8bit') : strlen($text); + } + + public static function normalizeEncoding($encodingLabel) + { + $encoding = strtoupper($encodingLabel); + $encoding = preg_replace('/[^a-zA-Z0-9\s]/', '', $encoding); + $equivalences = array( + 'ISO88591' => 'ISO-8859-1', + 'ISO8859' => 'ISO-8859-1', + 'ISO' => 'ISO-8859-1', + 'LATIN1' => 'ISO-8859-1', + 'LATIN' => 'ISO-8859-1', + 'UTF8' => 'UTF-8', + 'UTF' => 'UTF-8', + 'WIN1252' => 'ISO-8859-1', + 'WINDOWS1252' => 'ISO-8859-1' + ); + + if(empty($equivalences[$encoding])){ + return 'UTF-8'; + } + + return $equivalences[$encoding]; + } + + public static function encode($encodingLabel, $text) + { + $encodingLabel = self::normalizeEncoding($encodingLabel); + if($encodingLabel == 'ISO-8859-1') return self::toLatin1($text); + return self::toUTF8($text); + } + + protected static function utf8_decode($text, $option) + { + if ($option == self::WITHOUT_ICONV || !function_exists('iconv')) { + $o = utf8_decode( + str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), self::toUTF8($text)) + ); + } else { + $o = iconv("UTF-8", "Windows-1252" . ($option == self::ICONV_TRANSLIT ? '//TRANSLIT' : ($option == self::ICONV_IGNORE ? '//IGNORE' : '')), $text); + } + return $o; + } +} diff --git a/core/lib/composer/vendor/neitanod/forceutf8/test/ForceUTF8Test.php b/core/lib/composer/vendor/neitanod/forceutf8/test/ForceUTF8Test.php new file mode 100644 index 00000000..02ec6879 --- /dev/null +++ b/core/lib/composer/vendor/neitanod/forceutf8/test/ForceUTF8Test.php @@ -0,0 +1,101 @@ + FAILED\n"; + static::$failed++; + } + + private static function passed($test_name){ + static::character("."); + static::$passed++; + } + + private static function character($char){ + echo $char; + static::$last_echoed = 'char'; + } + + private static function line($msg){ + if(static::$last_echoed == 'char') echo "\n"; + echo $msg."\n"; + static::$last_echoed = 'line'; + } + } + diff --git a/core/lib/composer/vendor/neitanod/forceutf8/test/data/russian.txt b/core/lib/composer/vendor/neitanod/forceutf8/test/data/russian.txt new file mode 100644 index 00000000..1c618ad7 --- /dev/null +++ b/core/lib/composer/vendor/neitanod/forceutf8/test/data/russian.txt @@ -0,0 +1 @@ +hello žš, привет diff --git a/core/lib/composer/vendor/neitanod/forceutf8/test/data/test1.txt b/core/lib/composer/vendor/neitanod/forceutf8/test/data/test1.txt new file mode 100644 index 00000000..771829e0 --- /dev/null +++ b/core/lib/composer/vendor/neitanod/forceutf8/test/data/test1.txt @@ -0,0 +1 @@ +Hírek diff --git a/core/lib/composer/vendor/neitanod/forceutf8/test/data/test1Latin.txt b/core/lib/composer/vendor/neitanod/forceutf8/test/data/test1Latin.txt new file mode 100644 index 00000000..0aa69d6f --- /dev/null +++ b/core/lib/composer/vendor/neitanod/forceutf8/test/data/test1Latin.txt @@ -0,0 +1 @@ +Hírek diff --git a/core/lib/composer/vendor/pear/net_smtp/README.rst b/core/lib/composer/vendor/pear/net_smtp/README.rst deleted file mode 120000 index 753c5b5c..00000000 --- a/core/lib/composer/vendor/pear/net_smtp/README.rst +++ /dev/null @@ -1 +0,0 @@ -docs/guide.txt \ No newline at end of file diff --git a/core/lib/composer/vendor/pear/net_smtp/README.rst b/core/lib/composer/vendor/pear/net_smtp/README.rst new file mode 100644 index 00000000..a0e61dbd --- /dev/null +++ b/core/lib/composer/vendor/pear/net_smtp/README.rst @@ -0,0 +1,267 @@ +====================== + The Net_SMTP Package +====================== + +-------------------- + User Documentation +-------------------- + +:Author: Jon Parise +:Contact: jon@php.net + +.. contents:: Table of Contents +.. section-numbering:: + +Dependencies +============ + +The ``PEAR_Error`` Class +------------------------ + +The Net_SMTP package uses the `PEAR_Error`_ class for all of its `error +handling`_. + +The ``Net_Socket`` Package +-------------------------- + +The Net_Socket_ package is used as the basis for all network communications. +Connection options can be specified via the `$socket_options` construction +parameter:: + + $socket_options = array('ssl' => array('verify_peer_name' => false)); + $smtp = new Net_SMTP($host, null, null, false, 0, $socket_options); + +**Note:** PHP 5.6 introduced `OpenSSL changes`_. Peer certificate verification +is now enabled by default. Although not recommended, `$socket_options` can be +used to disable peer verification (as shown above). + +.. _OpenSSL changes: http://php.net/manual/en/migration56.openssl.php + +The ``Auth_SASL`` Package +------------------------- + +The `Auth_SASL`_ package is an optional dependency. If it is available, the +Net_SMTP package will be able to support the DIGEST-MD5_ and CRAM-MD5_ SMTP +authentication methods. Otherwise, only the LOGIN_ and PLAIN_ methods will +be available. + +Error Handling +============== + +All of the Net_SMTP class's public methods return a PEAR_Error_ object if an +error occurs. The standard way to check for a PEAR_Error object is by using +`PEAR::isError()`_:: + + if (PEAR::isError($error = $smtp->connect())) { + die($error->getMessage()); + } + +.. _PEAR::isError(): http://pear.php.net/manual/en/core.pear.pear.iserror.php + +SMTP Authentication +=================== + +The Net_SMTP package supports the SMTP authentication standard (as defined +by RFC-2554_). The Net_SMTP package supports the following authentication +methods, in order of preference: + +.. _RFC-2554: http://www.ietf.org/rfc/rfc2554.txt + +DIGEST-MD5 +---------- + +The DIGEST-MD5 authentication method uses `RSA Data Security Inc.`_'s MD5 +Message Digest algorithm. It is considered the most secure method of SMTP +authentication. + +**Note:** The DIGEST-MD5 authentication method is only supported if the +AUTH_SASL_ package is available. + +.. _RSA Data Security Inc.: http://www.rsasecurity.com/ + +CRAM-MD5 +-------- + +The CRAM-MD5 authentication method has been superseded by the DIGEST-MD5_ +method in terms of security. It is provided here for compatibility with +older SMTP servers that may not support the newer DIGEST-MD5 algorithm. + +**Note:** The CRAM-MD5 authentication method is only supported if the +AUTH_SASL_ package is available. + +LOGIN +----- + +The LOGIN authentication method encrypts the user's password using the +Base64_ encoding scheme. Because decrypting a Base64-encoded string is +trivial, LOGIN is not considered a secure authentication method and should +be avoided. + +.. _Base64: http://www.php.net/manual/en/function.base64-encode.php + +PLAIN +----- + +The PLAIN authentication method sends the user's password in plain text. +This method of authentication is not secure and should be avoided. + +Secure Connections +================== + +If `secure socket transports`_ have been enabled in PHP, it is possible to +establish a secure connection to the remote SMTP server:: + + $smtp = new Net_SMTP('ssl://mail.example.com', 465); + +This example connects to ``mail.example.com`` on port 465 (a common SMTPS +port) using the ``ssl://`` transport. + +.. _secure socket transports: http://www.php.net/transports + +Sending Data +============ + +Message data is sent using the ``data()`` method. The data can be supplied +as a single string or as an open file resource. + +If a string is provided, it is passed through the `data quoting`_ system and +sent to the socket connection as a single block. These operations are all +memory-based, so sending large messages may result in high memory usage. + +If an open file resource is provided, the ``data()`` method will read the +message data from the file line-by-line. Each chunk will be quoted and sent +to the socket connection individually, reducing the overall memory overhead of +this data sending operation. + +Header data can be specified separately from message body data by passing it +as the optional second parameter to ``data()``. This is especially useful +when an open file resource is being used to supply message data because it +allows header fields (like *Subject:*) to be built dynamically at runtime. + +:: + + $smtp->data($fp, "Subject: My Subject"); + +Data Quoting +============ + +By default, all outbound string data is quoted in accordance with SMTP +standards. This means that all native Unix (``\n``) and Mac (``\r``) line +endings are converted to Internet-standard CRLF (``\r\n``) line endings. +Also, because the SMTP protocol uses a single leading period (``.``) to signal +an end to the message data, single leading periods in the original data +string are "doubled" (e.g. "``..``"). + +These string transformation can be expensive when large blocks of data are +involved. For example, the Net_SMTP package is not aware of MIME parts (it +just sees the MIME message as one big string of characters), so it is not +able to skip non-text attachments when searching for characters that may +need to be quoted. + +Because of this, it is possible to extend the Net_SMTP class in order to +implement your own custom quoting routine. Just create a new class based on +the Net_SMTP class and reimplement the ``quotedata()`` method:: + + require 'Net_SMTP.php'; + + class Net_SMTP_custom extends Net_SMTP + { + function quotedata($data) + { + /* Perform custom data quoting */ + } + } + +Note that the ``$data`` parameter will be passed to the ``quotedata()`` +function `by reference`_. This means that you can operate directly on +``$data``. It also the overhead of copying a large ``$data`` string to and +from the ``quotedata()`` method. + +.. _by reference: http://www.php.net/manual/en/language.references.pass.php + +Server Responses +================ + +The Net_SMTP package retains the server's last response for further +inspection. The ``getResponse()`` method returns a 2-tuple (two element +array) containing the server's response code as an integer and the response's +arguments as a string. + +Upon a successful connection, the server's greeting string is available via +the ``getGreeting()`` method. + +Debugging +========= + +The Net_SMTP package contains built-in debugging output routines (disabled by +default). Debugging output must be explicitly enabled via the ``setDebug()`` +method:: + + $smtp->setDebug(true); + +The debugging messages will be sent to the standard output stream by default. +If you need more control over the output, you can optionally install your own +debug handler. + +:: + + function debugHandler($smtp, $message) + { + echo "[$smtp->host] $message\n"; + } + + $smtp->setDebug(true, "debugHandler"); + + +Examples +======== + +Basic Use +--------- + +The following script demonstrates how a simple email message can be sent +using the Net_SMTP package:: + + require 'Net/SMTP.php'; + + $host = 'mail.example.com'; + $from = 'user@example.com'; + $rcpt = array('recipient1@example.com', 'recipient2@example.com'); + $subj = "Subject: Test Message\n"; + $body = "Body Line 1\nBody Line 2"; + + /* Create a new Net_SMTP object. */ + if (! ($smtp = new Net_SMTP($host))) { + die("Unable to instantiate Net_SMTP object\n"); + } + + /* Connect to the SMTP server. */ + if (PEAR::isError($e = $smtp->connect())) { + die($e->getMessage() . "\n"); + } + + /* Send the 'MAIL FROM:' SMTP command. */ + if (PEAR::isError($smtp->mailFrom($from))) { + die("Unable to set sender to <$from>\n"); + } + + /* Address the message to each of the recipients. */ + foreach ($rcpt as $to) { + if (PEAR::isError($res = $smtp->rcptTo($to))) { + die("Unable to add recipient <$to>: " . $res->getMessage() . "\n"); + } + } + + /* Set the body of the message. */ + if (PEAR::isError($smtp->data($subj . "\r\n" . $body))) { + die("Unable to send data\n"); + } + + /* Disconnect from the SMTP server. */ + $smtp->disconnect(); + +.. _PEAR_Error: http://pear.php.net/manual/en/core.pear.pear-error.php +.. _Net_Socket: http://pear.php.net/package/Net_Socket +.. _Auth_SASL: http://pear.php.net/package/Auth_SASL + +.. vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=78 ft=rst: diff --git a/core/lib/composer/vendor/phpunit/phpunit/src/Util/XML.php b/core/lib/composer/vendor/phpunit/phpunit/src/Util/Xml.php similarity index 100% rename from core/lib/composer/vendor/phpunit/phpunit/src/Util/XML.php rename to core/lib/composer/vendor/phpunit/phpunit/src/Util/Xml.php diff --git a/core/lib/composer/vendor/phpunit/phpunit/tests/Util/XMLTest.php b/core/lib/composer/vendor/phpunit/phpunit/tests/Util/XmlTest.php similarity index 100% rename from core/lib/composer/vendor/phpunit/phpunit/tests/Util/XMLTest.php rename to core/lib/composer/vendor/phpunit/phpunit/tests/Util/XmlTest.php diff --git a/core/lib/composer/vendor/spomky-labs/base64url/LICENSE b/core/lib/composer/vendor/spomky-labs/base64url/LICENSE new file mode 100644 index 00000000..c1c9c423 --- /dev/null +++ b/core/lib/composer/vendor/spomky-labs/base64url/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2016 Spomky-Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/core/lib/composer/vendor/spomky-labs/base64url/composer.json b/core/lib/composer/vendor/spomky-labs/base64url/composer.json new file mode 100644 index 00000000..ce51fbef --- /dev/null +++ b/core/lib/composer/vendor/spomky-labs/base64url/composer.json @@ -0,0 +1,31 @@ +{ + "name": "spomky-labs/base64url", + "description": "Base 64 URL Safe Encoding/decoding PHP Library", + "type": "library", + "license": "MIT", + "keywords": ["Base64", "URL", "Safe", "RFC4648"], + "homepage": "https://github.com/Spomky-Labs/base64url", + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/base64url/contributors" + } + ], + "autoload": { + "psr-4": { + "Base64Url\\": "src/" + } + }, + "require": { + "php": "^5.3|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/core/lib/composer/vendor/spomky-labs/base64url/src/Base64Url.php b/core/lib/composer/vendor/spomky-labs/base64url/src/Base64Url.php new file mode 100644 index 00000000..4e7c7b6b --- /dev/null +++ b/core/lib/composer/vendor/spomky-labs/base64url/src/Base64Url.php @@ -0,0 +1,41 @@ +user_level == "Admin") { if (\Utils\SessionUtils::getSessionObject('account_locked') == "1") { header("Location:".CLIENT_BASE_URL."?g=admin&n=billing&m=admin_System"); + exit(); } else { header("Location:".HOME_LINK_ADMIN); + exit(); } } else { if (empty($user->default_module)) { header("Location:".HOME_LINK_OTHERS); + exit(); } else { $defaultModule = new \Modules\Common\Model\Module(); $defaultModule->Load("id = ?", array($user->default_module)); @@ -103,19 +112,24 @@ if (empty($user)) { $homeLink = CLIENT_BASE_URL."?g=".$defaultModule->mod_group."&&n=".$defaultModule->name. "&m=".$defaultModule->mod_group."_".str_replace(" ", "_", $defaultModule->menu); header("Location:".$homeLink); + exit(); } } } } else { - header("Location:".CLIENT_BASE_URL."login.php?f=1"); + $next = !empty($_REQUEST['next'])?'&next='.$_REQUEST['next']:''; + header("Location:".CLIENT_BASE_URL."login.php?f=1".$next); + exit(); } } } else { if ($user->user_level == "Admin") { header("Location:".HOME_LINK_ADMIN); + exit(); } else { if (empty($user->default_module)) { header("Location:".HOME_LINK_OTHERS); + exit(); } else { $defaultModule = new \Modules\Common\Model\Module(); $defaultModule->Load("id = ?", array($user->default_module)); @@ -125,6 +139,7 @@ if (empty($user)) { $homeLink = CLIENT_BASE_URL."?g=".$defaultModule->mod_group."&n=".$defaultModule->name. "&m=".$defaultModule->mod_group."_".str_replace(" ", "_", $defaultModule->menu); header("Location:".$homeLink); + exit(); } } } @@ -324,6 +339,7 @@ $logoFileUrl = \Classes\UIManager::getInstance()->getCompanyLogoUrl();

    +
    @@ -339,7 +355,7 @@ $logoFileUrl = \Classes\UIManager::getInstance()->getCompanyLogoUrl();
    - +
    diff --git a/core/logout.php b/core/logout.php index eef44ea5..e1f7cafe 100644 --- a/core/logout.php +++ b/core/logout.php @@ -1,5 +1,2 @@ executeQuery($sql); + + $sql = <<<'SQL' + Update Settings set value = '1' where name = 'System: Reset Module Names'; +SQL; + return $this->executeQuery($sql); + } + + public function down(){ + + return true; + } + +} diff --git a/core/migrations/v20180514_230002_add_conversation_tables.php b/core/migrations/v20180514_230002_add_conversation_tables.php new file mode 100644 index 00000000..e763d5ff --- /dev/null +++ b/core/migrations/v20180514_230002_add_conversation_tables.php @@ -0,0 +1,66 @@ +executeQuery($sql); + + $sql = <<<'SQL' +create table `ConversationUserStatus` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `employee` bigint(20) NOT NULL, + `status` varchar(15) NULL, + `seen_at` DATETIME default '0000-00-00 00:00:00', + primary key (`id`), + unique key `KEY_ConversationLastSeen_employee` (`employee`), + index `KEY_ConversationLastSeen_seen_at` (`seen_at`), + index `KEY_ConversationLastSeen_status` (`seen_at`) +) engine=innodb default charset=utf8; +SQL; + $this->executeQuery($sql); + + $sql = <<<'SQL' + Update Settings set value = '1' where name = 'System: Reset Module Names'; +SQL; + $this->executeQuery($sql); + + $sql = <<<'SQL' + Update Settings set value = '1' where name = 'System: Add New Permissions'; +SQL; + $this->executeQuery($sql); + + $sql = <<<'SQL' + INSERT INTO `SupportedLanguages` (`name`, `description`) VALUES ('fi', 'Finnish'); +SQL; + return $this->executeQuery($sql); + } + + public function down(){ + + return true; + } + +} diff --git a/core/modules.php b/core/modules.php index e965e47e..3bf01e33 100644 --- a/core/modules.php +++ b/core/modules.php @@ -133,7 +133,6 @@ foreach ($ams as $am) { $arr['label'] = $dbModule->label; $arr['icon'] = $dbModule->icon; $arr['menu'] = $dbModule->menu; - $arr['order'] = $dbModule->mod_order; $arr['status'] = $dbModule->status; $arr['user_levels'] = json_decode($dbModule->user_levels); $arr['user_roles'] = json_decode($dbModule->user_roles); @@ -195,7 +194,6 @@ foreach ($ams as $am) { $arr['label'] = $meta->label; $arr['icon'] = $meta->icon; $arr['menu'] = $meta->menu; - $arr['order'] = $meta->order; $arr['status'] = 'Enabled'; $arr['user_levels'] = $meta->user_levels; $arr['user_roles'] = isset($meta->user_roles) ? $meta->user_roles : ""; diff --git a/core/modules/employees/customTemplates/myDetails.html b/core/modules/employees/customTemplates/myDetails.html index afc5c057..8cc96043 100644 --- a/core/modules/employees/customTemplates/myDetails.html +++ b/core/modules/employees/customTemplates/myDetails.html @@ -21,10 +21,10 @@
    - - - - + + + +
    @@ -47,7 +47,7 @@
    -

    Personal Information

    +

    Personal Information

    @@ -89,7 +89,7 @@
    -

    Contact Information

    +

    Contact Information

    @@ -134,7 +134,7 @@
    -

    Job Details

    +

    Job Details

    @@ -146,11 +146,11 @@
    - +
    - +
    @@ -185,7 +185,7 @@
    - +
    - +
    @@ -211,8 +211,8 @@
    diff --git a/core/modules/meta.json b/core/modules/meta.json index afa92fb6..b74e130c 100644 --- a/core/modules/meta.json +++ b/core/modules/meta.json @@ -1,4 +1,5 @@ { +"Discussions":"fa-comments", "Personal Information":"fa-male", "Leave":"fa-calendar-o", "Time Management":"fa-clock-o", diff --git a/core/modules/travel/index.php b/core/modules/travel/index.php index 858acd72..0c37bcb6 100644 --- a/core/modules/travel/index.php +++ b/core/modules/travel/index.php @@ -32,6 +32,9 @@ $appModName = $moduleMainName.'Approval'; define('MODULE_PATH',dirname(__FILE__)); include APP_BASE_PATH.'header.php'; + +$customFields = \Classes\BaseService::getInstance()->getCustomFields("EmployeeTravelRecord"); + $additionalJs = array(); $additionalJs[] = BASE_URL.'admin/travel/lib.js?v='.$jsVersion; include APP_BASE_PATH.'modulejslibs.inc.php'; @@ -72,7 +75,7 @@ include APP_BASE_PATH.'modulejslibs.inc.php';
    +``` + +#### Babel + +[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively. + +```js +import $ from "jquery"; +``` + +#### Browserify/Webpack + +There are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this... + +```js +var $ = require("jquery"); +``` + +#### AMD (Asynchronous Module Definition) + +AMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html). + +```js +define(["jquery"], function($) { + +}); +``` + +### Node + +To include jQuery in [Node](nodejs.org), first install with npm. + +```sh +npm install jquery +``` + +For jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes. + +```js +require("jsdom").env("", function(err, window) { + if (err) { + console.error(err); + return; + } + + var $ = require("jquery")(window); +}); +``` diff --git a/web/bower_components/jquery/bower.json b/web/bower_components/jquery/bower.json new file mode 100644 index 00000000..95798d5a --- /dev/null +++ b/web/bower_components/jquery/bower.json @@ -0,0 +1,14 @@ +{ + "name": "jquery", + "main": "dist/jquery.js", + "license": "MIT", + "ignore": [ + "package.json" + ], + "keywords": [ + "jquery", + "javascript", + "browser", + "library" + ] +} \ No newline at end of file diff --git a/web/bower_components/jquery/dist/core.js b/web/bower_components/jquery/dist/core.js new file mode 100644 index 00000000..3a1c0cc7 --- /dev/null +++ b/web/bower_components/jquery/dist/core.js @@ -0,0 +1,399 @@ +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + +define( [ + "./var/arr", + "./var/document", + "./var/getProto", + "./var/slice", + "./var/concat", + "./var/push", + "./var/indexOf", + "./var/class2type", + "./var/toString", + "./var/hasOwn", + "./var/fnToString", + "./var/ObjectFunctionString", + "./var/support", + "./var/isFunction", + "./var/isWindow", + "./core/DOMEval", + "./core/toType" +], function( arr, document, getProto, slice, concat, push, indexOf, + class2type, toString, hasOwn, fnToString, ObjectFunctionString, + support, isFunction, isWindow, DOMEval, toType ) { + +"use strict"; + +var + version = "3.3.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} + +return jQuery; +} ); diff --git a/web/bower_components/jquery/dist/jquery.js b/web/bower_components/jquery/dist/jquery.js new file mode 100644 index 00000000..9b5206bc --- /dev/null +++ b/web/bower_components/jquery/dist/jquery.js @@ -0,0 +1,10364 @@ +/*! + * jQuery JavaScript Library v3.3.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2018-01-20T17:24Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + + + + var preservedScriptAttributes = { + type: true, + src: true, + noModule: true + }; + + function DOMEval( code, doc, node ) { + doc = doc || document; + + var i, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + if ( node[ i ] ) { + script[ i ] = node[ i ]; + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.3.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
    " ], + col: [ 2, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + div.style.position = "absolute"; + scrollboxSizeVal = div.offsetWidth === 36 || "absolute"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + ) ); + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + val = curCSS( elem, dimension, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox; + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = valueIsBorderBox && + ( support.boxSizingReliable() || val === elem.style[ dimension ] ); + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + if ( val === "auto" || + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) { + + val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ]; + + // offsetWidth/offsetHeight provide border-box values + valueIsBorderBox = true; + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra && boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ); + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && support.scrollboxSize() === styles.position ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = Date.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( "