1
0
Fork 0
mirror of https://github.com/Oreolek/ifhub.club.git synced 2024-07-02 22:45:02 +03:00
ifhub.club/application/tests/behat/behat.phar

46291 lines
1.5 MiB
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
define('BEHAT_PHP_BIN_PATH', 'php');
define('BEHAT_BIN_PATH', __FILE__);
define('BEHAT_VERSION', '2.4.0');
Phar::mapPhar('behat.phar');
require_once 'phar://behat.phar/vendor/autoload.php';
// internal encoding to utf8
mb_internal_encoding('utf8');
if (!defined('BEHAT_PHAR_CLI') || true === BEHAT_PHAR_CLI) {
// check, that we are in CLI
if ('cli' === php_sapi_name()) {
$app = new Behat\Behat\Console\BehatApplication(BEHAT_VERSION);
$app->run();
} else {
throw new RuntimeException('Behat can be runned only as CLI utility');
}
exit(0);
}
__HALT_COMPILER(); ?>
#
behat.phar)src/Behat/Behat/Annotation/Annotation.php<68>€†ÌO<C38C>Á)•#¶2src/Behat/Behat/Annotation/AnnotationInterface.phps€†ÌOs¹_(Ù¶2src/Behat/Behat/ClassLoader/MapFileClassLoader.php‡€†ÌO‡õm50src/Behat/Behat/Compiler/PearMapFileCompiler.php€†ÌOð™°¶,src/Behat/Behat/Console/BehatApplication.phpò€†ÌOòÊ_š³¶/src/Behat/Behat/Console/Command/BaseCommand.php €†ÌO rU{¢¶0src/Behat/Behat/Console/Command/BehatCommand.php〆ÌOãÉIÇ^¶5src/Behat/Behat/Console/Formatter/OutputFormatter.php` €†ÌO` ÁØ01src/Behat/Behat/Console/Input/InputDefinition.phpµ€†ÌOµK8src/Behat/Behat/Console/Processor/AggregateProcessor.php΀†ÌOβ2=¶<src/Behat/Behat/Console/Processor/ContextReaderProcessor.php.€†ÌO.µ=5src/Behat/Behat/Console/Processor/FormatProcessor.php·)€†ÌO·)çö. ¶6src/Behat/Behat/Console/Processor/GherkinProcessor.php×
€†ÌO×
Š¿3src/Behat/Behat/Console/Processor/HelpProcessor.phpa €†ÌOa ª]½»¶3src/Behat/Behat/Console/Processor/InitProcessor.php@€†ÌO@•º9¶6src/Behat/Behat/Console/Processor/LocatorProcessor.phpj
€†ÌOj
øˆ<C3B8>¯¶/src/Behat/Behat/Console/Processor/Processor.phpl€†ÌOlŠºGF¶8src/Behat/Behat/Console/Processor/ProcessorInterface.php»€†ÌO»fOÇ"¶2src/Behat/Behat/Console/Processor/RunProcessor.phpô€†ÌOôÒ¹<C392>(src/Behat/Behat/Context/BehatContext.phpB €†ÌOB ø¶>src/Behat/Behat/Context/ClassGuesser/ClassGuesserInterface.php€†ÌO­Àzˆ?src/Behat/Behat/Context/ClassGuesser/PredefinedClassGuesser.phpS€†ÌOSw<>¶4src/Behat/Behat/Context/ClosuredContextInterface.phpÑ€†ÌOÑÁç¦m¶-src/Behat/Behat/Context/ContextDispatcher.phpN €†ÌON ,»þl¶,src/Behat/Behat/Context/ContextInterface.php|€†ÌO|¹ˆ[¶)src/Behat/Behat/Context/ContextReader.phpÝ€†ÌOݤÝ4src/Behat/Behat/Context/ExtendedContextInterface.phpÈ€†ÌOÈ<âf†¶<src/Behat/Behat/Context/Initializer/InitializerInterface.php1€†ÌO1: Y2src/Behat/Behat/Context/Loader/AnnotatedLoader.php€†ÌOr.Y¶1src/Behat/Behat/Context/Loader/ClosuredLoader.phpñ€†ÌOñn_02src/Behat/Behat/Context/Loader/LoaderInterface.php3€†ÌO3†+3src/Behat/Behat/Context/Loader/TranslatedLoader.phpó€†ÌOóè:?¶&src/Behat/Behat/Context/Step/Given.php|€†ÌO|]f†/¶1src/Behat/Behat/Context/Step/SubstepInterface.php€†ÌOµãk<C3A3>%src/Behat/Behat/Context/Step/Then.phpx€†ÌOx»¶%src/Behat/Behat/Context/Step/When.phpx€†ÌOx¬&'Û¶:src/Behat/Behat/Context/SubcontextableContextInterface.phpó€†ÌOó«¶6src/Behat/Behat/Context/TranslatedContextInterface.php5€†ÌO5èŒ5src/Behat/Behat/DataCollector/LoggerDataCollector.php%!€†ÌO%!=¨ÜZ¶4src/Behat/Behat/Definition/Annotation/Definition.php±€†ÌO±ö¢—¶/src/Behat/Behat/Definition/Annotation/Given.php8€†ÌO8#¥ûæ¶.src/Behat/Behat/Definition/Annotation/Then.php5€†ÌO5ض8src/Behat/Behat/Definition/Annotation/Transformation.php¿ €†ÌO¿ ‡[鄶.src/Behat/Behat/Definition/Annotation/When.php5€†ÌO5@^<5E>3src/Behat/Behat/Definition/DefinitionDispatcher.php€†ÌOÀ ö¹¶2src/Behat/Behat/Definition/DefinitionInterface.php/€†ÌO/'Muu¶0src/Behat/Behat/Definition/DefinitionSnippet.phpù€†ÌOùÅ#»`¶>src/Behat/Behat/Definition/Loader/ClosuredDefinitionLoader.php €†ÌO ™jÁ¶?src/Behat/Behat/Definition/Loader/DefinitionLoaderInterface.php$€†ÌO$€€GR¶Csrc/Behat/Behat/Definition/Proposal/AnnotatedDefinitionProposal.phpº€†ÌOºKQiBsrc/Behat/Behat/Definition/Proposal/ClosuredDefinitionProposal.php
€†ÌO
jO÷E¶Dsrc/Behat/Behat/Definition/Proposal/DefinitionProposalDispatcher.phpö€†ÌOöl¼sI¶Csrc/Behat/Behat/Definition/Proposal/DefinitionProposalInterface.phpù€†ÌOùî9ð¾¶6src/Behat/Behat/Definition/TransformationInterface.php〆ÌOãͽØ}¶6src/Behat/Behat/DependencyInjection/BehatExtension.phpØ&€†ÌOØ&µPZ]¶Fsrc/Behat/Behat/DependencyInjection/Compiler/ConsoleProcessorsPass.php´€†ÌO´ EMIsrc/Behat/Behat/DependencyInjection/Compiler/ContextClassGuessersPass.php€†ÌOE• Hsrc/Behat/Behat/DependencyInjection/Compiler/ContextInitializersPass.php·€†ÌO·®B±í¶Csrc/Behat/Behat/DependencyInjection/Compiler/ContextLoadersPass.php¢€†ÌO¢«0<C2AB>Hsrc/Behat/Behat/DependencyInjection/Compiler/DefinitionProposalsPass.phpÌ€†ÌO̺šâ”¶Esrc/Behat/Behat/DependencyInjection/Compiler/EventSubscribersPass.php<68>€†ÌO<C38C>ü™[?src/Behat/Behat/DependencyInjection/Compiler/FormattersPass.php€†ÌO3âæA¶Csrc/Behat/Behat/DependencyInjection/Compiler/GherkinLoadersPass.php„€†ÌO„vç[ܶ4src/Behat/Behat/DependencyInjection/config/behat.xml¢J€†ÌO¢Jº§ˆCsrc/Behat/Behat/DependencyInjection/Configuration/Configuration.phpu€†ÌOuhá\w¶<src/Behat/Behat/DependencyInjection/Configuration/Loader.php€€†ÌO€”Ó&‹¶)src/Behat/Behat/Event/BackgroundEvent.php€†ÌOÂí(src/Behat/Behat/Event/EventInterface.php|€†ÌO|CWrû¶&src/Behat/Behat/Event/FeatureEvent.phpŽ€†ÌOŽ¬Ý´Á¶&src/Behat/Behat/Event/OutlineEvent.phpl€†ÌOl 0x¶-src/Behat/Behat/Event/OutlineExampleEvent.phpÜ€†ÌOÜ )j ¶'src/Behat/Behat/Event/ScenarioEvent.php
€†ÌO
r1¶#src/Behat/Behat/Event/StepEvent.php€†ÌOP<'Ƕ$src/Behat/Behat/Event/SuiteEvent.php€†ÌOʼù€¶0src/Behat/Behat/Exception/AmbiguousException.php€†ÌO0…p/src/Behat/Behat/Exception/BehaviorException.php”€†ÌO”VwÙ¶,src/Behat/Behat/Exception/ErrorException.php€†ÌOÃÈ5¶'src/Behat/Behat/Exception/Exception.php<68>€†ÌO<C38C>®ðÅ©¶0src/Behat/Behat/Exception/FormatterException.php€†ÌOÿ씟¶.src/Behat/Behat/Exception/PendingException.php¦€†ÌO¦<°ß¨¶0src/Behat/Behat/Exception/RedundantException.phpЀ†ÌOд»Oݶ0src/Behat/Behat/Exception/UndefinedException.php¥€†ÌO¥\§ã'src/Behat/Behat/Extension/Extension.php…€†ÌO…êÊ„~¶0src/Behat/Behat/Extension/ExtensionInterface.phpj€†ÌOjß¼KM¶.src/Behat/Behat/Extension/ExtensionManager.php €†ÌO ×É9¶¶.src/Behat/Behat/Formatter/ConsoleFormatter.php× €†ÌO× ™å­¿¶6src/Behat/Behat/Formatter/FailedScenariosFormatter.php´€†ÌO´G1src/Behat/Behat/Formatter/FormatterDispatcher.phpÌOîP´ðƶ0src/Behat/Behat/Formatter/FormatterInterface.php<68>€†ÌO<C38C>¢ M¸.src/Behat/Behat/Formatter/FormatterManager.phpÿ
€†ÌOÿ
°gî¶+src/Behat/Behat/Formatter/HtmlFormatter.php!q€†ÌO!qÅ—5,src/Behat/Behat/Formatter/JUnitFormatter.php€†ÌOœŠ("¶-src/Behat/Behat/Formatter/PrettyFormatter.phpMp€†ÌOMpéØ©^¶/src/Behat/Behat/Formatter/ProgressFormatter.php2€†ÌO2Ž6v+¶/src/Behat/Behat/Formatter/SnippetsFormatter.php€†ÌO»ZÈ5src/Behat/Behat/Gherkin/Loader/FeatureSuiteLoader.php+€†ÌO+âA¶2src/Behat/Behat/HelpPrinter/DefinitionsPrinter.php9 €†ÌO9 ŒDÓ<¶2src/Behat/Behat/HelpPrinter/StorySyntaxPrinter.php-€†ÌO-0”ƒç¶0src/Behat/Behat/Hook/Annotation/AfterFeature.php €†ÌO g]vÚ¶1src/Behat/Behat/Hook/Annotation/AfterScenario.php €†ÌO -<2D>-src/Behat/Behat/Hook/Annotation/AfterStep.phpý€†ÌOýÒ014¶.src/Behat/Behat/Hook/Annotation/AfterSuite.php€†ÌO»!â϶1src/Behat/Behat/Hook/Annotation/BeforeFeature.php €†ÌO rw2src/Behat/Behat/Hook/Annotation/BeforeScenario.php€†ÌOÇ@ˆ¶.src/Behat/Behat/Hook/Annotation/BeforeStep.php€†ÌO/YU#¶/src/Behat/Behat/Hook/Annotation/BeforeSuite.php€†ÌO É®¶/src/Behat/Behat/Hook/Annotation/FeatureHook.php€†ÌO¬¬k¼¶2src/Behat/Behat/Hook/Annotation/FilterableHook.phpx€†ÌOx½@ɶ(src/Behat/Behat/Hook/Annotation/Hook.php€†ÌO<00> u7¶0src/Behat/Behat/Hook/Annotation/ScenarioHook.php@€†ÌO@ýÇòr¶,src/Behat/Behat/Hook/Annotation/StepHook.phpÀ†ÌOÃ…­Ýݶ-src/Behat/Behat/Hook/Annotation/SuiteHook.phpÌ€†ÌOÌ'”-æ¶'src/Behat/Behat/Hook/HookDispatcher.php~€†ÌO~ú†ä¶&src/Behat/Behat/Hook/HookInterface.phpÌOîC Bp¶2src/Behat/Behat/Hook/Loader/ClosuredHookLoader.php£€†ÌO££!MN¶3src/Behat/Behat/Hook/Loader/HookLoaderInterface.php€†ÌOÚà»u¶+src/Behat/Behat/Tester/BackgroundTester.phpk
€†ÌOk
–Á‚Ò¶(src/Behat/Behat/Tester/FeatureTester.phpÅ
€†ÌOÅ
ðÙ´¶(src/Behat/Behat/Tester/OutlineTester.phpN €†ÌON ’ õò¶)src/Behat/Behat/Tester/ScenarioTester.php€†ÌOó‰Y¶%src/Behat/Behat/Tester/StepTester.phpЀ†ÌOÐ,ÿ9<C3BF>!src/Behat/Behat/Util/data/x00.php!€†ÌO!4ei¶!src/Behat/Behat/Util/data/x01.phpL€†ÌOLCyœ¶!src/Behat/Behat/Util/data/x02.phpŽ€†ÌOŽ¥¢ón¶!src/Behat/Behat/Util/data/x03.phpd€†ÌOd÷<>¯ì¶!src/Behat/Behat/Util/data/x04.php ÌOâüÿE*¶!src/Behat/Behat/Util/data/x05.phpЀ†ÌOÐÙ1ü¶!src/Behat/Behat/Util/data/x06.php“€†ÌO“$œŸé¶!src/Behat/Behat/Util/data/x07.php?€†ÌO?Eâ"Ķ!src/Behat/Behat/Util/data/x09.php(€†ÌO(˜A'¶!src/Behat/Behat/Util/data/x0a.php €†ÌO ùÅç¶!src/Behat/Behat/Util/data/x0b.php>€†ÌO>hfB ¶!src/Behat/Behat/Util/data/x0c.phpJ€†ÌOJ S2S¶!src/Behat/Behat/Util/data/x0d.php.€†ÌO.C8G!src/Behat/Behat/Util/data/x0e.phpA€†ÌOAúʶ!src/Behat/Behat/Util/data/x0f.php#€†ÌO#*Aäñ¶!src/Behat/Behat/Util/data/x10.php€†ÌO0†!src/Behat/Behat/Util/data/x11.php1€†ÌO1÷ÿÝ!src/Behat/Behat/Util/data/x12.phpO€†ÌOOûBö+¶!src/Behat/Behat/Util/data/x13.phpô€†ÌOôÎ<C38E> !src/Behat/Behat/Util/data/x14.php¿€†ÌO¿ΪͶ!src/Behat/Behat/Util/data/x15.php耆ÌOè€Ä{m¶!src/Behat/Behat/Util/data/x16.php€†ÌOE'«¶!src/Behat/Behat/Util/data/x17.phpT€†ÌOT!src/Behat/Behat/Util/data/x18.php…€†ÌO…<00>dB²¶!src/Behat/Behat/Util/data/x1e.php*€†ÌO*qÓã¶!src/Behat/Behat/Util/data/x1f.php(€†ÌO(üTæ¶!src/Behat/Behat/Util/data/x20.php(€†ÌO(Ÿ!src/Behat/Behat/Util/data/x21.php(€†ÌO(—n€¶!src/Behat/Behat/Util/data/x22.php(€†ÌO(ü#¦©¶!src/Behat/Behat/Util/data/x23.php(€†ÌO(m²Î!src/Behat/Behat/Util/data/x24.php6€†ÌO6Òr[v¶!src/Behat/Behat/Util/data/x25.php\€†ÌO\ÓÌqK¶!src/Behat/Behat/Util/data/x26.phpü€†ÌOü­ºc}¶!src/Behat/Behat/Util/data/x27.php¢€†ÌO¢JŒ1c¶!src/Behat/Behat/Util/data/x28.php"€†ÌO"$½¤¢¶!src/Behat/Behat/Util/data/x2e.php"€†ÌO"N`˜!src/Behat/Behat/Util/data/x2f.php뀆ÌOëcVê`¶!src/Behat/Behat/Util/data/x30.phpG€†ÌOGú‘.­¶!src/Behat/Behat/Util/data/x31.phpÛ€†ÌOÛ>CpB¶!src/Behat/Behat/Util/data/x32.phpñ€†ÌOñ,Qº!src/Behat/Behat/Util/data/x33.php逆ÌOé^ò䦶!src/Behat/Behat/Util/data/x4d.php(€†ÌO(t5Z•¶!src/Behat/Behat/Util/data/x4e.php(€†ÌO(å¤2;¶!src/Behat/Behat/Util/data/x4f.php(€†ÌO(ú!src/Behat/Behat/Util/data/x50.php(€†ÌO(Ôz”!src/Behat/Behat/Util/data/x51.php(€†ÌO(Eëü !src/Behat/Behat/Util/data/x52.php•€†ÌO• kÓ¶!src/Behat/Behat/Util/data/x53.php€†ÌO
¬ó!¶!src/Behat/Behat/Util/data/x54.php뀆ÌOëÃ<>‡|¶!src/Behat/Behat/Util/data/x55.phpE€†ÌOEݶ!src/Behat/Behat/Util/data/x56.phpÍ€†ÌOÍpݦC¶!src/Behat/Behat/Util/data/x57.phpô€†ÌOô…õ3}¶!src/Behat/Behat/Util/data/x58.php(€†ÌO(›å‡}¶!src/Behat/Behat/Util/data/x59.php(€†ÌO(
tïÓ¶!src/Behat/Behat/Util/data/x5a.php(€†ÌO(!#¥h¶!src/Behat/Behat/Util/data/x5b.php(€†ÌO(Ó—mA¶!src/Behat/Behat/Util/data/x5c.php(€†ÌO(Bï¶!src/Behat/Behat/Util/data/x5d.php(€†ÌO(7þü!src/Behat/Behat/Util/data/x5e.php(€†ÌO(¦o”¼¶!src/Behat/Behat/Util/data/x5f.php(€†ÌO(TÛ\•¶!src/Behat/Behat/Util/data/x60.php(€†ÌO(P!!src/Behat/Behat/Util/data/x61.php(€†ÌO(Á°fó¶!src/Behat/Behat/Util/data/x62.php(€†ÌO(3®Ú¶!src/Behat/Behat/Util/data/x63.php(€†ÌO(¢•Æt¶!src/Behat/Behat/Util/data/x64.php(€†ÌO(×m?‰¶!src/Behat/Behat/Util/data/x65.php(€†ÌO(FüW'¶!src/Behat/Behat/Util/data/x66.php(€†ÌO(´!src/Behat/Behat/Util/data/x67.php(€†ÌO(%Ù÷ ¶!src/Behat/Behat/Util/data/x68.php(€†ÌO(¾!src/Behat/Behat/Util/data/x69.php(€†ÌO(Ž/u€¶!src/Behat/Behat/Util/data/x6a.php(€†ÌO(¥x?;¶!src/Behat/Behat/Util/data/x6b.php(€†ÌO(WÌ÷!src/Behat/Behat/Util/data/x6c.php(€†ÌO(Æ]Ÿ¼¶!src/Behat/Behat/Util/data/x6d.php(€†ÌO(³¥fA¶!src/Behat/Behat/Util/data/x6e.php(€†ÌO("4ï¶!src/Behat/Behat/Util/data/x6f.php(€†ÌO(ЀÆƶ!src/Behat/Behat/Util/data/x70.php(€†ÌO(ê¨Ú¶!src/Behat/Behat/Util/data/x71.phpØ€†ÌOØ<00>fuy¶!src/Behat/Behat/Util/data/x72.phpD€†ÌODHDvÛ¶!src/Behat/Behat/Util/data/x73.php€†ÌOóû ·¶!src/Behat/Behat/Util/data/x74.phpg€†ÌOg Ák¶!src/Behat/Behat/Util/data/x75.phpj€†ÌOj<00>S<¶!src/Behat/Behat/Util/data/x76.phpK€†ÌOK~!src/Behat/Behat/Util/data/x77.php%€†ÌO%s¯Ó!src/Behat/Behat/Util/data/x78.php€†ÌO-¢•µ¶!src/Behat/Behat/Util/data/x79.php€†ÌOÌëì¶!src/Behat/Behat/Util/data/x7a.php$€†ÌO$oR!src/Behat/Behat/Util/data/x7b.php4€†ÌO4ËÔ±l¶!src/Behat/Behat/Util/data/x7c.phpc€†ÌOc¾e6!src/Behat/Behat/Util/data/x7d.phpA€†ÌOAk!src/Behat/Behat/Util/data/x7e.php9€†ÌO9!src/Behat/Behat/Util/data/x7f.phpY€†ÌOYäâ„û¶!src/Behat/Behat/Util/data/x80.php!€†ÌO!Ú%—ä¶!src/Behat/Behat/Util/data/x81.php[€†ÌO[c8ö¹¶!src/Behat/Behat/Util/data/x82.phpY€†ÌOYÀPK¶!src/Behat/Behat/Util/data/x83.phpQ€†ÌOQ<03>Êð¶!src/Behat/Behat/Util/data/x84.php?€†ÌO?·ÄC¶!src/Behat/Behat/Util/data/x85.phpS€†ÌOSþ;ÜJ¶!src/Behat/Behat/Util/data/x86.php)€†ÌO)^s<>!src/Behat/Behat/Util/data/x87.phpM€†ÌOM²Lãí¶!src/Behat/Behat/Util/data/x88.phpL€†ÌOLÀ €ô¶!src/Behat/Behat/Util/data/x89.php;€†ÌO;¯t¸þ¶!src/Behat/Behat/Util/data/x8a.phpb€†ÌObú¶!src/Behat/Behat/Util/data/x8b.php8€†ÌO8<17>ˆ!src/Behat/Behat/Util/data/x8c.php_€†ÌO_ò¡P×!src/Behat/Behat/Util/data/x8d.php^€†ÌO^(úŸM¶!src/Behat/Behat/Util/data/x8e.php_€†ÌO_rǬ!src/Behat/Behat/Util/data/x8f.php€†ÌO ¬!src/Behat/Behat/Util/data/x90.php@€†ÌO@Ò‹'ض!src/Behat/Behat/Util/data/x91.phpH€†ÌOH™rä¶!src/Behat/Behat/Util/data/x92.php=€†ÌO=¬Z«¶!src/Behat/Behat/Util/data/x93.phpG€†ÌOGÑÌ
!src/Behat/Behat/Util/data/x94.phpr€†ÌOru;pÕ¶!src/Behat/Behat/Util/data/x95.php[€†ÌO[UM톶!src/Behat/Behat/Util/data/x96.phpP€†ÌOPjÏc³¶!src/Behat/Behat/Util/data/x97.phpC€†ÌOC%'eF¶!src/Behat/Behat/Util/data/x98.phpu€†ÌOuîm
!src/Behat/Behat/Util/data/x99.php`€†ÌO`d«_§¶!src/Behat/Behat/Util/data/x9a.php<€†ÌO<ûa8¶!src/Behat/Behat/Util/data/x9b.php`€†ÌO`Š!src/Behat/Behat/Util/data/x9c.phpE€†ÌOE³ç»v¶!src/Behat/Behat/Util/data/x9d.php€†ÌO<65>!src/Behat/Behat/Util/data/x9e.phpZ€†ÌOZ½¬™!src/Behat/Behat/Util/data/x9f.phpZ€†ÌOZÁ äK¶!src/Behat/Behat/Util/data/xa0.phpT€†ÌOT[è‡/¶!src/Behat/Behat/Util/data/xa1.phpc€†ÌOcÇ öG¶!src/Behat/Behat/Util/data/xa2.phpg€†ÌOg<00>qw¶¶!src/Behat/Behat/Util/data/xa3.phpU€†ÌOUí’Õƒ¶!src/Behat/Behat/Util/data/xa4.phpH€†ÌOHÇ®¬:¶!src/Behat/Behat/Util/data/xac.php^€†ÌO^¯³Ýa¶!src/Behat/Behat/Util/data/xad.phpF€†ÌOF©nGl¶!src/Behat/Behat/Util/data/xae.php@€†ÌO@`4p<¶!src/Behat/Behat/Util/data/xaf.phpC€†ÌOCY*À¶!src/Behat/Behat/Util/data/xb0.php9€†ÌO9õ¶!src/Behat/Behat/Util/data/xb1.php#€†ÌO#áýè!src/Behat/Behat/Util/data/xb2.phpF€†ÌOFÙv¿h¶!src/Behat/Behat/Util/data/xb3.phpB€†ÌOBß:W¶!src/Behat/Behat/Util/data/xb4.php1€†ÌO1Ç—n¶!src/Behat/Behat/Util/data/xb5.phpD€†ÌODh¢º¶!src/Behat/Behat/Util/data/xb6.php@€†ÌO@»Â/‘¶!src/Behat/Behat/Util/data/xb7.php3€†ÌO3Uø€¶!src/Behat/Behat/Util/data/xb8.php9€†ÌO9õH!src/Behat/Behat/Util/data/xb9.phpP€†ÌOPÑ7u!src/Behat/Behat/Util/data/xba.phpH€†ÌOH3'!src/Behat/Behat/Util/data/xbb.php4€†ÌO4¬<†¶!src/Behat/Behat/Util/data/xbc.phpL€†ÌOLyñ+‡¶!src/Behat/Behat/Util/data/xbd.phpE€†ÌOEä£ý!src/Behat/Behat/Util/data/xbe.phpW€†ÌOW5q¤@¶!src/Behat/Behat/Util/data/xbf.phpR€†ÌOR2SÃ!src/Behat/Behat/Util/data/xc0.php\€†ÌO\>`N¶!src/Behat/Behat/Util/data/xc1.php€†ÌOX¶'¶!src/Behat/Behat/Util/data/xc2.php@€†ÌO@<RA߶!src/Behat/Behat/Util/data/xc3.phpB€†ÌOBr Kh¶!src/Behat/Behat/Util/data/xc4.php2€†ÌO2«eò†¶!src/Behat/Behat/Util/data/xc5.php,€†ÌO,u¡_>¶!src/Behat/Behat/Util/data/xc6.phpL€†ÌOL;~õ¶!src/Behat/Behat/Util/data/xc7.phpP€†ÌOPšÂƶ!src/Behat/Behat/Util/data/xc8.php5€†ÌO5ìõ!src/Behat/Behat/Util/data/xc9.php$€†ÌO$¬¯|å¶!src/Behat/Behat/Util/data/xca.phpÅ€†ÌOÅ|&¶þ¶!src/Behat/Behat/Util/data/xcb.phpi€†ÌOi8î »¶!src/Behat/Behat/Util/data/xcc.php€†ÌOÚÝüZ¶!src/Behat/Behat/Util/data/xcd.php´€†ÌO´áUw¶!src/Behat/Behat/Util/data/xce.phpÆ€†ÌOÆõ!t¶!src/Behat/Behat/Util/data/xcf.php}€†ÌO};*p¶!src/Behat/Behat/Util/data/xd0.php(€†ÌO(M%ö!src/Behat/Behat/Util/data/xd1.php(€†ÌO(<00>ÜMm¶!src/Behat/Behat/Util/data/xd2.php(€†ÌO(}h…D¶!src/Behat/Behat/Util/data/xd3.php(€†ÌO(ìùíê¶!src/Behat/Behat/Util/data/xd4.php(€†ÌO(!src/Behat/Behat/Util/data/xd5.php(€†ÌO(<08>|¹¶!src/Behat/Behat/Util/data/xd6.php(€†ÌO(ú$´<>!src/Behat/Behat/Util/data/xd7.php€†ÌO+*Lµ¶!src/Behat/Behat/Util/data/xf9.php»€†ÌO»ÐýÈ !src/Behat/Behat/Util/data/xfa.php(€†ÌO(aÁ[¶!src/Behat/Behat/Util/data/xfb.php±€†ÌO±SÈ!src/Behat/Behat/Util/data/xfc.php€†ÌOÚ¯¨¶!src/Behat/Behat/Util/data/xfd.php§€†ÌO§h=µ¶!src/Behat/Behat/Util/data/xfe.phpe€†ÌOe !src/Behat/Behat/Util/data/xff.php¢€†ÌO¢åY¾?¶src/Behat/Behat/Util/LICENSEÜ€†ÌOÜ{U^j¶'src/Behat/Behat/Util/Transliterator.phpK€†ÌOK®ŽˆÖ¶vendor/.composer/autoload.phpW€†ÌOWÁk&vendor/.composer/autoload_classmap.phpi€†ÌOiø¾¢V¶(vendor/.composer/autoload_namespaces.phpk€†ÌOk¤Aí  vendor/.composer/ClassLoader.phpc€†ÌOcX0Lvendor/autoload.php{€†ÌO{ÿ>Êè¶!vendor/behat/gherkin/autoload.php0€†ÌO0Æ0gy¶vendor/behat/gherkin/i18n.phpH€†ÌOHNã¨|¶ vendor/behat/gherkin/libpath.php€†ÌOtrnǶvendor/behat/gherkin/LICENSE>€†ÌO>?vendor/behat/gherkin/src/Behat/Gherkin/Cache/CacheInterface.php)€†ÌO)ŒgPž¶:vendor/behat/gherkin/src/Behat/Gherkin/Cache/FileCache.php€†ÌOÓ?3„¶?vendor/behat/gherkin/src/Behat/Gherkin/Dumper/GherkinDumper.php³€†ÌO³>vendor/behat/gherkin/src/Behat/Gherkin/Exception/Exception.php=€†ÌO=õ¶ Cvendor/behat/gherkin/src/Behat/Gherkin/Exception/LexerException.phpA€†ÌOAûZÅN¶Dvendor/behat/gherkin/src/Behat/Gherkin/Exception/ParserException.phpB€†ÌOBÂ6¸Ö¶Avendor/behat/gherkin/src/Behat/Gherkin/Filter/FilterInterface.php“€†ÌO“2egæ¶<vendor/behat/gherkin/src/Behat/Gherkin/Filter/LineFilter.php0€†ÌO0]6í¶Avendor/behat/gherkin/src/Behat/Gherkin/Filter/LineRangeFilter.php­€†ÌO­î&t¿¶<vendor/behat/gherkin/src/Behat/Gherkin/Filter/NameFilter.phpK€†ÌOK•¹Ž<C2B9>;vendor/behat/gherkin/src/Behat/Gherkin/Filter/TagFilter.phpÉ€†ÌOÉ2vendor/behat/gherkin/src/Behat/Gherkin/Gherkin.php €†ÌO a œ†¶Avendor/behat/gherkin/src/Behat/Gherkin/Keywords/ArrayKeywords.php€†ÌO±¶Gvendor/behat/gherkin/src/Behat/Gherkin/Keywords/CachedArrayKeywords.phpÄ€†ÌOÄ-,=¶Dvendor/behat/gherkin/src/Behat/Gherkin/Keywords/CucumberKeywords.php€†ÌOÎBE¶Bvendor/behat/gherkin/src/Behat/Gherkin/Keywords/KeywordsDumper.phpZ"€†ÌOZ"~kâI¶Evendor/behat/gherkin/src/Behat/Gherkin/Keywords/KeywordsInterface.phpÁ€†ÌOÁá:½Â¶Nvendor/behat/gherkin/src/Behat/Gherkin/Keywords/SymfonyTranslationKeywords.php€†ÌOÅôæ¶0vendor/behat/gherkin/src/Behat/Gherkin/Lexer.php§4€†ÌO§4½)äã¶Dvendor/behat/gherkin/src/Behat/Gherkin/Loader/AbstractFileLoader.php^€†ÌO^•>ÝÁ¶=vendor/behat/gherkin/src/Behat/Gherkin/Loader/ArrayLoader.phpÙ€†ÌOÙÂÛ'‡¶Avendor/behat/gherkin/src/Behat/Gherkin/Loader/DirectoryLoader.php…€†ÌO…`‚èú¶Evendor/behat/gherkin/src/Behat/Gherkin/Loader/FileLoaderInterface.php-€†ÌO-k˜¡à¶Cvendor/behat/gherkin/src/Behat/Gherkin/Loader/GherkinFileLoader.php¶ €†ÌO¶ ¼ö̶Avendor/behat/gherkin/src/Behat/Gherkin/Loader/LoaderInterface.phpþ€†ÌOþDÿÛl¶@vendor/behat/gherkin/src/Behat/Gherkin/Loader/YamlFileLoader.phpÝ €†ÌOÝ ‹ÍÕñ¶<vendor/behat/gherkin/src/Behat/Gherkin/Node/AbstractNode.php€†ÌOŒ§¶Dvendor/behat/gherkin/src/Behat/Gherkin/Node/AbstractScenarioNode.php€†ÌO ³É¶>vendor/behat/gherkin/src/Behat/Gherkin/Node/BackgroundNode.php©€†ÌO©È®KR¶Cvendor/behat/gherkin/src/Behat/Gherkin/Node/ExamplePyStringNode.phpü€†ÌOüÖtÖ¶?vendor/behat/gherkin/src/Behat/Gherkin/Node/ExampleStepNode.phpÀ†ÌOÃÌKF¶@vendor/behat/gherkin/src/Behat/Gherkin/Node/ExampleTableNode.php〆ÌOãûÝôV¶;vendor/behat/gherkin/src/Behat/Gherkin/Node/FeatureNode.phpE€†ÌOE{oDvendor/behat/gherkin/src/Behat/Gherkin/Node/NodeVisitorInterface.php?€†ÌO?ÎA;vendor/behat/gherkin/src/Behat/Gherkin/Node/OutlineNode.phph€†ÌOhËæ<vendor/behat/gherkin/src/Behat/Gherkin/Node/PyStringNode.phpW€†ÌOWLO¨ž¶<vendor/behat/gherkin/src/Behat/Gherkin/Node/ScenarioNode.phpu€†ÌOu!gûQ¶Ivendor/behat/gherkin/src/Behat/Gherkin/Node/StepArgumentNodeInterface.phpL€†ÌOLªñâɶ8vendor/behat/gherkin/src/Behat/Gherkin/Node/StepNode.phpn€†ÌOn¾+¿ƒ¶9vendor/behat/gherkin/src/Behat/Gherkin/Node/TableNode.php‰€†ÌO‰"î#”¶1vendor/behat/gherkin/src/Behat/Gherkin/Parser.phpr4€†ÌOr4f"N¸%vendor/composer/autoload_classmap.phpˆ€†ÌOˆ^ÙV'vendor/composer/autoload_namespaces.php0€†ÌO0ì_™æ¶vendor/composer/ClassLoader.php«€†ÌO«²r>vendor/symfony/config/Symfony/Component/Config/ConfigCache.phpk €†ÌOk rdž¶Gvendor/symfony/config/Symfony/Component/Config/Definition/ArrayNode.php&€†ÌO&>knè¶Fvendor/symfony/config/Symfony/Component/Config/Definition/BaseNode.php뀆ÌOëŠÞ^K¶Ivendor/symfony/config/Symfony/Component/Config/Definition/BooleanNode.php«€†ÌO«î‰¶Yvendor/symfony/config/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.phpy €†ÌOy Ç̽i¶[vendor/symfony/config/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php±€†ÌO±P<>”¶Qvendor/symfony/config/Symfony/Component/Config/Definition/Builder/ExprBuilder.php<68>€†ÌO<C38C>Њm¶Rvendor/symfony/config/Symfony/Component/Config/Definition/Builder/MergeBuilder.phpµ€†ÌOµ/_l¶Qvendor/symfony/config/Symfony/Component/Config/Definition/Builder/NodeBuilder.phpÔ€†ÌOÔ=œÀ+¶Tvendor/symfony/config/Symfony/Component/Config/Definition/Builder/NodeDefinition.php.€†ÌO.ú†Å<E280A0>Yvendor/symfony/config/Symfony/Component/Config/Definition/Builder/NodeParentInterface.php¾€†ÌO¾Zvendor/symfony/config/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.phpƒ€†ÌOƒ¦ø®¶cvendor/symfony/config/Symfony/Component/Config/Definition/Builder/ParentNodeDefinitionInterface.phpJ€†ÌOJùY[ô¶Zvendor/symfony/config/Symfony/Component/Config/Definition/Builder/ScalarNodeDefinition.phpÞ€†ÌOÞFÿQvendor/symfony/config/Symfony/Component/Config/Definition/Builder/TreeBuilder.phpk€†ÌOkôÓô¶Wvendor/symfony/config/Symfony/Component/Config/Definition/Builder/ValidationBuilder.phpr€†ÌOrŒä<C592>Ó¶\vendor/symfony/config/Symfony/Component/Config/Definition/Builder/VariableNodeDefinition.php¿€†ÌO¿£<>STvendor/symfony/config/Symfony/Component/Config/Definition/ConfigurationInterface.php]€†ÌO]2þY>¶]vendor/symfony/config/Symfony/Component/Config/Definition/Exception/DuplicateKeyException.phpE€†ÌOEø|÷Qvendor/symfony/config/Symfony/Component/Config/Definition/Exception/Exception.phpÊ€†ÌOÊžCŠÐ¶cvendor/symfony/config/Symfony/Component/Config/Definition/Exception/ForbiddenOverwriteException.phpQ€†ÌOQ¨:2&¶evendor/symfony/config/Symfony/Component/Config/Definition/Exception/InvalidConfigurationException.php·€†ÌO·5-ý\vendor/symfony/config/Symfony/Component/Config/Definition/Exception/InvalidTypeException.php퀆ÌOí¾Ä@¶Yvendor/symfony/config/Symfony/Component/Config/Definition/Exception/UnsetKeyException.php€†ÌOþ¤½¿¶Kvendor/symfony/config/Symfony/Component/Config/Definition/NodeInterface.phpQ€†ÌOQºúúGvendor/symfony/config/Symfony/Component/Config/Definition/Processor.php€†ÌO'ò.ɶQvendor/symfony/config/Symfony/Component/Config/Definition/PrototypedArrayNode.php)!€†ÌO)!•F<E280A2>î¶Tvendor/symfony/config/Symfony/Component/Config/Definition/PrototypeNodeInterface.phpp€†ÌOpô~ÆJ¶Hvendor/symfony/config/Symfony/Component/Config/Definition/ScalarNode.phpq€†ÌOq “¶Jvendor/symfony/config/Symfony/Component/Config/Definition/VariableNode.php¸ €†ÌO¸ ¶gvendor/symfony/config/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.phpT€†ÌOT7¡ Tvendor/symfony/config/Symfony/Component/Config/Exception/FileLoaderLoadException.php% €†ÌO% ¤ZÅ€¶>vendor/symfony/config/Symfony/Component/Config/FileLocator.phpÇ
€†ÌOÇ
ÿåé¶Gvendor/symfony/config/Symfony/Component/Config/FileLocatorInterface.phpe€†ÌOen˜â$¶6vendor/symfony/config/Symfony/Component/Config/LICENSE)€†ÌO)àýC+¶Jvendor/symfony/config/Symfony/Component/Config/Loader/DelegatingLoader.php"€†ÌO"P>˜¶Dvendor/symfony/config/Symfony/Component/Config/Loader/FileLoader.phpY
€†ÌOY
HÃRQ¶@vendor/symfony/config/Symfony/Component/Config/Loader/Loader.phpx€†ÌOx@™&ú¶Ivendor/symfony/config/Symfony/Component/Config/Loader/LoaderInterface.phpð€†ÌOð]â(@¶Hvendor/symfony/config/Symfony/Component/Config/Loader/LoaderResolver.php¡€†ÌO¡rhq¶Qvendor/symfony/config/Symfony/Component/Config/Loader/LoaderResolverInterface.phpÓ€†ÌOÓjE¬Õ¶Mvendor/symfony/config/Symfony/Component/Config/Resource/DirectoryResource.php‡ €†ÌO‡ ÿÍPp¶Hvendor/symfony/config/Symfony/Component/Config/Resource/FileResource.php€†ÌO¢(¤Mvendor/symfony/config/Symfony/Component/Config/Resource/ResourceInterface.php/€†ÌO/ìf:ñ¶@vendor/symfony/console/Symfony/Component/Console/Application.phpÂi€†ÌOÂi™úoŠ¶Dvendor/symfony/console/Symfony/Component/Console/Command/Command.phpÕ>€†ÌOÕ>&È-¶Hvendor/symfony/console/Symfony/Component/Console/Command/HelpCommand.php¸€†ÌO¸_DC¶Hvendor/symfony/console/Symfony/Component/Console/Command/ListCommand.phpÔ€†ÌOÔ2°‡Ü¶Nvendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatter.phpЀ†ÌOÐÂ&rþ¶Wvendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterInterface.php¹€†ÌO¹FÿšÜ¶Svendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyle.phpÅ€†ÌOÅ2Q¶\vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.phpt€†ÌOtÿ#/ɶHvendor/symfony/console/Symfony/Component/Console/Helper/DialogHelper.phpw€†ÌOw®E虶Kvendor/symfony/console/Symfony/Component/Console/Helper/FormatterHelper.phpž
€†ÌOž
Ä<>Bvendor/symfony/console/Symfony/Component/Console/Helper/Helper.php¨€†ÌO¨»DqÓ¶Kvendor/symfony/console/Symfony/Component/Console/Helper/HelperInterface.phpÞ€†ÌOÞ™Ü+¨¶Evendor/symfony/console/Symfony/Component/Console/Helper/HelperSet.phpv €†ÌOv Øîãë¶Dvendor/symfony/console/Symfony/Component/Console/Input/ArgvInput.php×#€†ÌO×#³>9¸Evendor/symfony/console/Symfony/Component/Console/Input/ArrayInput.php€†ÌO`%²F¶@vendor/symfony/console/Symfony/Component/Console/Input/Input.phpŽ€†ÌOŽ<>Hvendor/symfony/console/Symfony/Component/Console/Input/InputArgument.phpÈ €†ÌOÈ W†ÝU¶Jvendor/symfony/console/Symfony/Component/Console/Input/InputDefinition.php@€†ÌO@«2¶Ivendor/symfony/console/Symfony/Component/Console/Input/InputInterface.phpÑ
€†ÌOÑ
¼?÷²¶Fvendor/symfony/console/Symfony/Component/Console/Input/InputOption.phpÛ€†ÌOÛºG‰O¶Fvendor/symfony/console/Symfony/Component/Console/Input/StringInput.phph
€†ÌOh
ý)jé¶8vendor/symfony/console/Symfony/Component/Console/LICENSE)€†ÌO)àýC+¶Ivendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutput.phpŠ€†ÌOŠ
¬¶Fvendor/symfony/console/Symfony/Component/Console/Output/NullOutput.phpÊ€†ÌOÊRÓͶBvendor/symfony/console/Symfony/Component/Console/Output/Output.php€†ÌOß½?°¶Kvendor/symfony/console/Symfony/Component/Console/Output/OutputInterface.phpÐ €†ÌOÐ LY÷ǶHvendor/symfony/console/Symfony/Component/Console/Output/StreamOutput.phpñ €†ÌOñ ¸¾RZ¶:vendor/symfony/console/Symfony/Component/Console/Shell.phpA€†ÌOA©‰h¶Mvendor/symfony/console/Symfony/Component/Console/Tester/ApplicationTester.phpb
€†ÌOb
OòPR¶Ivendor/symfony/console/Symfony/Component/Console/Tester/CommandTester.php3
€†ÌO3
ž`8¶Svendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Alias.phpü€†ÌOül5svendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php€†ÌO(arvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php€†ÌO?;Œá¶rvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.phpâ €†ÌOâ ñÒ†‹¶ƒvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php)€†ÌO)Ò<Ç9¶qvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CheckReferenceValidityPass.phpØ€†ÌO؀辶_vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/Compiler.phpˆ
€†ÌOˆ
F<>«°¶lvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CompilerPassInterface.phpþ€†ÌOþºPÕ¶svendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.phpm€†ÌOm­ØÛô¶gvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/LoggingFormatter.php°€†ÌO°!lð<6C>vvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.phpÌOï—^¸avendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/PassConfig.php¾€†ÌO¾eB¶tvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RemoveAbstractDefinitionsPass.php€†ÌO r<>ovendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RemovePrivateAliasesPass.phpó€†ÌOó®!ä?¶rvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.phpí
€†ÌOí
*öå·¶nvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RepeatablePassInterface.php¬€†ÌO¬4'.¶cvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RepeatedPass.php€†ÌO<00>ù6¶yvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php­€†ÌO­ZLuvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php†€†ÌO†}òëé¶svendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php´ €†ÌO´ zqÎŽ¶wvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.phpY€†ÌOYÎR¶uvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.phpP €†ÌOP <11>õlvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php®
€†ÌO®
ZSpvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphEdge.php퀆ÌOíx¼7Û¶pvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphNode.php"
€†ÌO"
\˜Wvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Container.php5€†ÌO5±¸cý¶\vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerAware.php`€†ÌO`ìÈ&p¶evendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerAwareInterface.php¶€†ÌO¶ Úeâ¶^vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php\€†ÌO\ å½²¶`vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerInterface.php† €†ÌO† .ƒqo¶Xvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Definition.phpÊ3€†ÌOÊ3<00>ox'¶avendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/DefinitionDecorator.php¾€†ÌO¾&%L#¶[vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/Dumper.php+€†ÌO+N/ì¶dvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/DumperInterface.phpÖ€†ÌOÖ6GY¶cvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php"€†ÌO"§Šq‡¶^vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/PhpDumper.phpF€†ÌOF¿ êl¶^vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/XmlDumper.phpv'€†ÌOv'«i_vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/YamlDumper.phpÝ€†ÌOÝû‰­¶jvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ExceptionInterface.phpÙ€†ÌOÙ`übD¶nvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/InactiveScopeException.php¶€†ÌO¶ìG pvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/InvalidArgumentException.php3€†ÌO3]IÖ¶{vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ParameterCircularReferenceException.phpu€†ÌOuœoš¶rvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.php(€†ÌO(˜gnI¶hvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/RuntimeException.phpÌOîº7†K¶wvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ScopeCrossingInjectionException.phpm€†ÌOm wvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ScopeWideningInjectionException.php_€†ÌO_¿›´¶yvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ServiceCircularReferenceException.phpÈ€†ÌOÈ‚ø¡¶pvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ServiceNotFoundException.phpK€†ÌOK¢°Ijvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.phpô€†ÌOô0m3ضQvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/LICENSE)€†ÌO)àýC+¶bvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/ClosureLoader.phpñ€†ÌOñÆ
¥_vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/FileLoader.php€†ÌO&¿3o¶bvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/IniFileLoader.phpÓ€†ÌOÓËx¶bvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php&€†ÌO&»«OO¶uvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsdw€†ÌOw <20>(=¶bvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.phplB€†ÌOlBB q¥¶cvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php\'€†ÌO\'Ⓠ¶Wvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Parameter.phpÿ€†ÌOÿ­‰F"¶mvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/FrozenParameterBag.php¾€†ÌO¾2<>$g¶gvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php €†ÌO ÖÍÙ«¶pvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/ParameterBagInterface.php/€†ÌO/;
|x¶Wvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Reference.php5€†ÌO5y&Ã(¶Svendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Scope.php`€†ÌO`nÒ÷¶\vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ScopeInterface.phpÿ€†ÌOÿPÐæ@¶^vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/SimpleXMLElement.php €†ÌO {<7B>z˶fvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/TaggedContainerInterface.php怆ÌO暸Ƃ¶Vvendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Variable.php7€†ÌO7$Kvendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php”€†ÌO”ßÆUvendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php"€†ÌO"£qö¶^vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.phps €†ÌOs F2Ÿ«¶^vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.phpY€†ÌOYû¼¶Ivendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/LICENSE)€†ÌO)àýC+¶Hvendor/symfony/finder/Symfony/Component/Finder/Comparator/Comparator.phpp€†ÌOpæ¿Lvendor/symfony/finder/Symfony/Component/Finder/Comparator/DateComparator.phpµ€†ÌOµ½Nvendor/symfony/finder/Symfony/Component/Finder/Comparator/NumberComparator.php €†ÌO ~ÿBɶ9vendor/symfony/finder/Symfony/Component/Finder/Finder.phpì4€†ÌOì4æ2Òú¶7vendor/symfony/finder/Symfony/Component/Finder/Glob.phpb €†ÌOb ØNk Pvendor/symfony/finder/Symfony/Component/Finder/Iterator/CustomFilterIterator.phpÙ€†ÌOÙOðýʶSvendor/symfony/finder/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.phpm€†ÌOm[ücK¶Tvendor/symfony/finder/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php|€†ÌO|ÑBƶZvendor/symfony/finder/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php€†ÌOÆ0 Rvendor/symfony/finder/Symfony/Component/Finder/Iterator/FilenameFilterIterator.phpÁ €†ÌOÁ §¡w¶Rvendor/symfony/finder/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php5€†ÌO5»'£×¶Vvendor/symfony/finder/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.phpY€†ÌOY¸¦›¶Svendor/symfony/finder/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php,€†ÌO,T5¤}¶Lvendor/symfony/finder/Symfony/Component/Finder/Iterator/SortableIterator.php>€†ÌO>š*f^¶6vendor/symfony/finder/Symfony/Component/Finder/LICENSE)€†ÌO)àýC+¶>vendor/symfony/finder/Symfony/Component/Finder/SplFileInfo.php€†ÌO̱›Ë¶Ovendor/symfony/translation/Symfony/Component/Translation/IdentityTranslator.phpŽ€†ÌOŽFYô¶Evendor/symfony/translation/Symfony/Component/Translation/Interval.php
€†ÌO
5t1
@vendor/symfony/translation/Symfony/Component/Translation/LICENSE)€†ÌO)àýC+¶Ovendor/symfony/translation/Symfony/Component/Translation/Loader/ArrayLoader.phpœ€†ÌOœR¤·¶Qvendor/symfony/translation/Symfony/Component/Translation/Loader/CsvFileLoader.php €†ÌO ? &Ó¶Svendor/symfony/translation/Symfony/Component/Translation/Loader/LoaderInterface.phpB€†ÌOB(é?¯¶Qvendor/symfony/translation/Symfony/Component/Translation/Loader/PhpFileLoader.php €†ÌO ½A䞶ovendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xliff-core-1.2-strict.xsd€†ÌOöxO¶]vendor/symfony/translation/Symfony/Component/Translation/Loader/schema/dic/xliff-core/xml.xsdš"€†ÌOš"›ÅåÒ¶Svendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.phpà €†ÌOà rƒ8¶Rvendor/symfony/translation/Symfony/Component/Translation/Loader/YamlFileLoader.php¤€†ÌO¤Ç€ë¶Mvendor/symfony/translation/Symfony/Component/Translation/MessageCatalogue.phpÏ€†ÌOÏ3öç¶Vvendor/symfony/translation/Symfony/Component/Translation/MessageCatalogueInterface.phpL€†ÌOL<66>ù¶Lvendor/symfony/translation/Symfony/Component/Translation/MessageSelector.phpy
€†ÌOy
E,p¯¶Ovendor/symfony/translation/Symfony/Component/Translation/PluralizationRules.phpb€†ÌOb,¥DݶGvendor/symfony/translation/Symfony/Component/Translation/Translator.php¨€†ÌO¨gGA¶Pvendor/symfony/translation/Symfony/Component/Translation/TranslatorInterface.phpÇ€†ÌOÇÌÕ¶5vendor/symfony/yaml/Symfony/Component/Yaml/Dumper.php4€†ÌO4'šqu¶6vendor/symfony/yaml/Symfony/Component/Yaml/Escaper.php] €†ÌO] ¹zå ¶Fvendor/symfony/yaml/Symfony/Component/Yaml/Exception/DumpException.phpñ€†ÌOñÇÄxC¶Kvendor/symfony/yaml/Symfony/Component/Yaml/Exception/ExceptionInterface.phpÆ€†ÌOÆî+­Gvendor/symfony/yaml/Symfony/Component/Yaml/Exception/ParseException.phpX €†ÌOX ˜33¶5vendor/symfony/yaml/Symfony/Component/Yaml/Inline.phpN2€†ÌON28;ø´¶2vendor/symfony/yaml/Symfony/Component/Yaml/LICENSE)€†ÌO)àýC+¶5vendor/symfony/yaml/Symfony/Component/Yaml/Parser.phpUM€†ÌOUMº(ëy¶8vendor/symfony/yaml/Symfony/Component/Yaml/Unescaper.phpš€†ÌOšm Á¶3vendor/symfony/yaml/Symfony/Component/Yaml/Yaml.phpV
€†ÌOV
fs«W¶LICENSE=€†ÌO=£²2i18n.php{'€†ÌO{'M8ݶ<?php
namespace Behat\Behat\Annotation;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Context\SubcontextableContextInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat annotation class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class Annotation implements AnnotationInterface
{
private $closure;
private $callback;
private $path;
private $description;
/**
* Constructs annotation.
*
* @param callback $callback
*
* @throws \InvalidArgumentException
*/
public function __construct($callback)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf(
'Annotation callback should be a valid callable, but %s given',
gettype($callback)
));
}
$this->closure = !is_array($callback);
if (!$this->isClosure()) {
$this->path = $callback[0] . '::' . $callback[1] . '()';
} else {
$reflection = new \ReflectionFunction($callback);
$this->path = $reflection->getFileName() . ':' . $reflection->getStartLine();
}
$this->callback = $callback;
}
/**
* Sets annotation description.
*
* @param string $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* Returns description.
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Returns path string for callback.
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Checks whether callback is closure.
*
* @return Boolean
*/
public function isClosure()
{
return $this->closure;
}
/**
* Returns callback.
*
* @return callback
*/
public function getCallback()
{
return $this->callback;
}
/**
* Returns callback, mapped to specific context (or it's subcontext) instance.
*
* @param ContextInterface $context
*
* @return callback
*
* @throws \RuntimeException
*/
public function getCallbackForContext(ContextInterface $context)
{
$callback = $this->getCallback();
if (!$this->isClosure()) {
if ($callback[0] === get_class($context)) {
$callback = array($context, $callback[1]);
} elseif ($context instanceof SubcontextableContextInterface) {
$subcontext = $context->getSubcontextByClassName($callback[0]);
if (null === $subcontext) {
throw new \RuntimeException(sprintf(
'"%s" subcontext instance not found in context "%s".'."\n".
'Looks like something is wrong with getSubcontextByClassName() method in one of your contexts',
$callback[0], get_class($context)
));
}
$reflection = new \ReflectionClass($subcontext);
if (!$reflection->hasMethod($callback[1])) {
throw new \RuntimeException(sprintf(
'Subcontext "%s" does not have "%s()" method.'."\n".
'Looks like something is wrong with getSubcontextByClassName() method in one of your contexts',
get_class($subcontext), $callback[1]
));
}
$callback = array($subcontext, $callback[1]);
}
}
return $callback;
}
/**
* Returns callback reflection.
*
* @return \ReflectionFunction
*/
public function getCallbackReflection()
{
if (!$this->isClosure()) {
return new \ReflectionMethod($this->callback[0], $this->callback[1]);
} else {
return new \ReflectionFunction($this->callback);
}
}
}
<?php
namespace Behat\Behat\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat annotation interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface AnnotationInterface
{
/**
* Returns path string for callback.
*
* @return string
*/
public function getPath();
/**
* Checks whether callback is closure.
*
* @return Boolean
*/
public function isClosure();
/**
* Returns callback.
*
* @return callback
*/
public function getCallback();
/**
* Returns callback reflection.
*
* @return \ReflectionFunction
*/
public function getCallbackReflection();
}
<?php
namespace Behat\Behat\ClassLoader;
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A class loader that uses a mapping file to look up paths.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class MapFileClassLoader
{
private $map = array();
/**
* Constructor.
*
* @param string $file Path to class mapping file
*/
public function __construct($file)
{
$this->map = require $file;
}
/**
* Registers this instance as an autoloader.
*
* @param Boolean $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
*/
public function loadClass($class)
{
if ('\\' === $class[0]) {
$class = substr($class, 1);
}
if (isset($this->map[$class])) {
require $this->map[$class];
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|null The path, if found
*/
public function findFile($class)
{
if ('\\' === $class[0]) {
$class = substr($class, 1);
}
if (isset($this->map[$class])) {
return $this->map[$class];
}
}
}
<?php
namespace Behat\Behat\Compiler;
use Symfony\Component\Finder\Finder;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Class loader map file compiler.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class PearMapFileCompiler
{
/**
* Behat lib directory.
*
* @var string
*/
private $libPath;
/**
* Initializes compiler.
*/
public function __construct()
{
$this->libPath = realpath(__DIR__ . '/../../../../');
}
/**
* Compiles map file and autoloader.
*
* @param string $version
*/
public function compile($autoloaderFilename = 'autoload.php', $mapFilename = 'autoload_map.php')
{
if (file_exists($mapFilename)) {
unlink($mapFilename);
}
$mappings = '';
$mappings .= $this->generateMappingFor(
$this->libPath.'/src',
"__DIR__ . '/src/'"
);
$mappings .= $this->generateMappingFor(
$this->libPath.'/vendor/behat/gherkin/src',
"'gherkin/src/'"
);
$mappings .= "\nif (!defined('BEHAT_AUTOLOAD_SF2') || true === BEHAT_AUTOLOAD_SF2) {\n";
$mappings .= $this->generateMappingFor(
array(
$this->libPath.'/vendor/symfony/config',
$this->libPath.'/vendor/symfony/console',
$this->libPath.'/vendor/symfony/dependency-injection',
$this->libPath.'/vendor/symfony/event-dispatcher',
$this->libPath.'/vendor/symfony/finder',
$this->libPath.'/vendor/symfony/translation',
$this->libPath.'/vendor/symfony/yaml',
)
);
$mappings .= "}\n";
$mapContent = <<<MAP_FILE
<?php
\$mappings = array();
$mappings
return \$mappings;
MAP_FILE;
file_put_contents($mapFilename, $mapContent);
file_put_contents($autoloaderFilename, $this->getAutoloadScript($mapFilename));
}
/**
* Generates mapping for specific path(s).
*
* @param mixed $paths single path or array of paths
* @param string|null $prefixCode path prefix code
*
* @return strings
*/
protected function generateMappingFor($paths, $prefixCode = null)
{
$mappings = '';
foreach ((array) $paths as $path) {
$trim = $path.'/';
foreach ($this->findPhpFile()->in($path) as $file) {
$path = str_replace($trim, '', $file->getRealPath());
$class = str_replace(array('/', '.php'), array('\\', ''), $path);
if (null !== $prefixCode) {
$mappings .= "\$mappings['{$class}'] = {$prefixCode} . '{$path}';\n";
} else {
$mappings .= "\$mappings['{$class}'] = '{$path}';\n";
}
}
}
return $mappings;
}
/**
* Returns autoload.php content.
*
* @param string $mapFilename
*
* @return string
*/
protected function getAutoloadScript($mapFilename)
{
return sprintf(<<<'EOF'
<?php
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (!class_exists('Behat\Behat\ClassLoader\MapFileClassLoader')) {
require_once __DIR__ . '/src/Behat/Behat/ClassLoader/MapFileClassLoader.php';
}
use Behat\Behat\ClassLoader\MapFileClassLoader;
$loader = new MapFileClassLoader(__DIR__ . '/%s');
$loader->register();
EOF
, $mapFilename);
}
/**
* Creates finder instance to search php files.
*
* @return Symfony\Component\Finder\Finder
*/
private function findPhpFile()
{
$finder = new Finder();
return $finder->files()->ignoreVCS(true)->name('*.php');
}
}
<?php
namespace Behat\Behat\Console;
use Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Console\Application,
Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Input\InputDefinition,
Symfony\Component\Console\Input\InputOption,
Symfony\Component\Console\Output\OutputInterface;
use Behat\Behat\DependencyInjection\BehatExtension,
Behat\Behat\DependencyInjection\Configuration\Loader;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat console application.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BehatApplication extends Application
{
private $basePath;
/**
* {@inheritdoc}
*/
public function __construct($version)
{
parent::__construct('Behat', $version);
}
/**
* {@inheritdoc}
*/
public function getDefinition()
{
return new InputDefinition(array(
new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message.'),
new InputOption('--verbose', '-v', InputOption::VALUE_NONE, 'Increase verbosity of exceptions.'),
new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this behat version.'),
new InputOption('--config', '-c', InputOption::VALUE_REQUIRED, 'Specify config file to use.'),
new InputOption('--profile', '-p', InputOption::VALUE_REQUIRED, 'Specify config profile to use.')
));
}
/**
* Runs the current application.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return integer 0 if everything went fine, or an error code
*/
public function doRun(InputInterface $input, OutputInterface $output)
{
$this->add($this->createCommand($input));
return parent::doRun($input, $output);
}
/**
* Creates main command for application.
*
* @param InputInterface $input
*
* @return Command
*/
protected function createCommand(InputInterface $input)
{
return $this->createContainer($input)->get('behat.console.command');
}
/**
* Creates container instance, loads extensions and freezes it.
*
* @param InputInterface $input
*
* @return ContainerInterface
*/
protected function createContainer(InputInterface $input)
{
$container = new ContainerBuilder();
$this->loadCoreExtension($container, $this->loadConfiguration($container, $input));
$container->compile();
return $container;
}
/**
* Configures container based on providen config file and profile.
*
* @param ContainerBuilder $container
* @param InputInterface $input
*/
protected function loadConfiguration(ContainerBuilder $container, InputInterface $input)
{
// locate paths
$this->basePath = getcwd();
if ($configPath = $this->getConfigurationFilePath($input)) {
$this->basePath = realpath(dirname($configPath));
}
// read configuration
$loader = new Loader($configPath);
$profile = $input->getParameterOption(array('--profile', '-p')) ?: 'default';
return $loader->loadConfiguration($profile);
}
/**
* Finds configuration file and returns path to it.
*
* @param InputInterface $input
*
* @return string
*/
protected function getConfigurationFilePath(InputInterface $input)
{
// custom configuration file
if ($file = $input->getParameterOption(array('--config', '-c'))) {
if (is_file($file)) {
return $file;
}
return;
}
// predefined config paths
$cwd = rtrim(getcwd(), DIRECTORY_SEPARATOR);
foreach (array_filter(array(
$cwd.DIRECTORY_SEPARATOR.'behat.yml',
$cwd.DIRECTORY_SEPARATOR.'behat.yml.dist',
$cwd.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'behat.yml',
$cwd.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'behat.yml.dist',
), 'is_file') as $path) {
return $path;
}
}
/**
* Loads core extension into container.
*
* @param ContainerBuilder $container
* @param $array $configs
*/
protected function loadCoreExtension(ContainerBuilder $container, array $configs)
{
if (null === $this->basePath) {
throw new RuntimeException(
'Suite basepath is not set. Seems you have forgot to load configuration first.'
);
}
$extension = new BehatExtension($this->basePath);
$extension->load($configs, $container);
$container->addObjectResource($extension);
}
/**
* {@inheritdoc}
*/
protected function getCommandName(InputInterface $input)
{
return 'behat';
}
/**
* {@inheritdoc}
*/
protected function getTerminalWidth()
{
return PHP_INT_MAX;
}
}
<?php
namespace Behat\Behat\Console\Command;
use Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Output\OutputInterface;
use Behat\Behat\Console\Processor\ProcessorInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Base behat console command.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class BaseCommand extends Command
{
private $processor;
/**
* Returns service container instance.
*
* @return ContainerInterface
*/
abstract protected function getContainer();
/**
* Sets command processor.
*
* @param ProcessorInterface $processor
*
* @return Command
*/
protected function setProcessor(ProcessorInterface $processor)
{
$this->processor = $processor;
$this->processor->configure($this);
return $this;
}
/**
* {@inheritdoc}
*/
protected function initialize(InputInterface $input, OutputInterface $output)
{
$this->processor->process($input, $output);
}
}
<?php
namespace Behat\Behat\Console\Command;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Output\OutputInterface;
use Behat\Gherkin\Gherkin;
use Behat\Behat\Console\Input\InputDefinition,
Behat\Behat\Console\Processor\ProcessorInterface,
Behat\Behat\Event\SuiteEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat console command.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BehatCommand extends BaseCommand
{
private $container;
private $featuresPaths;
private $strict = true;
private $dryRun = false;
/**
* Initializes command.
*
* @param ContainerInterface $container
* @param ProcessorInterface $processor
*/
public function __construct(ContainerInterface $container, ProcessorInterface $processor)
{
parent::__construct('behat');
$this->container = $container;
$this->setDefinition(new InputDefinition);
$this->setProcessor($processor);
}
/**
* Sets features/scenarios paths to run.
*
* @param array $paths
*/
public function setFeaturesPaths(array $paths)
{
$this->featuresPaths = $paths;
}
/**
* Returns paths to the features of current suite (basepath).
*
* @return array
*/
public function getFeaturesPaths()
{
return $this->featuresPaths;
}
/**
* Sets runner to be strict.
*
* @param Boolean $strict
*/
public function setStrict($strict = true)
{
$this->strict = (bool) $strict;
}
/**
* Checks whether runner is strict.
*
* @return Boolean
*/
public function isStrict()
{
return $this->strict;
}
/**
* Sets suite to dry-run mode (skip all steps).
*
* @param Boolean $dryRun
*/
public function setDryRun($dryRun = true)
{
$this->dryRun = (bool) $dryRun;
}
/**
* Checks whether runner is in dry-run mode.
*
* @return Boolean
*/
public function isDryRun()
{
return $this->dryRun;
}
/**
* Returns container instance.
*
* @return ContainerInterface
*/
protected function getContainer()
{
return $this->container;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$gherkin = $this->getContainer()->get('gherkin');
$this->beforeSuite();
$this->runFeatures($gherkin);
$this->afterSuite();
return $this->getCliReturnCode();
}
/**
* Parses and runs provided features.
*
* @param Gherkin $gherkin gherkin parser/loader
*/
protected function runFeatures(Gherkin $gherkin)
{
foreach ($this->getFeaturesPaths() as $path) {
// parse every feature with Gherkin
$features = $gherkin->load((string) $path);
// and run it in FeatureTester
foreach ($features as $feature) {
$tester = $this->getContainer()->get('behat.tester.feature');
$tester->setDryRun($this->isDryRun());
$feature->accept($tester);
}
}
}
/**
* Returns CLI code for finished suite.
*
* @return integer
*/
protected function getCliReturnCode()
{
$logger = $this->getContainer()->get('behat.logger');
if ($this->isStrict()) {
return intval(0 < $logger->getSuiteResult());
}
return intval(4 === $logger->getSuiteResult());
}
/**
* Fire beforeSuite event.
*/
protected function beforeSuite()
{
$dispatcher = $this->getContainer()->get('behat.event_dispatcher');
$logger = $this->getContainer()->get('behat.logger');
$parameters = $this->getContainer()->get('behat.context.dispatcher')->getContextParameters();
$dispatcher->dispatch('beforeSuite', new SuiteEvent($logger, $parameters, false));
// catch app interruption
if (function_exists('pcntl_signal')) {
declare(ticks = 1);
pcntl_signal(SIGINT, function() use($dispatcher, $parameters, $logger) {
$dispatcher->dispatch('afterSuite', new SuiteEvent($logger, $parameters, false));
exit(1);
});
}
}
/**
* Fire afterSuite event.
*/
protected function afterSuite()
{
$dispatcher = $this->getContainer()->get('behat.event_dispatcher');
$logger = $this->getContainer()->get('behat.logger');
$parameters = $this->getContainer()->get('behat.context.dispatcher')->getContextParameters();
$dispatcher->dispatch('afterSuite', new SuiteEvent($logger, $parameters, true));
}
}
<?php
namespace Behat\Behat\Console\Formatter;
use Symfony\Component\Console\Formatter\OutputFormatter as BaseOutputFormatter,
Symfony\Component\Console\Formatter\OutputFormatterStyle;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat console output formatter.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class OutputFormatter extends BaseOutputFormatter
{
/**
* {@inheritdoc}
*/
public function __construct($decorated = null, array $styles = array())
{
parent::__construct($decorated, array_merge(array(
'undefined' => new OutputFormatterStyle('yellow'),
'pending' => new OutputFormatterStyle('yellow'),
'pending_param' => new OutputFormatterStyle('yellow', null, array('bold')),
'failed' => new OutputFormatterStyle('red'),
'failed_param' => new OutputFormatterStyle('red', null, array('bold')),
'passed' => new OutputFormatterStyle('green'),
'passed_param' => new OutputFormatterStyle('green', null, array('bold')),
'skipped' => new OutputFormatterStyle('cyan'),
'skipped_param' => new OutputFormatterStyle('cyan', null, array('bold')),
'comment' => new OutputFormatterStyle('black'),
'tag' => new OutputFormatterStyle('cyan')
), $styles));
}
/**
* Formats a message according to the given styles.
*
* @param string $message The message to style
*
* @return string The styled message
*/
public function format($message)
{
return preg_replace_callback(
'/{\+([a-z-_]+)}(.*?){\-\\1}/si', array($this, 'replaceStyle'), $message
);
}
/**
* Replaces style of the output.
*
* @param array $match
*
* @return string The replaced style
*/
private function replaceStyle($match)
{
if (!$this->isDecorated()) {
return $match[2];
}
if ($this->hasStyle($match[1])) {
$style = $this->getStyle($match[1]);
} else {
return $match[0];
}
return $style->apply($match[2]);
}
}
<?php
namespace Behat\Behat\Console\Input;
use Symfony\Component\Console\Input\InputDefinition as BaseDefinition;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Extended InputDefinition, which supports switchers.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class InputDefinition extends BaseDefinition
{
/**
* Gets the synopsis.
*
* @return string The synopsis
*/
public function getSynopsis()
{
$elements = array();
$isSwitch = false;
$options = $this->getOptions();
foreach ($options as $option) {
if ($isSwitch) {
$isSwitch = false;
continue;
}
// if switch
if (array_key_exists('no-'.$option->getName(), $options)) {
$elements[] = sprintf('[--[no-]%s]', $option->getName());
$isSwitch = true;
} else {
$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
$elements[] = sprintf('['.($option->isValueRequired() ? '%s--%s="..."' : ($option->isValueOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName());
}
}
foreach ($this->getArguments() as $argument) {
$elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
if ($argument->isArray()) {
$elements[] = sprintf('... [%sN]', $argument->getName());
}
}
return implode(' ', $elements);
}
/**
* Returns a textual representation of the InputDefinition.
*
* @return string A string representing the InputDefinition
*/
public function asText()
{
// find the largest option or argument name
$max = 0;
foreach ($this->getOptions() as $option) {
$nameLength = strlen($option->getName()) + 2;
if ($option->getShortcut()) {
$nameLength += strlen($option->getShortcut()) + 3;
}
if ($this->hasOption('no-'.$option->getName())) {
$nameLength += 5;
}
$max = max($max, $nameLength);
}
foreach ($this->getArguments() as $argument) {
$max = max($max, strlen($argument->getName()));
}
++$max;
$text = array();
if ($this->getArguments()) {
$text[] = '<comment>Arguments:</comment>';
foreach ($this->getArguments() as $argument) {
if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
$default = sprintf('<comment> (default: %s)</comment>', $this->subformatDefaultValue($argument->getDefault()));
} else {
$default = '';
}
$description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $argument->getDescription());
$text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $description, $default);
}
$text[] = '';
}
if ($this->getOptions()) {
$text[] = '<comment>Options:</comment>';
$isSwitch = false;
$options = $this->getOptions();
foreach ($options as $option) {
if ($isSwitch) {
$isSwitch = false;
continue;
}
if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) {
$default = sprintf('<comment> (default: %s)</comment>', $this->subformatDefaultValue($option->getDefault()));
} else {
$default = '';
}
if ($this->hasOption('no-'.$option->getName())) {
$isSwitch = true;
}
$multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
$description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $option->getDescription());
$optionMax = $max - strlen($option->getName()) - 2;
if ($isSwitch) {
$optionMax -= 5;
}
$text[] = sprintf(" <info>%s</info> %-${optionMax}s%s%s%s",
'--'.( $isSwitch ? '[no-]' : '' ) . $option->getName(),
$option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '',
$description,
$default,
$multiple
);
}
$text[] = '';
}
return implode("\n", $text);
}
private function subformatDefaultValue($default)
{
if (is_array($default) && $default === array_values($default)) {
return sprintf("array('%s')", implode("', '", $default));
}
return str_replace("\n", '', var_export($default, true));
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Output\OutputInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Processors manager.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AggregateProcessor implements ProcessorInterface
{
private $processors = array();
/**
* Adds processor to the manager.
*
* @param ProcessorInterface $processor Processor instance
*/
public function addProcessor(ProcessorInterface $processor)
{
$this->processors[] = $processor;
}
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command)
{
foreach ($this->processors as $processor) {
$processor->configure($command);
}
}
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*/
public function process(InputInterface $input, OutputInterface $output)
{
foreach ($this->processors as $processor) {
$processor->process($input, $output);
}
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Input\InputOption,
Symfony\Component\Console\Output\OutputInterface;
use Behat\Gherkin\Filter\NameFilter,
Behat\Gherkin\Filter\TagFilter,
Behat\Gherkin\Cache\FileCache;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Context reader processor.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ContextReaderProcessor extends Processor
{
/**
* Constructs processor.
*
* @param ContainerInterface $container Container instance
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*/
public function process(InputInterface $input, OutputInterface $output)
{
$this->container->get('behat.context.reader')->read();
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Input\InputOption,
Symfony\Component\Console\Output\OutputInterface;
use Behat\Behat\Formatter\FormatterManager,
Behat\Behat\Formatter\FormatterDispatcher;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Format processor.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FormatProcessor extends Processor
{
private $container;
/**
* Constructs processor.
*
* @param ContainerInterface $container Container instance
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command)
{
$formatDispatchers = $this->container->get('behat.formatter.manager')->getDispatchers();
$command
->addOption('--format', '-f', InputOption::VALUE_REQUIRED,
"How to format features. <comment>pretty</comment> is default.\n" .
"Default formatters are:\n" .
implode("\n",
array_map(function($dispatcher) {
$comment = '- <comment>'.$dispatcher->getName().'</comment>: ';
if ($dispatcher->getDescription()) {
$comment .= $dispatcher->getDescription();
} else {
$comment .= $dispatcher->getClass();
}
return $comment;
}, $formatDispatchers)
) . "\n" .
"Can use multiple formats at once (splitted with \"<comment>,</comment>\")"
)
->addOption('--out', null, InputOption::VALUE_REQUIRED,
"Write formatter output to a file/directory\n" .
"instead of STDOUT <comment>(output_path)</comment>."
)
->addOption('--lang', null, InputOption::VALUE_REQUIRED,
'Print formatter output in particular language.'
)
// --[no-]ansi
->addOption('--ansi', null, InputOption::VALUE_NONE,
"Whether or not to use ANSI color in the output.\n".
"Behat decides based on your platform and the output\n".
"destination if not specified."
)
->addOption('--no-ansi', null, InputOption::VALUE_NONE)
// --[no-]time
->addOption('--time', null, InputOption::VALUE_NONE,
"Whether or not to show timer in output."
)
->addOption('--no-time', null, InputOption::VALUE_NONE)
// --[no-]paths
->addOption('--paths', null, InputOption::VALUE_NONE,
"Whether or not to print sources paths."
)
->addOption('--no-paths', null, InputOption::VALUE_NONE)
// --[no-]snippets
->addOption('--snippets', null, InputOption::VALUE_NONE,
"Whether or not to print snippets for undefined steps."
)
->addOption('--no-snippets', null, InputOption::VALUE_NONE)
// --[no-]snippets-paths
->addOption('--snippets-paths', null, InputOption::VALUE_NONE,
"Whether or not to print details about undefined steps\n".
"in their snippets."
)
->addOption('--no-snippets-paths', null, InputOption::VALUE_NONE)
// --[no-]multiline
->addOption('--multiline', null, InputOption::VALUE_NONE,
"Whether or not to print multiline arguments for steps."
)
->addOption('--no-multiline', null, InputOption::VALUE_NONE)
// --[no-]expand
->addOption('--expand', null, InputOption::VALUE_NONE,
"Whether or not to expand scenario outline examples\n".
"tables.\n"
)
->addOption('--no-expand', null, InputOption::VALUE_NONE)
;
}
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*/
public function process(InputInterface $input, OutputInterface $output)
{
$manager = $this->container->get('behat.formatter.manager');
$formats = array_map('trim', explode(',',
$input->getOption('format') ?: $this->container->getParameter('behat.formatter.name')
));
$this->loadFormatterTranslations();
$this->loadCustomFormatters($manager);
$this->initFormatters($manager, $formats);
$this->configureFormatters($manager, $input, $output);
$this->initMultipleOutputs($manager, $input);
}
/**
* Loads formatter translations from behat.paths.i18n parameter file.
*/
protected function loadFormatterTranslations()
{
if (!is_file($i18nFile = $this->container->getParameter('behat.paths.i18n'))) {
return;
}
$translator = $this->container->get('behat.translator');
foreach (require($i18nFile) as $lang => $messages) {
$translator->addResource('array', $messages, $lang, 'behat');
}
}
/**
* Loads custom formatters, defined in behat.yml.
*
* @param FormatterManager $manager
*/
protected function loadCustomFormatters(FormatterManager $manager)
{
foreach ($this->container->getParameter('behat.formatter.classes') as $name => $class) {
$manager->addDispatcher(new FormatterDispatcher($name, $class));
}
}
/**
* Inits formatters.
*
* @param FormatterManager $manager
* @param $array $formats
*/
protected function initFormatters(FormatterManager $manager, array $formats)
{
foreach ($formats as $format) {
$manager->initFormatter($format);
}
}
/**
* Configures formatters based on container, input and output configurations.
*
* @param FormatterManager $manager
* @param InputInterface $input
* @param OutputInterface $output
*/
protected function configureFormatters(FormatterManager $manager, InputInterface $input,
OutputInterface $output)
{
$parameters = $this->container->getParameter('behat.formatter.parameters');
foreach ($parameters as $name => $value) {
if ('output_path' === $name) {
continue;
}
$manager->setFormattersParameter($name, $value);
}
$manager->setFormattersParameter('base_path',
$this->container->getParameter('behat.paths.base')
);
$manager->setFormattersParameter('support_path',
$this->container->getParameter('behat.paths.bootstrap')
);
$manager->setFormattersParameter('decorated',
$output->isDecorated()
);
if ($input->getOption('verbose')) {
$manager->setFormattersParameter('verbose', true);
}
if ($input->getOption('lang')) {
$manager->setFormattersParameter('language', $input->getOption('lang'));
}
if (null !== $ansi = $this->getSwitchValue($input, 'ansi')) {
$output->setDecorated($ansi);
$manager->setFormattersParameter('decorated', $ansi);
}
if (null !== $time = $this->getSwitchValue($input, 'time')) {
$manager->setFormattersParameter('time', $time);
}
if (null !== $snippets = $this->getSwitchValue($input, 'snippets')) {
$manager->setFormattersParameter('snippets', $snippets);
}
if (null !== $snippetsPaths = $this->getSwitchValue($input, 'snippets-paths')) {
$manager->setFormattersParameter('snippets_paths', $snippetsPaths);
}
if (null !== $paths = $this->getSwitchValue($input, 'paths')) {
$manager->setFormattersParameter('paths', $paths);
}
if (null !== $expand = $this->getSwitchValue($input, 'expand')) {
$manager->setFormattersParameter('expand', $expand);
}
if (null !== $multiline = $this->getSwitchValue($input, 'multiline')) {
$manager->setFormattersParameter('multiline_arguments', $multiline);
}
}
/**
* Initializes multiple formatters with different outputs.
*
* @param FormatterManager $manager
* @param InputInterface $input
*/
protected function initMultipleOutputs(FormatterManager $manager, InputInterface $input)
{
if ($input->getOption('out')) {
$outputs = $input->getOption('out');
} elseif (isset($parameters['output_path'])) {
$outputs = $parameters['output_path'];
} else {
return;
}
if (false === strpos($outputs, ',')) {
$outputPath = $this->locateOutputPath($outputs);
$manager->setFormattersParameter('output_path', $outputPath);
$manager->setFormattersParameter('decorated', (bool) $this->getSwitchValue($input, 'ansi'));
return;
}
foreach (array_map('trim', explode(',', $outputs)) as $i => $out) {
if (!$out || 'null' === $out || 'false' === $out) {
continue;
}
$outputPath = $this->locateOutputPath($out);
$formatters = $manager->getFormatters();
if (isset($formatters[$i])) {
$formatters[$i]->setParameter('output_path', $outputPath);
$formatters[$i]->setParameter('decorated', (bool) $this->getSwitchValue($input, 'ansi'));
}
}
}
/**
* Locates output path from relative one.
*
* @param string $out
*
* @return string
*/
private function locateOutputPath($out)
{
$out = $this->container->getParameter('behat.paths.base').DIRECTORY_SEPARATOR.$out;
if (!file_exists($out)) {
touch($out);
$out = realpath($out);
unlink($out);
} else {
$out = realpath($out);
}
return $out;
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Input\InputOption,
Symfony\Component\Console\Output\OutputInterface;
use Behat\Gherkin\Filter\NameFilter,
Behat\Gherkin\Filter\TagFilter,
Behat\Gherkin\Cache\FileCache;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Gherkin processor.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class GherkinProcessor extends Processor
{
private $container;
/**
* Constructs processor.
*
* @param ContainerInterface $container Container instance
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command)
{
$command
->addOption('--name', null, InputOption::VALUE_REQUIRED,
"Only execute the feature elements which match\n" .
"part of the given name or regex."
)
->addOption('--tags', null, InputOption::VALUE_REQUIRED,
"Only execute the features or scenarios with tags\n" .
"matching tag filter expression.\n"
)
->addOption('--cache', null, InputOption::VALUE_REQUIRED,
"Cache parsed features into specified path."
)
;
}
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*/
public function process(InputInterface $input, OutputInterface $output)
{
$gherkinParser = $this->container->get('gherkin');
$name = $input->getOption('name')
?: $this->container->getParameter('gherkin.filters.name');
if ($name) {
$gherkinParser->addFilter(new NameFilter($name));
}
$tags = $input->getOption('tags')
?: $this->container->getParameter('gherkin.filters.tags');
if ($tags) {
$gherkinParser->addFilter(new TagFilter($tags));
}
$path = $input->getOption('cache')
?: $this->container->getParameter('behat.options.cache');
if ($path) {
$cache = new FileCache($path);
$this->container->get('gherkin.loader.gherkin_file')->setCache($cache);
}
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Input\InputOption,
Symfony\Component\Console\Output\OutputInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Help (story-syntax and definition printers) processor.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class HelpProcessor extends Processor
{
private $container;
/**
* Constructs processor.
*
* @param ContainerInterface $container Container instance
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command)
{
$command
->addOption('--story-syntax', null, InputOption::VALUE_NONE,
"Print <comment>*.feature</comment> example.\n" .
"Use <info>--lang</info> to see specific language."
)
->addOption('--definitions', '-d', InputOption::VALUE_REQUIRED,
"Print all available step definitions:\n" .
"- use <info>-dl</info> to just list definition expressions.\n" .
"- use <info>-di</info> to show definitions with extended info.\n" .
"- use <info>-d 'needle'</info> to find specific definitions.\n" .
"Use <info>--lang</info> to see definitions in specific language.\n"
)
;
}
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*/
public function process(InputInterface $input, OutputInterface $output)
{
if ($input->getOption('story-syntax')) {
$this->container->get('behat.help_printer.story_syntax')->printSyntax(
$output, $input->getOption('lang') ?: 'en'
);
exit(0);
}
if ($type = $input->getOption('definitions')) {
if ('l' === $type) {
$short = true;
$search = null;
} elseif ('i' === $type) {
$short = false;
$search = null;
} else {
$short = false;
$search = $type;
}
$this->container->get('behat.help_printer.definitions')->printDefinitions(
$output, $search, $input->getOption('lang') ?: 'en', $short
);
exit(0);
}
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Input\InputOption,
Symfony\Component\Console\Output\OutputInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Init operation processor.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class InitProcessor extends Processor
{
private $container;
/**
* Constructs processor.
*
* @param ContainerInterface $container Container instance
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command)
{
$command->addOption('--init', null, InputOption::VALUE_NONE,
"Create <comment>features</comment> directory structure.\n"
);
}
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*/
public function process(InputInterface $input, OutputInterface $output)
{
if ($input->getOption('init')) {
$this->initFeaturesDirectoryStructure($output);
exit(0);
}
}
/**
* Creates features path structure (initializes behat tests structure).
*
* @param OutputInterface $output output console
*/
protected function initFeaturesDirectoryStructure(OutputInterface $output)
{
$basePath = $this->container->getParameter('behat.paths.base').DIRECTORY_SEPARATOR;
$featuresPath = $this->container->getParameter('behat.paths.features');
$bootstrapPath = $this->container->getParameter('behat.paths.bootstrap');
if (!is_dir($featuresPath)) {
mkdir($featuresPath, 0777, true);
$output->writeln(
'<info>+d</info> ' .
str_replace($basePath, '', realpath($featuresPath)) .
' <comment>- place your *.feature files here</comment>'
);
}
if (!is_dir($bootstrapPath)) {
mkdir($bootstrapPath, 0777, true);
$output->writeln(
'<info>+d</info> ' .
str_replace($basePath, '', realpath($bootstrapPath)) .
' <comment>- place bootstrap scripts and static files here</comment>'
);
file_put_contents(
$bootstrapPath.DIRECTORY_SEPARATOR.'FeatureContext.php',
$this->getFeatureContextSkelet()
);
$output->writeln(
'<info>+f</info> ' .
str_replace($basePath, '', realpath($bootstrapPath)).DIRECTORY_SEPARATOR.
'FeatureContext.php <comment>- place your feature related code here</comment>'
);
}
}
/**
* Returns feature context skelet.
*
* @return string
*/
protected function getFeatureContextSkelet()
{
return <<<'PHP'
<?php
use Behat\Behat\Context\ClosuredContextInterface,
Behat\Behat\Context\TranslatedContextInterface,
Behat\Behat\Context\BehatContext,
Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
//
// Require 3rd-party libraries here:
//
// require_once 'PHPUnit/Autoload.php';
// require_once 'PHPUnit/Framework/Assert/Functions.php';
//
/**
* Features context.
*/
class FeatureContext extends BehatContext
{
/**
* Initializes context.
* Every scenario gets it's own context object.
*
* @param array $parameters context parameters (set them up through behat.yml)
*/
public function __construct(array $parameters)
{
// Initialize your context here
}
//
// Place your definition and hook methods here:
//
// /**
// * @Given /^I have done something with "([^"]*)"$/
// */
// public function iHaveDoneSomethingWith($argument)
// {
// doSomethingWith($argument);
// }
//
}
PHP;
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Finder\Finder,
Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputArgument,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Output\OutputInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Path locator processor.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class LocatorProcessor extends Processor
{
private $container;
/**
* Constructs processor.
*
* @param ContainerInterface $container Container instance
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command)
{
$command->addArgument('features', InputArgument::OPTIONAL,
"Feature(s) to run. Could be:\n" .
"- a dir <comment>(features/)</comment>\n" .
"- a feature <comment>(*.feature)</comment>\n" .
"- a scenario at specific line <comment>(*.feature:10)</comment>.\n" .
"- all scenarios at or after a specific line <comment>(*.feature:10-*)</comment>.\n" .
"- all scenarios at a line within a specific range <comment>(*.feature:10-20)</comment>."
);
}
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @throws \InvalidArgumentException
*/
public function process(InputInterface $input, OutputInterface $output)
{
$this->container->get('behat.console.command')->setFeaturesPaths(
array($input->getArgument('features'))
);
if (is_dir($bootstrapPath = $this->container->getParameter('behat.paths.bootstrap'))) {
$this->loadBootstrapScripts($bootstrapPath);
}
}
/**
* Requires *.php scripts from bootstrap/ folder.
*
* @param string $path
*/
protected function loadBootstrapScripts($path)
{
$iterator = Finder::create()
->files()
->name('*.php')
->sortByName()
->in($path)
;
foreach ($iterator as $file) {
require_once((string) $file);
}
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Abstract base processor.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class Processor implements ProcessorInterface
{
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command)
{
}
/**
* Returns correct value for input switch.
*
* @param InputInterface $input
* @param string $name
*
* @return Boolean|null
*/
protected function getSwitchValue(InputInterface $input, $name)
{
if ($input->getOption($name)) {
return true;
}
if ($input->getOption('no-'.$name)) {
return false;
}
return null;
}
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Output\OutputInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat console processor interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ProcessorInterface
{
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command);
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*/
public function process(InputInterface $input, OutputInterface $output);
}
<?php
namespace Behat\Behat\Console\Processor;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\Console\Command\Command,
Symfony\Component\Console\Input\InputInterface,
Symfony\Component\Console\Input\InputOption,
Symfony\Component\Console\Output\OutputInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* command configuration processor.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class RunProcessor extends Processor
{
private $container;
/**
* Constructs processor.
*
* @param ContainerInterface $container Container instance
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Configures command to be able to process it later.
*
* @param Command $command
*/
public function configure(Command $command)
{
$command
->addOption('--strict', null, InputOption::VALUE_NONE,
'Fail if there are any undefined or pending steps.'
)
->addOption('--dry-run', null, InputOption::VALUE_NONE,
'Invokes formatters without executing the steps & hooks.'
)
->addOption('--rerun', null, InputOption::VALUE_REQUIRED,
"Save list of failed scenarios into new file\n" .
"or use existing file to run only scenarios from it."
)
->addOption('--append-snippets', null, InputOption::VALUE_NONE,
"Appends snippets for undefined steps into main context."
)
;
}
/**
* Processes data from container and console input.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @throws \RuntimeException
*/
public function process(InputInterface $input, OutputInterface $output)
{
$command = $this->container->get('behat.console.command');
$hookDispatcher = $this->container->get('behat.hook.dispatcher');
$command->setStrict(
$input->getOption('strict') || $this->container->getParameter('behat.options.strict')
);
$command->setDryRun(
$input->getOption('dry-run') || $this->container->getParameter('behat.options.dry_run')
);
$hookDispatcher->setDryRun(
$input->getOption('dry-run') || $this->container->getParameter('behat.options.dry_run')
);
if ($file = $input->getOption('rerun') ?: $this->container->getParameter('behat.options.rerun')) {
if (file_exists($file)) {
$command->setFeaturesPaths(explode("\n", trim(file_get_contents($file))));
}
$this->container->get('behat.formatter.manager')
->initFormatter('failed')
->setParameter('output_path', $file);
}
if ($input->getOption('append-snippets') || $this->container->getParameter('behat.options.append_snippets')) {
$this->initializeSnippetsAppender();
}
}
/**
* Appends snippets to the main context after suite run.
*/
protected function initializeSnippetsAppender()
{
$contextRefl = new \ReflectionClass(
$this->container->get('behat.context.dispatcher')->getContextClass()
);
if ($contextRefl->implementsInterface('Behat\Behat\Context\ClosuredContextInterface')) {
throw new \RuntimeException(
'--append-snippets doesn\'t support closured contexts'
);
}
$formatManager = $this->container->get('behat.formatter.manager');
$formatManager->setFormattersParameter('snippets', false);
$formatter = $formatManager->initFormatter('snippets');
$formatter->setParameter('decorated', false);
$formatter->setParameter('output_decorate', false);
$formatter->setParameter('output', $snippets = fopen('php://memory', 'rw'));
$this->container->get('behat.event_dispatcher')
->addListener('afterSuite', function() use($contextRefl, $snippets) {
rewind($snippets);
$snippets = stream_get_contents($snippets);
if (trim($snippets)) {
$snippets = strtr($snippets, array('\\' => '\\\\', '$' => '\\$'));
$context = file_get_contents($contextRefl->getFileName());
$context = preg_replace('/}[ \n]*$/', rtrim($snippets)."\n}\n", $context);
file_put_contents($contextRefl->getFileName(), $context);
}
}, -5);
}
}
<?php
namespace Behat\Behat\Context;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat basic context implementation.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BehatContext implements ExtendedContextInterface
{
private $subcontexts = array();
private $parentContext;
/**
* Adds subcontext to current context.
*
* @param string $alias
* @param ExtendedContextInterface $context
*/
public function useContext($alias, ExtendedContextInterface $context)
{
$context->setParentContext($this);
$this->subcontexts[$alias] = $context;
}
/**
* Sets parent context of current context.
*
* @param ExtendedContextInterface $parentContext
*/
public function setParentContext(ExtendedContextInterface $parentContext)
{
$this->parentContext = $parentContext;
}
/**
* Returns main context.
*
* @return ExtendedContextInterface
*/
public function getMainContext()
{
if (null !== $this->parentContext) {
return $this->parentContext->getMainContext();
}
return $this;
}
/**
* Find current context's subcontext by alias name.
*
* @param string $alias
*
* @return ExtendedContextInterface
*/
public function getSubcontext($alias)
{
// search in current context subcontexts
if (isset($this->subcontexts[$alias])) {
return $this->subcontexts[$alias];
}
// search in subcontexts childs contexts
foreach ($this->subcontexts as $subcontext) {
if (null !== $context = $subcontext->getSubcontext($alias)) {
return $context;
}
}
}
/**
* Returns all added subcontexts.
*
* @return array
*/
public function getSubcontexts()
{
return $this->subcontexts;
}
/**
* Finds subcontext by it's name.
*
* @param string $className
*
* @return ContextInterface
*/
public function getSubcontextByClassName($className)
{
foreach ($this->getSubcontexts() as $subcontext) {
if (get_class($subcontext) === $className) {
return $subcontext;
}
if ($context = $subcontext->getSubcontextByClassName($className)) {
return $context;
}
}
}
/**
* Prints beautified debug string.
*
* @param string $string debug string
*/
public function printDebug($string)
{
echo "\n\033[36m| " . strtr($string, array("\n" => "\n| ")) . "\033[0m\n\n";
}
}
<?php
namespace Behat\Behat\Context\ClassGuesser;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Context class guesser interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ClassGuesserInterface
{
/**
* Tries to guess context classname.
*
* @return string|null
*/
public function guess();
}
<?php
namespace Behat\Behat\Context\ClassGuesser;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Predefined context class guesser.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class PredefinedClassGuesser implements ClassGuesserInterface
{
private $classname;
/**
* Initializes guesser.
*
* @param string $classname
*/
public function __construct($classname)
{
$this->classname = $classname;
}
/**
* Tries to guess context classname.
*
* @return string|null
*/
public function guess()
{
return class_exists($this->classname) ? $this->classname : null;
}
}
<?php
namespace Behat\Behat\Context;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Closured context interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ClosuredContextInterface extends ContextInterface
{
/**
* Returns array of step definition files (*.php).
*
* @return array
*/
public function getStepDefinitionResources();
/**
* Returns array of hook definition files (*.php).
*
* @return array
*/
public function getHookDefinitionResources();
}
<?php
namespace Behat\Behat\Context;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Context dispatcher.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ContextDispatcher
{
private $classGuessers = array();
private $initializers = array();
private $parameters = array();
/**
* Initialize dispatcher.
*
* @param array $parameters context parameters
*/
public function __construct(array $parameters = array())
{
$this->parameters = $parameters;
}
/**
* Adds context class guesser to the dispatcher.
*
* @param ClassGuesser\ClassGuesserInterface $guesser
*/
public function addClassGuesser(ClassGuesser\ClassGuesserInterface $guesser)
{
$this->classGuessers[] = $guesser;
}
/**
* Adds context initializer to the dispatcher.
*
* @param Initializer\InitializerInterface $initializer
*/
public function addInitializer(Initializer\InitializerInterface $initializer)
{
$this->initializers[] = $initializer;
}
/**
* Returns context classname.
*
* @return string
*/
public function getContextClass()
{
$classname = null;
foreach ($this->classGuessers as $guesser) {
if ($classname = $guesser->guess()) {
break;
}
}
if (null === $classname) {
throw new \RuntimeException(sprintf('Context class not found.'));
}
if (!class_exists($classname)) {
throw new \RuntimeException(sprintf('Context class "%s" not found', $classname));
}
$contextClassRefl = new \ReflectionClass($classname);
if (!$contextClassRefl->implementsInterface('Behat\Behat\Context\ContextInterface')) {
throw new \RuntimeException(sprintf(
'Context class "%s" should implement ContextInterface', $classname
));
}
return $classname;
}
/**
* Returns context parameters.
*
* @return array
*/
public function getContextParameters()
{
return $this->parameters;
}
/**
* Creates new context instance.
*
* @return ContextInterface
*
* @throws \RuntimeException
*/
public function createContext()
{
$classname = $this->getContextClass();
$parameters = $this->getContextParameters();
$context = new $classname($parameters);
$this->initializeContext($context);
return $context;
}
/**
* Initializes context with registered initializers.
*
* @param ContextInterface $context
*/
private function initializeContext(ContextInterface $context)
{
foreach ($this->initializers as $initializer) {
if ($initializer->supports($context)) {
$initializer->initialize($context);
}
}
// if context has subcontexts - initialize them too
if ($context instanceof SubcontextableContextInterface) {
foreach ($context->getSubcontexts() as $subcontext) {
$this->initializeContext($subcontext);
}
}
}
}
<?php
namespace Behat\Behat\Context;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Context interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ContextInterface
{
}
<?php
namespace Behat\Behat\Context;
use Behat\Behat\Definition\DefinitionDispatcher,
Behat\Behat\Hook\HookDispatcher;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Context reader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ContextReader
{
private $contextDispatcher;
private $loaders = array();
/**
* Initializes context reader.
*
* @param ContextDispatcher $contextDispatcher
*/
public function __construct(ContextDispatcher $contextDispatcher)
{
$this->contextDispatcher = $contextDispatcher;
}
/**
* Adds context loader to the list of available loaders.
*
* @param Loader\LoaderInterface $loader
*/
public function addLoader(Loader\LoaderInterface $loader)
{
$this->loaders[] = $loader;
}
/**
* Reads all definition data from main context.
*/
public function read()
{
$this->readFromContext($this->contextDispatcher->createContext());
}
/**
* Reads definition data from specific context class.
*
* @param ContextInterface $context
*/
private function readFromContext(ContextInterface $context)
{
foreach ($this->loaders as $loader) {
if ($loader->supports($context)) {
$loader->load($context);
}
}
if ($context instanceof SubcontextableContextInterface) {
foreach ($context->getSubcontexts() as $subcontext) {
$this->readFromContext($subcontext);
}
}
}
}
<?php
namespace Behat\Behat\Context;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Extended context interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ExtendedContextInterface extends SubcontextableContextInterface
{
/**
* Sets parent context of current context.
*
* @param ExtendedContextInterface $parentContext
*/
public function setParentContext(ExtendedContextInterface $parentContext);
/**
* Returns main context.
*
* @return ExtendedContextInterface
*/
public function getMainContext();
/**
* Find current context's subcontext by alias name.
*
* @param string $alias
*
* @return ExtendedContextInterface
*/
public function getSubcontext($alias);
}
<?php
namespace Behat\Behat\Context\Initializer;
use Behat\Behat\Context\ContextInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Context initializer interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface InitializerInterface
{
/**
* Checks if initializer supports provided context.
*
* @param ContextInterface $context
*
* @return Boolean
*/
public function supports(ContextInterface $context);
/**
* Initializes provided context.
*
* @param ContextInterface $context
*/
public function initialize(ContextInterface $context);
}
<?php
namespace Behat\Behat\Context\Loader;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Definition\DefinitionDispatcher,
Behat\Behat\Definition\DefinitionInterface,
Behat\Behat\Definition\TransformationInterface,
Behat\Behat\Hook\HookDispatcher,
Behat\Behat\Hook\HookInterface,
Behat\Behat\Annotation\AnnotationInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Annotated contexts reader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AnnotatedLoader implements LoaderInterface
{
private $definitionDispatcher;
private $hookDispatcher;
private $annotationClasses = array(
'given' => 'Behat\Behat\Definition\Annotation\Given',
'when' => 'Behat\Behat\Definition\Annotation\When',
'then' => 'Behat\Behat\Definition\Annotation\Then',
'transform' => 'Behat\Behat\Definition\Annotation\Transformation',
'beforesuite' => 'Behat\Behat\Hook\Annotation\BeforeSuite',
'aftersuite' => 'Behat\Behat\Hook\Annotation\AfterSuite',
'beforefeature' => 'Behat\Behat\Hook\Annotation\BeforeFeature',
'afterfeature' => 'Behat\Behat\Hook\Annotation\AfterFeature',
'beforescenario' => 'Behat\Behat\Hook\Annotation\BeforeScenario',
'afterscenario' => 'Behat\Behat\Hook\Annotation\AfterScenario',
'beforestep' => 'Behat\Behat\Hook\Annotation\BeforeStep',
'afterstep' => 'Behat\Behat\Hook\Annotation\AfterStep'
);
private $availableAnnotations;
/**
* Initializes context loader.
*
* @param DefinitionDispatcher $definitionDispatcher
* @param HookDispatcher $hookDispatcher
*/
public function __construct(DefinitionDispatcher $definitionDispatcher, HookDispatcher $hookDispatcher)
{
$this->definitionDispatcher = $definitionDispatcher;
$this->hookDispatcher = $hookDispatcher;
$this->availableAnnotations = implode("|", array_keys($this->annotationClasses));
}
/**
* Checks if loader supports provided context.
*
* @param ContextInterface $context
*
* @return Boolean
*/
public function supports(ContextInterface $context)
{
return true;
}
/**
* Loads definitions and translations from provided context.
*
* @param ContextInterface $context
*/
public function load(ContextInterface $context)
{
$reflection = new \ReflectionObject($context);
foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $methodRefl) {
foreach ($this->readMethodAnnotations($reflection->getName(), $methodRefl) as $annotation) {
if ($annotation instanceof DefinitionInterface) {
$this->definitionDispatcher->addDefinition($annotation);
} elseif ($annotation instanceof TransformationInterface) {
$this->definitionDispatcher->addTransformation($annotation);
} elseif ($annotation instanceof HookInterface) {
$this->hookDispatcher->addHook($annotation);
}
}
}
}
/**
* Reads all supported method annotations.
*
* @param stirng $className
* @param \ReflectionMethod $method
*
* @return array
*/
private function readMethodAnnotations($className, \ReflectionMethod $method)
{
$annotations = array();
// read parent annotations
try {
$prototype = $method->getPrototype();
$annotations = array_merge($annotations, $this->readMethodAnnotations($className, $prototype));
} catch (\ReflectionException $e) {}
// read method annotations
if ($docBlock = $method->getDocComment()) {
$description = null;
foreach (explode("\n", $docBlock) as $docLine) {
$docLine = preg_replace('/^\/\*\*\s*|^\s*\*\s*|\s*\*\/$|\s*$/', '', $docLine);
if (preg_match('/^\@('.$this->availableAnnotations.')\s*(.*)?$/i', $docLine, $matches)) {
$class = $this->annotationClasses[strtolower($matches[1])];
$callback = array($className, $method->getName());
if (isset($matches[2]) && !empty($matches[2])) {
$annotation = new $class($callback, $matches[2]);
} else {
$annotation = new $class($callback);
}
if (null !== $description) {
$annotation->setDescription($description);
}
$annotations[] = $annotation;
} elseif (null === $description && '' !== $docLine && false === strpos($docLine, '@')) {
$description = $docLine;
}
}
}
return $annotations;
}
}
<?php
namespace Behat\Behat\Context\Loader;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Context\ClosuredContextInterface,
Behat\Behat\Definition\Loader\ClosuredDefinitionLoader,
Behat\Behat\Hook\Loader\ClosuredHookLoader;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Closured contexts reader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ClosuredLoader implements LoaderInterface
{
private $definitionLoader;
private $hookLoader;
/**
* Initializes context loader.
*
* @param ClosuredDefinitionLoader $definitionLoader
* @param ClosuredHookLoader $hookLoader
*/
public function __construct(ClosuredDefinitionLoader $definitionLoader, ClosuredHookLoader $hookLoader)
{
$this->definitionLoader = $definitionLoader;
$this->hookLoader = $hookLoader;
}
/**
* Checks if loader supports provided context.
*
* @param ContextInterface $context
*
* @return Boolean
*/
public function supports(ContextInterface $context)
{
return $context instanceof ClosuredContextInterface;
}
/**
* Loads definitions and translations from provided context.
*
* @param ContextInterface $context
*/
public function load(ContextInterface $context)
{
foreach ($context->getStepDefinitionResources() as $path) {
$this->definitionLoader->load($path);
}
foreach ($context->getHookDefinitionResources() as $path) {
$this->hookLoader->load($path);
}
}
}
<?php
namespace Behat\Behat\Context\Loader;
use Behat\Behat\Context\ContextInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Context loader interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface LoaderInterface
{
/**
* Checks if loader supports provided context.
*
* @param ContextInterface $context
*
* @return Boolean
*/
public function supports(ContextInterface $context);
/**
* Loads definitions and translations from provided context.
*
* @param ContextInterface $context
*/
public function load(ContextInterface $context);
}
<?php
namespace Behat\Behat\Context\Loader;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Context\TranslatedContextInterface;
use Symfony\Component\Translation\TranslatorInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Translated contexts reader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class TranslatedLoader implements LoaderInterface
{
private $translator;
/**
* Initializes context loader.
*
* @param TranslatorInterface $translator
*/
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
/**
* Checks if loader supports provided context.
*
* @param ContextInterface $context
*
* @return Boolean
*/
public function supports(ContextInterface $context)
{
return $context instanceof TranslatedContextInterface;
}
/**
* Loads definitions and translations from provided context.
*
* @param ContextInterface $context
*
* @throws \InvalidArgumentException
*/
public function load(ContextInterface $context)
{
foreach ($context->getTranslationResources() as $path) {
$extension = pathinfo($path, PATHINFO_EXTENSION);
if ('yml' === $extension) {
$this->translator->addResource(
'yaml', $path, basename($path, '.yml'), 'behat.definitions'
);
} elseif ('xliff' === $extension) {
$this->translator->addResource(
'xliff', $path, basename($path, '.xliff'), 'behat.definitions'
);
} elseif ('php' === $extension) {
$this->translator->addResource(
'php', $path, basename($path, '.php'), 'behat.definitions'
);
} else {
throw new \InvalidArgumentException(sprintf(
'Can not read definitions translations from file "%s". File is not supported',
$path
));
}
}
}
}
<?php
namespace Behat\Behat\Context\Step;
use Behat\Gherkin\Node\StepNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Given substep.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Given implements SubstepInterface
{
private $node;
/**
* Initializes Given substep.
*/
public function __construct()
{
$arguments = func_get_args();
$text = array_shift($arguments);
$node = new StepNode('Given', $text);
$node->setArguments($arguments);
$this->node = $node;
}
/**
* Returns substep node.
*
* @return StepNode
*/
public function getStepNode()
{
return $this->node;
}
}
<?php
namespace Behat\Behat\Context\Step;
use Behat\Gherkin\Node\StepNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Substep interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface SubstepInterface
{
/**
* Returns substep node.
*
* @return StepNode
*/
public function getStepNode();
}
<?php
namespace Behat\Behat\Context\Step;
use Behat\Gherkin\Node\StepNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Then substep.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Then implements SubstepInterface
{
private $node;
/**
* Initializes Then substep.
*/
public function __construct()
{
$arguments = func_get_args();
$text = array_shift($arguments);
$node = new StepNode('Then', $text);
$node->setArguments($arguments);
$this->node = $node;
}
/**
* Returns substep node.
*
* @return StepNode
*/
public function getStepNode()
{
return $this->node;
}
}
<?php
namespace Behat\Behat\Context\Step;
use Behat\Gherkin\Node\StepNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* When substep.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class When implements SubstepInterface
{
private $node;
/**
* Initializes When substep.
*/
public function __construct()
{
$arguments = func_get_args();
$text = array_shift($arguments);
$node = new StepNode('When', $text);
$node->setArguments($arguments);
$this->node = $node;
}
/**
* Returns substep node.
*
* @return StepNode
*/
public function getStepNode()
{
return $this->node;
}
}
<?php
namespace Behat\Behat\Context;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Context interface with subcontexts support.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface SubcontextableContextInterface extends ContextInterface
{
/**
* Returns all added subcontexts.
*
* @return array
*/
public function getSubcontexts();
/**
* Finds subcontext by it's name.
*
* @param string $className
*
* @return ContextInterface
*/
public function getSubcontextByClassName($className);
}
<?php
namespace Behat\Behat\Context;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Translated context interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface TranslatedContextInterface extends ContextInterface
{
/**
* Returns array of i18n XLIFF files paths.
*
* @return array
*/
public function getTranslationResources();
}
<?php
namespace Behat\Behat\DataCollector;
use Symfony\Component\EventDispatcher\EventDispatcher,
Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Behat\Behat\Event\FeatureEvent,
Behat\Behat\Event\SuiteEvent,
Behat\Behat\Event\ScenarioEvent,
Behat\Behat\Event\OutlineExampleEvent,
Behat\Behat\Event\StepEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat run logger.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class LoggerDataCollector implements EventSubscriberInterface
{
private $startTime;
private $finishTime;
private $statuses = array(
StepEvent::PASSED => 'passed',
StepEvent::SKIPPED => 'skipped',
StepEvent::PENDING => 'pending',
StepEvent::UNDEFINED => 'undefined',
StepEvent::FAILED => 'failed'
);
private $suiteResult = 0;
private $featuresCount = 0;
private $featuresStatuses = array();
private $scenariosCount = 0;
private $scenariosStatuses = array();
private $stepsCount = 0;
private $stepsStatuses = array();
private $definitionsSnippets = array();
private $failedStepsEvents = array();
private $pendingStepsEvents = array();
/**
* Initializes logger.
*/
public function __construct()
{
$this->featuresStatuses = array_combine(
array_values($this->statuses),
array_fill(0, count($this->statuses), 0)
);
$this->scenariosStatuses = array_combine(
array_values($this->statuses),
array_fill(0, count($this->statuses), 0)
);
$this->stepsStatuses = array_combine(
array_values($this->statuses),
array_fill(0, count($this->statuses), 0)
);
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
$events = array(
'beforeSuite', 'afterSuite', 'afterFeature', 'afterScenario', 'afterOutlineExample',
'afterStep'
);
return array_combine($events, $events);
}
/**
* Listens to "suite.before" event.
*
* @param SuiteEvent $event
*
* @uses startTimer()
*/
public function beforeSuite(SuiteEvent $event)
{
$this->startTimer();
}
/**
* Listens to "suite.after" event.
*
* @param SuiteEvent $event
*
* @uses finishTimer()
*/
public function afterSuite(SuiteEvent $event)
{
$this->finishTimer();
}
/**
* Listens to "feature.after" event.
*
* @param FeatureEvent $event
*
* @uses collectFeatureResult()
*/
public function afterFeature(FeatureEvent $event)
{
$this->collectFeatureResult($event->getResult());
}
/**
* Listens to "scenario.after" event.
*
* @param ScenarioEvent $event
*
* @uses collectScenarioResult()
*/
public function afterScenario(ScenarioEvent $event)
{
$this->collectScenarioResult($event->getResult());
}
/**
* Listens to "outline.example.after" event.
*
* @param OutlineExampleEvent $event
*
* @uses collectScenarioResult()
*/
public function afterOutlineExample(OutlineExampleEvent $event)
{
$this->collectScenarioResult($event->getResult());
}
/**
* Listens to "step.after" event.
*
* @param StepEvent $event
*
* @uses collectStepStats()
*/
public function afterStep(StepEvent $event)
{
$this->collectStepStats($event);
}
/**
* Returns suite total execution time.
*
* @return float miliseconds
*/
public function getTotalTime()
{
return $this->finishTime - $this->startTime;
}
/**
* Returns overall suites result.
*
* @return integer
*/
public function getSuiteResult()
{
return $this->suiteResult;
}
/**
* Returns overall features count.
*
* @return integer
*/
public function getFeaturesCount()
{
return $this->featuresCount;
}
/**
* Returns hash of features statuses count.
*
* @return array hash (ex: passed => 10, failed => 2)
*/
public function getFeaturesStatuses()
{
return $this->featuresStatuses;
}
/**
* Returns overall scenarios count.
*
* @return integer
*/
public function getScenariosCount()
{
return $this->scenariosCount;
}
/**
* Returns hash of scenarios statuses count.
*
* @return array hash (ex: passed => 10, failed => 2)
*/
public function getScenariosStatuses()
{
return $this->scenariosStatuses;
}
/**
* Returns overall steps count.
*
* @return integer
*/
public function getStepsCount()
{
return $this->stepsCount;
}
/**
* Returns hash of steps statuses count.
*
* @return array hash (ex: passed => 10, failed => 2)
*/
public function getStepsStatuses()
{
return $this->stepsStatuses;
}
/**
* Returns hash of definition snippets for undefined steps.
*
* @return array hash with md5 as key and snippet as value
*/
public function getDefinitionsSnippets()
{
return $this->definitionsSnippets;
}
/**
* Returns array of failed steps events.
*
* @return array
*/
public function getFailedStepsEvents()
{
return $this->failedStepsEvents;
}
/**
* Returns array of pending steps events;
*
* @return array
*/
public function getPendingStepsEvents()
{
return $this->pendingStepsEvents;
}
/**
* Starts suite timer.
*/
private function startTimer()
{
$this->startTime = microtime(true);
}
/**
* Stops suite timer.
*/
private function finishTimer()
{
$this->finishTime = microtime(true);
}
/**
* Collects feature result status.
*
* @param integer $result status code
*/
private function collectFeatureResult($result)
{
++$this->featuresCount;
++$this->featuresStatuses[$this->statuses[$result]];
$this->suiteResult = max($this->suiteResult, $result);
}
/**
* Collects scenario result status.
*
* @param integer $result status code
*/
private function collectScenarioResult($result)
{
++$this->scenariosCount;
++$this->scenariosStatuses[$this->statuses[$result]];
}
/**
* Collects step statistics.
*
* @param StepEvent $event
*/
private function collectStepStats(StepEvent $event)
{
++$this->stepsCount;
++$this->stepsStatuses[$this->statuses[$event->getResult()]];
switch ($event->getResult()) {
case StepEvent::UNDEFINED:
$hash = $event->getSnippet()->getHash();
if (!isset($this->definitionsSnippets[$hash])) {
$this->definitionsSnippets[$hash] = $event->getSnippet();
} else {
$this->definitionsSnippets[$hash]->addStep($event->getSnippet()->getLastStep());
}
break;
case StepEvent::FAILED:
$this->failedStepsEvents[] = $event;
break;
case StepEvent::PENDING:
$this->pendingStepsEvents[] = $event;
break;
}
}
}
<?php
namespace Behat\Behat\Definition\Annotation;
use Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
use Behat\Behat\Definition\DefinitionInterface,
Behat\Behat\Exception\ErrorException,
Behat\Behat\Context\ContextInterface,
Behat\Behat\Annotation\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Step definition.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class Definition extends Annotation implements DefinitionInterface
{
private $regex;
private $matchedText;
private $values = array();
/**
* Initializes definition.
*
* @param callback $callback definition callback
* @param string $regex definition regular expression
*
* @throws \InvalidArgumentException
*/
public function __construct($callback, $regex)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf(
'"%s" definition callback should be a valid callable, but %s given',
basename(str_replace('\\', '/', get_class($this))), gettype($callback)
));
}
parent::__construct($callback);
$this->regex = $regex;
}
/**
* Returns definition regex to match.
*
* @return string
*/
public function getRegex()
{
return $this->regex;
}
/**
* Saves matched step text to definition.
*
* @param string $text
*/
public function setMatchedText($text)
{
$this->matchedText = $text;
}
/**
* Returns matched step text.
*
* @return string
*/
public function getMatchedText()
{
return $this->matchedText;
}
/**
* Sets step parameters for step run.
*
* @param array $values
*/
public function setValues(array $values)
{
$this->values = $values;
}
/**
* Returns step parameters for step run.
*
* @return array
*/
public function getValues()
{
return $this->values;
}
/**
* Custom error handler.
*
* This method used as custom error handler when step is running.
*
* @see set_error_handler()
*
* @param integer $level
* @param string $message
* @param string $file
* @param integer $line
*
* @return Boolean
*
* @throws ErrorException
*/
public function errorHandler($level, $message, $file, $line)
{
if (0 !== error_reporting()) {
throw new ErrorException($level, $message, $file, $line);
}
// error reporting turned off or more likely suppressed with @
return false;
}
/**
* Runs definition callback.
*
* @param ContextInterface $context
*
* @return mixed
*
* @throws BehaviorException
*/
public function run(ContextInterface $context)
{
if (defined('BEHAT_ERROR_REPORTING')) {
$errorLevel = BEHAT_ERROR_REPORTING;
} else {
$errorLevel = E_ALL ^ E_WARNING;
}
$oldHandler = set_error_handler(array($this, 'errorHandler'), $errorLevel);
$callback = $this->getCallbackForContext($context);
$values = $this->getValues();
if ($this->isClosure()) {
array_unshift($values, $context);
}
$return = call_user_func_array($callback, $values);
if (null !== $oldHandler) {
set_error_handler($oldHandler);
}
return $return;
}
}
<?php
namespace Behat\Behat\Definition\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Given type step definition.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Given extends Definition
{
/**
* Returns definition type (Given|When|Then).
*
* @return string
*/
public function getType()
{
return 'Given';
}
}
<?php
namespace Behat\Behat\Definition\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Then type step definition.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Then extends Definition
{
/**
* Returns definition type (Given|When|Then).
*
* @return string
*/
public function getType()
{
return 'Then';
}
}
<?php
namespace Behat\Behat\Definition\Annotation;
use Behat\Gherkin\Node\TableNode;
use Behat\Behat\Definition\TransformationInterface,
Behat\Behat\Context\ContextInterface,
Behat\Behat\Annotation\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Step arguments transformation.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Transformation extends Annotation implements TransformationInterface
{
private $regex;
/**
* Initializes transformation.
*
* @param callback $callback definition callback
* @param string $regex definition regular expression
*
* @throws \InvalidArgumentException
*/
public function __construct($callback, $regex)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf(
'Transformation callback should be a valid callable, but %s given',
gettype($callback)
));
}
parent::__construct($callback);
$this->regex = $regex;
}
/**
* Returns transformation regex.
*
* @return string
*/
public function getRegex()
{
return $this->regex;
}
/**
* Transforms provided argument.
*
* @param string $translatedRegex
* @param ContextInterface $context
* @param mixed $argument
*
* @return mixed
*/
public function transform($translatedRegex, ContextInterface $context, $argument)
{
$callback = $this->getCallbackForContext($context);
if ($argument instanceof TableNode) {
$tableMatching = 'table:' . implode(',', $argument->getRow(0));
if (preg_match($translatedRegex, $tableMatching)
|| preg_match($this->regex, $tableMatching)) {
return call_user_func($callback, $argument);
}
} elseif (is_string($argument) || $argument instanceof PyStringNode) {
if (preg_match($translatedRegex, (string) $argument, $transformArguments)
|| preg_match($this->regex, (string) $argument, $transformArguments)) {
array_shift($transformArguments);
return call_user_func_array($callback, $transformArguments);
}
}
}
}
<?php
namespace Behat\Behat\Definition\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* When type step definition.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class When extends Definition
{
/**
* Returns definition type (Given|When|Then).
*
* @return string
*/
public function getType()
{
return 'When';
}
}
<?php
namespace Behat\Behat\Definition;
use Symfony\Component\Translation\TranslatorInterface;
use Behat\Gherkin\Node\StepNode,
Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
use Behat\Behat\Definition\Proposal\DefinitionProposalDispatcher,
Behat\Behat\Exception\RedundantException,
Behat\Behat\Exception\AmbiguousException,
Behat\Behat\Exception\UndefinedException,
Behat\Behat\Context\ContextInterface,
Behat\Behat\Definition\DefinitionSnippet;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Definition dispatcher.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class DefinitionDispatcher
{
private $transformations = array();
private $definitions = array();
private $proposalDispatcher;
private $translator;
/**
* Initializes definition dispatcher.
*
* @param DefinitionProposalDispatcher $proposalDispatcher
* @param TranslatorInterface $translator
*/
public function __construct(DefinitionProposalDispatcher $proposalDispatcher, TranslatorInterface $translator)
{
$this->proposalDispatcher = $proposalDispatcher;
$this->translator = $translator;
}
/**
* Adds definition to dispatcher.
*
* @param DefinitionInterface $definition
*
* @throws RedundantException
*/
public function addDefinition(DefinitionInterface $definition)
{
$regex = $definition->getRegex();
if (isset($this->definitions[$regex])) {
throw new RedundantException($definition, $this->definitions[$regex]);
}
$this->definitions[$regex] = $definition;
}
/**
* Returns array of available definitions.
*
* @return array array of hashes => array(regex => definition)
*/
public function getDefinitions()
{
return $this->definitions;
}
/**
* Adds transformation to dispatcher.
*
* @param TransformationInterface $transformation
*/
public function addTransformation(TransformationInterface $transformation)
{
$this->transformations[] = $transformation;
}
/**
* Returns array of available transformations.
*
* @return array array of argument transformers
*/
public function getTransformations()
{
return $this->transformations;
}
/**
* Cleans dispatcher.
*/
public function clean()
{
$this->definitions = array();
$this->transformations = array();
}
/**
* Finds step definition, that match specified step.
*
* @param ContextInterface $context
* @param StepNode $step
*
* @return Definition
*
* @uses loadDefinitions()
*
* @throws AmbiguousException if step description is ambiguous
* @throws UndefinedException if step definition not found
*/
public function findDefinition(ContextInterface $context, StepNode $step)
{
$text = $step->getText();
$multiline = $step->getArguments();
$matches = array();
// find step to match
foreach ($this->getDefinitions() as $origRegex => $definition) {
$transRegex = $this->translateDefinitionRegex($origRegex, $step->getLanguage());
// if not regex really (string) - transform into it
if (0 !== strpos($origRegex, '/')) {
$origRegex = '/^'.preg_quote($origRegex, '/').'$/';
$transRegex = '/^'.preg_quote($transRegex, '/').'$/';
}
if (preg_match($origRegex, $text, $arguments)
|| ($origRegex !== $transRegex && preg_match($transRegex, $text, $arguments))) {
// prepare callback arguments
$arguments = $this->prepareCallbackArguments(
$context, $definition->getCallbackReflection(), array_slice($arguments, 1), $multiline
);
// transform arguments
foreach ($arguments as $num => $argument) {
foreach ($this->getTransformations() as $trans) {
$transRegex = $this->translateDefinitionRegex(
$trans->getRegex(), $step->getLanguage()
);
$newArgument = $trans->transform($transRegex, $context, $argument);
if (null !== $newArgument) {
$arguments[$num] = $newArgument;
}
}
}
// set matched definition
$definition->setMatchedText($text);
$definition->setValues($arguments);
$matches[] = $definition;
}
}
if (count($matches) > 1) {
throw new AmbiguousException($text, $matches);
}
if (0 === count($matches)) {
throw new UndefinedException($text);
}
return $matches[0];
}
/**
* Returns step definition for step node.
*
* @param ContextInterface $context
* @param StepNode $step
*
* @return DefinitionSnippet
*/
public function proposeDefinition(ContextInterface $context, StepNode $step)
{
return $this->proposalDispatcher->propose($context, $step);
}
/**
* Translates definition regex to provided language (if possible).
*
* @param string $regex regex to translate
* @param string $language language
*
* @return string
*/
public function translateDefinitionRegex($regex, $language)
{
return $this->translator->trans($regex, array(), 'behat.definitions', $language);
}
/**
* Merges found arguments with multiliners and maps them to the function callback signature.
*
* @param ContextInterface $context context instance
* @param \ReflectionFunctionAbstract $refl callback reflection
* @param array $arguments found arguments
* @param array $multiline multiline arguments of the step
*
* @return array
*/
private function prepareCallbackArguments(ContextInterface $context, \ReflectionFunctionAbstract $refl,
array $arguments, array $multiline)
{
$parametersRefl = $refl->getParameters();
if ($refl->isClosure()) {
array_shift($parametersRefl);
}
$resulting = array();
foreach ($parametersRefl as $num => $parameterRefl) {
if (isset($arguments[$parameterRefl->getName()])) {
$resulting[] = $arguments[$parameterRefl->getName()];
} elseif (isset($arguments[$num])) {
$resulting[] = $arguments[$num];
}
}
foreach ($multiline as $argument) {
$resulting[] = $argument;
}
return $resulting;
}
}
<?php
namespace Behat\Behat\Definition;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Exception\BehaviorException;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Step definition.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface DefinitionInterface
{
/**
* Returns definition type (Given|When|Then).
*
* @return string
*/
public function getType();
/**
* Runs definition callback.
*
* @param ContextInterface $context
*
* @return mixed
*
* @throws BehaviorException
*/
public function run(ContextInterface $context);
}
<?php
namespace Behat\Behat\Definition;
use Behat\Gherkin\Node\StepNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Definition snippet.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class DefinitionSnippet
{
private $type;
private $template;
private $steps = array();
/**
* Initializes definition snippet.
*
* @param StepNode $step Step interested in snippet
* @param string $template Definition snippet template
*/
public function __construct(StepNode $step, $template)
{
$type = $step->getType();
$this->type = in_array($type, array('Given', 'When', 'Then')) ? $type : 'Given';
$this->template = $template;
$this->steps[] = $step;
}
/**
* Adds step interested in this snippet.
*
* @param StepNode $step Step interested in snippet
*/
public function addStep(StepNode $step)
{
$this->steps[] = $step;
}
/**
* Returns last step in list of steps.
*
* @return StepNode
*/
public function getLastStep()
{
return end($this->steps);
}
/**
* Returns list of steps interested in this snippet.
*
* @return array
*/
public function getSteps()
{
return $this->steps;
}
/**
* Returns snippet unique hash (ignoring step type).
*
* @return string
*/
public function getHash()
{
return md5($this->template);
}
/**
* Returns definition snippet text.
*
* @return string
*/
public function getSnippet()
{
return sprintf($this->template, $this->type);
}
/**
* Returns definition snippet text.
*
* @return string
*/
public function __toString()
{
return $this->getSnippet();
}
}
<?php
namespace Behat\Behat\Definition\Loader;
use Behat\Gherkin\Node\StepNode;
use Behat\Behat\Definition\DefinitionDispatcher,
Behat\Behat\Definition\Annotation\Given,
Behat\Behat\Definition\Annotation\When,
Behat\Behat\Definition\Annotation\Then,
Behat\Behat\Definition\Annotation\Transformation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Closured step definitions loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ClosuredDefinitionLoader implements DefinitionLoaderInterface
{
private $dispatcher;
/**
* Initializes loader.
*
* @param DefinitionDispatcher $dispatcher
*/
public function __construct(DefinitionDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Loads definitions from provided resource.
*
* @param mixed $resource
*/
public function load($resource)
{
$steps = $this;
require($resource);
}
/**
* Defines argument transformation.
*
* @param string $regex transformation regex (to find specific argument)
* @param callback $callback transformation callback (must return transformed argument)
*/
public function Transform($regex, $callback)
{
$this->dispatcher->addTransformation(new Transformation($callback, $regex));
}
/**
* Defines a step with ->Given|When|Then|...('/regex/', callback) or
* call a step with ->Given|When|Then|...('I enter "12" in the field', $world) or
* even with arguments ->Given|When|Then|...('I fill up fields', $world, $table).
*
* @param string $type step type (Given|When|Then|...)
* @param string $arguments step regex & callback
*
* @return ClosuredDefinitionLoader
*
* @throws RedundantException if step definition is already exists
*/
public function __call($type, $arguments)
{
if (2 == count($arguments) && is_callable($arguments[1])) {
switch (strtolower($type)) {
case 'when':
$definition = new When($arguments[1], $arguments[0]);
break;
case 'then':
$definition = new Then($arguments[1], $arguments[0]);
break;
case 'given':
default:
$definition = new Given($arguments[1], $arguments[0]);
break;
}
$this->dispatcher->addDefinition($definition);
} else {
$text = array_shift($arguments);
$world = array_shift($arguments);
$step = new StepNode($type, $text);
$step->setArguments($arguments);
$definition = $this->dispatcher->findDefinition($world, $step);
$definition->run($world);
}
return $this;
}
}
<?php
namespace Behat\Behat\Definition\Loader;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Definition loader interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface DefinitionLoaderInterface
{
/**
* Loads definitions from provided resource.
*
* @param mixed $resource
*/
public function load($resource);
}
<?php
namespace Behat\Behat\Definition\Proposal;
use Behat\Gherkin\Node\StepNode,
Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Definition\DefinitionSnippet,
Behat\Behat\Util\Transliterator;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Annotated definitions proposal.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AnnotatedDefinitionProposal implements DefinitionProposalInterface
{
private static $proposedMethods = array();
/**
* Checks if loader supports provided context.
*
* @param ContextInterface $context
*
* @return Boolean
*/
public function supports(ContextInterface $context)
{
return true;
}
/**
* Loads definitions and translations from provided context.
*
* @param ContextInterface $context
* @param StepNode $step
*
* @return DefinitionSnippet
*/
public function propose(ContextInterface $context, StepNode $step)
{
$contextRefl = new \ReflectionObject($context);
$contextClass = $contextRefl->getName();
$replacePatterns = array(
"/(?<= |^)\\\'(?:((?!\\').)*)\\\'(?= |$)/", // Single quoted strings
'/(?<= |^)\"(?:[^\"]*)\"(?= |$)/', // Double quoted strings
'/(\d+)/', // Numbers
);
$text = $step->getText();
$text = preg_replace('/([\/\[\]\(\)\\\^\$\.\|\?\*\+\'])/', '\\\\$1', $text);
$regex = preg_replace(
$replacePatterns,
array(
"\\'([^\']*)\\'",
"\"([^\"]*)\"",
"(\\d+)",
),
$text
);
preg_match('/' . $regex . '/', $step->getText(), $matches);
$count = count($matches) - 1;
$methodName = preg_replace($replacePatterns, '', $text);
$methodName = Transliterator::transliterate($methodName, ' ');
$methodName = preg_replace('/[^a-zA-Z\_\ ]/', '', $methodName);
$methodName = str_replace(' ', '', ucwords($methodName));
if (0 !== strlen($methodName)) {
$methodName[0] = strtolower($methodName[0]);
} else {
$methodName = 'stepDefinition1';
}
// get method number from method name
$methodNumber = 2;
if (preg_match('/(\d+)$/', $methodName, $matches)) {
$methodNumber = intval($matches[1]);
}
// check that proposed method name isn't arelady defined in context
while ($contextRefl->hasMethod($methodName)) {
$methodName = preg_replace('/\d+$/', '', $methodName);
$methodName .= $methodNumber++;
}
// check that proposed method name haven't been proposed earlier
if (isset(self::$proposedMethods[$contextClass])) {
foreach (self::$proposedMethods[$contextClass] as $proposedRegex => $proposedMethod) {
if ($proposedRegex !== $regex) {
while ($proposedMethod === $methodName) {
$methodName = preg_replace('/\d+$/', '', $methodName);
$methodName .= $methodNumber++;
}
}
}
}
self::$proposedMethods[$contextClass][$regex] = $methodName;
$args = array();
for ($i = 0; $i < $count; $i++) {
$args[] = "\$arg" . ($i + 1);
}
foreach ($step->getArguments() as $argument) {
if ($argument instanceof PyStringNode) {
$args[] = "PyStringNode \$string";
} elseif ($argument instanceof TableNode) {
$args[] = "TableNode \$table";
}
}
$description = sprintf(<<<PHP
/**
* @%s /^%s$/
*/
public function %s(%s)
{
throw new PendingException();
}
PHP
, '%s', $regex, $methodName, implode(', ', $args)
);
return new DefinitionSnippet($step, $description);
}
}
<?php
namespace Behat\Behat\Definition\Proposal;
use Behat\Gherkin\Node\StepNode,
Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Context\ClosuredContextInterface,
Behat\Behat\Definition\DefinitionSnippet;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Closured definitions proposal.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ClosuredDefinitionProposal implements DefinitionProposalInterface
{
/**
* Checks if loader supports provided context.
*
* @param ContextInterface $context
*
* @return Boolean
*/
public function supports(ContextInterface $context)
{
return $context instanceof ClosuredContextInterface;
}
/**
* Loads definitions and translations from provided context.
*
* @param ContextInterface $context
* @param StepNode $step
*
* @return DefinitionSnippet
*/
public function propose(ContextInterface $context, StepNode $step)
{
$text = $step->getText();
$regex = preg_replace('/([\/\[\]\(\)\\\^\$\.\|\?\*\+\'])/', '\\\\$1', $text);
$regex = preg_replace(
array(
"/(?<= |^)\\\'(?:((?!\\').)*)\\\'(?= |$)/", // Single quoted strings
'/(?<= |^)\"(?:[^\"]*)\"(?= |$)/', // Double quoted strings
'/(\d+)/', // Numbers
),
array(
"\\'([^\']*)\\'",
"\"([^\"]*)\"",
"(\\d+)",
),
$regex
);
preg_match('/' . $regex . '/', $text, $matches);
$count = count($matches) - 1;
$args = array("\$world");
for ($i = 0; $i < $count; $i++) {
$args[] = "\$arg".($i + 1);
}
foreach ($step->getArguments() as $argument) {
if ($argument instanceof PyStringNode) {
$args[] = "\$string";
} elseif ($argument instanceof TableNode) {
$args[] = "\$table";
}
}
$description = sprintf(<<<PHP
\$steps->%s('/^%s$/', function(%s) {
throw new \Behat\Behat\Exception\PendingException();
});
PHP
, '%s', $regex, implode(', ', $args)
);
return new DefinitionSnippet($step, $description);
}
}
<?php
namespace Behat\Behat\Definition\Proposal;
use Behat\Gherkin\Node\StepNode;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Definition\DefinitionSnippet;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Definition proposals dispatcher.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class DefinitionProposalDispatcher
{
private $proposals = array();
/**
* Adds proposal object to the dispatcher.
*
* @param DefinitionProposalInterface $proposal
*/
public function addProposal(DefinitionProposalInterface $proposal)
{
$this->proposals[] = $proposal;
}
/**
* Returns step definition for step node.
*
* @param ContextInterface $context
* @param StepNode $step
*
* @return DefinitionSnippet
*/
public function propose(ContextInterface $context, StepNode $step)
{
foreach ($this->proposals as $proposal) {
if ($proposal->supports($context)) {
return $proposal->propose($context, $step);
}
}
}
}
<?php
namespace Behat\Behat\Definition\Proposal;
use Behat\Gherkin\Node\StepNode;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Definition\DefinitionSnippet;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Definition proposal interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface DefinitionProposalInterface
{
/**
* Checks if loader supports provided context.
*
* @param ContextInterface $context
*
* @return Boolean
*/
public function supports(ContextInterface $context);
/**
* Loads definitions and translations from provided context.
*
* @param ContextInterface $context
* @param StepNode $step
*
* @return DefinitionSnippet
*/
public function propose(ContextInterface $context, StepNode $step);
}
<?php
namespace Behat\Behat\Definition;
use Behat\Behat\Context\ContextInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Step transformation.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface TransformationInterface
{
/**
* Transforms provided argument.
*
* @param string $translatedRegex
* @param ContextInterface $context
* @param mixed $argument
*
* @return mixed
*/
public function transform($translatedRegex, ContextInterface $context, $argument);
}
<?php
namespace Behat\Behat\DependencyInjection;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface,
Symfony\Component\DependencyInjection\Loader\XmlFileLoader,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\ParameterBag\ParameterBag,
Symfony\Component\Config\Definition\Processor,
Symfony\Component\Config\FileLocator;
use Behat\Behat\Extension\ExtensionManager;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat service container extension.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BehatExtension implements ExtensionInterface
{
protected $basePath;
protected $processor;
protected $configuration;
protected $extensionManager;
/**
* Initializes configuration.
*/
public function __construct($basePath)
{
$this->basePath = $basePath;
$this->processor = new Processor();
$this->configuration = new Configuration\Configuration();
$this->extensionManager = new ExtensionManager($basePath);
}
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$this->loadDefaults($container);
$container->setParameter('behat.paths.base', $this->basePath);
// set internal encoding to UTF-8
if ('UTF-8' !== mb_internal_encoding()) {
mb_internal_encoding('UTF-8');
}
// activate and normalize specified by user extensions
foreach ($configs as $i => $config) {
if (isset($config['extensions'])) {
$extensions = array();
foreach ($config['extensions'] as $id => $extensionConfig) {
$activationId = $this->extensionManager->activateExtension($id);
$extensions[$activationId] = $extensionConfig;
}
$configs[$i]['extensions'] = $extensions;
}
}
// set list of extensions to container
$container->setParameter('behat.extension.classes',
$this->extensionManager->getExtensionClasses()
);
// normalize and merge the actual configuration
$tree = $this->configuration->getConfigTree($this->extensionManager);
$config = $this->processor->process($tree, $configs);
if (isset($config['paths'])) {
$this->loadPathsConfiguration($config['paths'], $container);
}
if (isset($config['context'])) {
$this->loadContextConfiguration($config['context'], $container);
}
if (isset($config['formatter'])) {
$this->loadFormatterConfiguration($config['formatter'], $container);
}
if (isset($config['options'])) {
$this->loadOptionsConfiguration($config['options'], $container);
}
if (isset($config['filters'])) {
$this->loadFiltersConfiguration($config['filters'], $container);
}
if (isset($config['extensions'])) {
$this->loadExtensionsConfiguration($config['extensions'], $container);
}
$this->resolveRelativePaths($container);
$this->addCompilerPasses($container);
}
/**
* Loads paths configuration.
*
* @param array $config
* @param ContainerBuilder $container
*/
protected function loadPathsConfiguration(array $config, ContainerBuilder $container)
{
foreach ($config as $key => $path) {
$container->setParameter('behat.paths.'.$key, $path);
}
}
/**
* Loads context configuration.
*
* @param array $config
* @param ContainerBuilder $container
*/
protected function loadContextConfiguration(array $config, ContainerBuilder $container)
{
foreach ($config as $key => $value) {
$container->setParameter('behat.context.'.$key, $value);
}
}
/**
* Loads formatter(s) configuration.
*
* @param array $config
* @param ContainerBuilder $container
*/
protected function loadFormatterConfiguration(array $config, ContainerBuilder $container)
{
foreach ($config as $key => $value) {
$container->setParameter('behat.formatter.'.$key, $value);
}
}
/**
* Loads behat options configuration.
*
* @param array $config
* @param ContainerBuilder $container
*/
protected function loadOptionsConfiguration(array $config, ContainerBuilder $container)
{
foreach ($config as $key => $value) {
$container->setParameter('behat.options.'.$key, $value);
}
}
/**
* Loads gherkin filters configuration.
*
* @param array $config
* @param ContainerBuilder $container
*/
protected function loadFiltersConfiguration(array $config, ContainerBuilder $container)
{
foreach ($config as $key => $filter) {
$container->setParameter('gherkin.filters.'.$key, $filter);
}
}
/**
* Loads extensions configuration.
*
* @param array $config
* @param ContainerBuilder $container
*/
protected function loadExtensionsConfiguration(array $config, ContainerBuilder $container)
{
foreach ($config as $id => $extensionConfig) {
// load extension from manager
$extension = $this->extensionManager->getExtension($id);
// create temporary container
$tempContainer = new ContainerBuilder(new ParameterBag(array(
'behat.paths.base' => $container->getParameter('behat.paths.base'),
'behat.extension.classes' => $container->getParameter('behat.extension.classes'),
)));
$tempContainer->addObjectResource($extension);
// load extension into temporary container
$extension->load($extensionConfig, $tempContainer);
// merge temporary container into normal one
$container->merge($tempContainer);
// add extension compiler passes
array_map(array($container, 'addCompilerPass'), $extension->getCompilerPasses());
}
}
/**
* Resolves relative behat.paths.* parameters in container.
*
* @param ContainerBuilder $container
*/
protected function resolveRelativePaths(ContainerBuilder $container)
{
$featuresPath = $container->getParameter('behat.paths.features');
$bootstrapPath = $container->getParameter('behat.paths.bootstrap');
$parameterBag = $container->getParameterBag();
$featuresPath = $parameterBag->resolveValue($featuresPath);
$bootstrapPath = $parameterBag->resolveValue($bootstrapPath);
if (!$this->isAbsolutePath($featuresPath)) {
$featuresPath = $this->basePath.DIRECTORY_SEPARATOR.$featuresPath;
$container->setParameter('behat.paths.features', $featuresPath);
}
if (!$this->isAbsolutePath($bootstrapPath)) {
$bootstrapPath = $this->basePath.DIRECTORY_SEPARATOR.$bootstrapPath;
$container->setParameter('behat.paths.bootstrap', $bootstrapPath);
}
}
/**
* Adds core compiler passes to container.
*
* @param ContainerBuilder $container
*/
protected function addCompilerPasses(ContainerBuilder $container)
{
$container->addCompilerPass(new Compiler\ConsoleProcessorsPass());
$container->addCompilerPass(new Compiler\GherkinLoadersPass());
$container->addCompilerPass(new Compiler\ContextLoadersPass());
$container->addCompilerPass(new Compiler\ContextClassGuessersPass());
$container->addCompilerPass(new Compiler\ContextInitializersPass());
$container->addCompilerPass(new Compiler\DefinitionProposalsPass());
$container->addCompilerPass(new Compiler\FormattersPass());
$container->addCompilerPass(new Compiler\EventSubscribersPass());
}
/**
* {@inheritdoc}
*/
public function getXsdValidationBasePath()
{
return __DIR__ . '/config/schema';
}
/**
* {@inheritdoc}
*/
public function getNamespace()
{
return 'http://behat.com/schema/dic/behat';
}
/**
* {@inheritdoc}
*/
public function getAlias()
{
return 'behat';
}
/**
* {@inheritdoc}
*/
protected function loadDefaults($container)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/config'));
$loader->load('behat.xml');
$behatClassLoaderReflection = new \ReflectionClass('Behat\Behat\Console\BehatApplication');
$gherkinParserReflection = new \ReflectionClass('Behat\Gherkin\Parser');
$behatLibPath = dirname($behatClassLoaderReflection->getFilename()) . '/../../../../';
$gherkinLibPath = dirname($gherkinParserReflection->getFilename()) . '/../../../';
$container->setParameter('gherkin.paths.lib', $gherkinLibPath);
$container->setParameter('behat.paths.lib', $behatLibPath);
}
/**
* Returns whether the file path is an absolute path.
*
* @param string $file A file path
*
* @return Boolean
*/
private function isAbsolutePath($file)
{
if ($file[0] == '/' || $file[0] == '\\'
|| (strlen($file) > 3 && ctype_alpha($file[0])
&& $file[1] == ':'
&& ($file[2] == '\\' || $file[2] == '/')
)
|| null !== parse_url($file, PHP_URL_SCHEME)
) {
return true;
}
return false;
}
}
<?php
namespace Behat\Behat\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat.
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Command pass - registers all available command processors.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ConsoleProcessorsPass implements CompilerPassInterface
{
/**
* Processes container.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.console.processor.aggregate')) {
return;
}
$aggregator = $container->getDefinition('behat.console.processor.aggregate');
foreach ($container->findTaggedServiceIds('behat.console.processor') as $id => $attributes) {
$aggregator->addMethodCall('addProcessor', array(new Reference($id)));
}
}
}
<?php
namespace Behat\Behat\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat.
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Context class guessers pass - registers all available context class guessers.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ContextClassGuessersPass implements CompilerPassInterface
{
/**
* Processes container.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.context.dispatcher')) {
return;
}
$dispatcher = $container->getDefinition('behat.context.dispatcher');
// Sorts guessers by priority (0 by default).
// Guessers with higher priority go first.
// If two guessers has same priority, then the
// lastly added one goes first. Means guessers
// from later extensions have more priority.
$prioritizedGuessers = array();
foreach ($container->findTaggedServiceIds('behat.context.class_guesser') as $id => $attributes) {
$attributes = isset($attributes[0]) ? $attributes[0] : array();
$priority = intval(isset($attributes['priority']) ? $attributes['priority'] : 0);
if (!isset($prioritizedGuessers[$priority])) {
$prioritizedGuessers[$priority] = array();
}
array_unshift($prioritizedGuessers[$priority], new Reference($id));
}
krsort($prioritizedGuessers);
foreach ($prioritizedGuessers as $guessers) {
foreach ($guessers as $guesser) {
$dispatcher->addMethodCall('addClassGuesser', array($guesser));
}
}
}
}
<?php
namespace Behat\Behat\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat.
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Context initializers pass - registers all available context initializers.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ContextInitializersPass implements CompilerPassInterface
{
/**
* Processes container.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.context.dispatcher')) {
return;
}
$dispatcher = $container->getDefinition('behat.context.dispatcher');
foreach ($container->findTaggedServiceIds('behat.context.initializer') as $id => $attributes) {
$dispatcher->addMethodCall('addInitializer', array(new Reference($id)));
}
}
}
<?php
namespace Behat\Behat\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat.
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Context loaders pass - registers all available context loaders.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ContextLoadersPass implements CompilerPassInterface
{
/**
* Processes container.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.context.reader')) {
return;
}
$readerDefinition = $container->getDefinition('behat.context.reader');
foreach ($container->findTaggedServiceIds('behat.context.loader') as $id => $attributes) {
$readerDefinition->addMethodCall('addLoader', array(new Reference($id)));
}
}
}
<?php
namespace Behat\Behat\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat.
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Definition proposals pass - registers all available definition proposals.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class DefinitionProposalsPass implements CompilerPassInterface
{
/**
* Processes container.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.definition.proposal_dispatcher')) {
return;
}
$dispatcher = $container->getDefinition('behat.definition.proposal_dispatcher');
foreach ($container->findTaggedServiceIds('behat.definition.proposal') as $id => $attributes) {
$dispatcher->addMethodCall('addProposal', array(new Reference($id)));
}
}
}
<?php
namespace Behat\Behat\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat.
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Event subscribers pass - registers all available event subscribers.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class EventSubscribersPass implements CompilerPassInterface
{
/**
* Processes container.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.event_dispatcher')) {
return;
}
$dispatcherDefinition = $container->getDefinition('behat.event_dispatcher');
foreach ($container->findTaggedServiceIds('behat.event_subscriber') as $id => $attributes) {
foreach ($attributes as $attribute) {
$priority = isset($attribute['priority']) ? intval($attribute['priority']) : 0;
$dispatcherDefinition->addMethodCall(
'addSubscriber', array(new Reference($id), $priority)
);
}
}
}
}
<?php
namespace Behat\Behat\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat.
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Formatters pass - registers all available formatters.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FormattersPass implements CompilerPassInterface
{
/**
* Processes container.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.formatter.manager')) {
return;
}
$manager = $container->getDefinition('behat.formatter.manager');
foreach ($container->findTaggedServiceIds('behat.formatter.dispatcher') as $id => $attributes) {
$manager->addMethodCall('addDispatcher', array(new Reference($id)));
}
}
}
<?php
namespace Behat\Behat\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat.
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Gherkin loaders pass - registers all available Gherkin loaders.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class GherkinLoadersPass implements CompilerPassInterface
{
/**
* Processes container.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('gherkin')) {
return;
}
$gherkinDefinition = $container->getDefinition('gherkin');
foreach ($container->findTaggedServiceIds('gherkin.loader') as $id => $attributes) {
$gherkinDefinition->addMethodCall('addLoader', array(new Reference($id)));
}
}
}
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services">
<parameters>
<!-- Path parameters -->
<parameter key="gherkin.paths.lib">null</parameter>
<parameter key="gherkin.paths.i18n">%gherkin.paths.lib%/i18n.php</parameter>
<parameter key="behat.paths.lib">null</parameter>
<parameter key="behat.paths.i18n">%behat.paths.lib%/i18n.php</parameter>
<parameter key="behat.paths.base"></parameter>
<parameter key="behat.paths.features">%behat.paths.base%/features</parameter>
<parameter key="behat.paths.bootstrap">%behat.paths.features%/bootstrap</parameter>
<!-- Format parameters -->
<parameter key="behat.formatter.name">pretty</parameter>
<parameter key="behat.formatter.parameters" type="collection"></parameter>
<parameter key="behat.formatter.classes" type="collection"></parameter>
<parameter key="behat.formatter.dispatcher.class">Behat\Behat\Formatter\FormatterDispatcher</parameter>
<parameter key="behat.formatter.manager.class">Behat\Behat\Formatter\FormatterManager</parameter>
<!-- Options -->
<parameter key="behat.options.cache">null</parameter>
<parameter key="behat.options.rerun">null</parameter>
<parameter key="behat.options.strict">null</parameter>
<parameter key="behat.options.dry_run">null</parameter>
<parameter key="behat.options.append_snippets">null</parameter>
<!-- Gherkin Parser -->
<parameter key="gherkin.class">Behat\Gherkin\Gherkin</parameter>
<parameter key="gherkin.parser.class">Behat\Gherkin\Parser</parameter>
<parameter key="gherkin.lexer.class">Behat\Gherkin\Lexer</parameter>
<parameter key="gherkin.loader.gherkin_file.class">Behat\Gherkin\Loader\GherkinFileLoader</parameter>
<parameter key="gherkin.loader.directory.class">Behat\Gherkin\Loader\DirectoryLoader</parameter>
<parameter key="gherkin.loader.feature_suite.class">Behat\Behat\Gherkin\Loader\FeatureSuiteLoader</parameter>
<parameter key="gherkin.keywords.class">Behat\Gherkin\Keywords\CachedArrayKeywords</parameter>
<parameter key="gherkin.keywords.path">%gherkin.paths.i18n%</parameter>
<parameter key="gherkin.keywords.dumper.class">Behat\Gherkin\Keywords\KeywordsDumper</parameter>
<parameter key="gherkin.filters.name">null</parameter>
<parameter key="gherkin.filters.tags">null</parameter>
<!-- Core -->
<parameter key="behat.extension.classes" type="collection"></parameter>
<parameter key="behat.console.command.class">Behat\Behat\Console\Command\BehatCommand</parameter>
<parameter key="behat.console.processor.aggregate.class">Behat\Behat\Console\Processor\AggregateProcessor</parameter>
<parameter key="behat.console.processor.locator.class">Behat\Behat\Console\Processor\LocatorProcessor</parameter>
<parameter key="behat.console.processor.context.reader.class">Behat\Behat\Console\Processor\ContextReaderProcessor</parameter>
<parameter key="behat.console.processor.init.class">Behat\Behat\Console\Processor\InitProcessor</parameter>
<parameter key="behat.console.processor.format.class">Behat\Behat\Console\Processor\FormatProcessor</parameter>
<parameter key="behat.console.processor.help.class">Behat\Behat\Console\Processor\HelpProcessor</parameter>
<parameter key="behat.console.processor.gherkin.class">Behat\Behat\Console\Processor\GherkinProcessor</parameter>
<parameter key="behat.console.processor.run.class">Behat\Behat\Console\Processor\RunProcessor</parameter>
<!-- Context -->
<parameter key="behat.context.class">FeatureContext</parameter>
<parameter key="behat.context.parameters" type="collection"></parameter>
<parameter key="behat.context.dispatcher.class">Behat\Behat\Context\ContextDispatcher</parameter>
<parameter key="behat.context.reader.class">Behat\Behat\Context\ContextReader</parameter>
<parameter key="behat.context.class_guesser.predefined.class">Behat\Behat\Context\ClassGuesser\PredefinedClassGuesser</parameter>
<parameter key="behat.context.loader.translated.class">Behat\Behat\Context\Loader\TranslatedLoader</parameter>
<parameter key="behat.context.loader.annotated.class">Behat\Behat\Context\Loader\AnnotatedLoader</parameter>
<parameter key="behat.context.loader.closured.class">Behat\Behat\Context\Loader\ClosuredLoader</parameter>
<!-- Definition Dispathcer -->
<parameter key="behat.definition.dispatcher.class">Behat\Behat\Definition\DefinitionDispatcher</parameter>
<parameter key="behat.definition.loader.closured.class">Behat\Behat\Definition\Loader\ClosuredDefinitionLoader</parameter>
<parameter key="behat.definition.proposal_dispatcher.class">Behat\Behat\Definition\Proposal\DefinitionProposalDispatcher</parameter>
<parameter key="behat.definition.proposal.closured.class">Behat\Behat\Definition\Proposal\ClosuredDefinitionProposal</parameter>
<parameter key="behat.definition.proposal.annotated.class">Behat\Behat\Definition\Proposal\AnnotatedDefinitionProposal</parameter>
<!-- Hook Dispatcher -->
<parameter key="behat.hook.dispatcher.class">Behat\Behat\Hook\HookDispatcher</parameter>
<parameter key="behat.hook.loader.closured.class">Behat\Behat\Hook\Loader\ClosuredHookLoader</parameter>
<!-- Tester -->
<parameter key="behat.tester.feature.class">Behat\Behat\Tester\FeatureTester</parameter>
<parameter key="behat.tester.background.class">Behat\Behat\Tester\BackgroundTester</parameter>
<parameter key="behat.tester.scenario.class">Behat\Behat\Tester\ScenarioTester</parameter>
<parameter key="behat.tester.outline.class">Behat\Behat\Tester\OutlineTester</parameter>
<parameter key="behat.tester.step.class">Behat\Behat\Tester\StepTester</parameter>
<!-- Translator -->
<parameter key="behat.translator.class">Symfony\Component\Translation\Translator</parameter>
<parameter key="behat.translator.message_selector.class">Symfony\Component\Translation\MessageSelector</parameter>
<parameter key="behat.translator.xliff_loader.class">Symfony\Component\Translation\Loader\XliffFileLoader</parameter>
<parameter key="behat.translator.yaml_loader.class">Symfony\Component\Translation\Loader\YamlFileLoader</parameter>
<parameter key="behat.translator.php_loader.class">Symfony\Component\Translation\Loader\PhpFileLoader</parameter>
<parameter key="behat.translator.array_loader.class">Symfony\Component\Translation\Loader\ArrayLoader</parameter>
<!-- Event Dispatcher -->
<parameter key="behat.event_dispatcher.class">Symfony\Component\EventDispatcher\EventDispatcher</parameter>
<!-- DataCollector -->
<parameter key="behat.logger.class">Behat\Behat\DataCollector\LoggerDataCollector</parameter>
<!-- HelpPrinter -->
<parameter key="behat.help_printer.definitions.class">Behat\Behat\HelpPrinter\DefinitionsPrinter</parameter>
<parameter key="behat.help_printer.story_syntax.class">Behat\Behat\HelpPrinter\StorySyntaxPrinter</parameter>
</parameters>
<services>
<!-- Gherkin Parser -->
<service id="gherkin" class="%gherkin.class%" />
<service id="gherkin.parser" class="%gherkin.parser.class%">
<argument type="service" id="gherkin.lexer" />
</service>
<service id="gherkin.lexer" class="%gherkin.lexer.class%">
<argument type="service" id="gherkin.keywords" />
</service>
<service id="gherkin.keywords" class="%gherkin.keywords.class%">
<argument>%gherkin.paths.lib%/i18n.php</argument>
</service>
<service id="gherkin.loader.gherkin_file" class="%gherkin.loader.gherkin_file.class%">
<argument type="service" id="gherkin.parser" />
<tag name="gherkin.loader" />
</service>
<service id="gherkin.loader.feature_suite" class="%gherkin.loader.feature_suite.class%">
<argument>%behat.paths.features%</argument>
<argument type="service" id="gherkin" />
<tag name="gherkin.loader" />
</service>
<service id="gherkin.loader.directory" class="%gherkin.loader.directory.class%">
<argument type="service" id="gherkin" />
<tag name="gherkin.loader" />
</service>
<!-- Core -->
<service id="behat.console.command" class="%behat.console.command.class%">
<argument type="service" id="service_container" />
<argument type="service" id="behat.console.processor.aggregate" />
</service>
<!-- Processors -->
<service id="behat.console.processor.aggregate" class="%behat.console.processor.aggregate.class%" />
<service id="behat.console.processor.locator" class="%behat.console.processor.locator.class%">
<argument type="service" id="service_container" />
<tag name="behat.console.processor" />
</service>
<service id="behat.console.processor.init" class="%behat.console.processor.init.class%">
<argument type="service" id="service_container" />
<tag name="behat.console.processor" />
</service>
<service id="behat.console.processor.format" class="%behat.console.processor.format.class%">
<argument type="service" id="service_container" />
<tag name="behat.console.processor" />
</service>
<service id="behat.console.processor.context.reader" class="%behat.console.processor.context.reader.class%">
<argument type="service" id="service_container" />
<tag name="behat.console.processor" />
</service>
<service id="behat.console.processor.help" class="%behat.console.processor.help.class%">
<argument type="service" id="service_container" />
<tag name="behat.console.processor" />
</service>
<service id="behat.console.processor.gherkin" class="%behat.console.processor.gherkin.class%">
<argument type="service" id="service_container" />
<tag name="behat.console.processor" />
</service>
<service id="behat.console.processor.run" class="%behat.console.processor.run.class%">
<argument type="service" id="service_container" />
<tag name="behat.console.processor" />
</service>
<!-- Context -->
<service id="behat.context.reader" class="%behat.context.reader.class%">
<argument type="service" id="behat.context.dispatcher" />
</service>
<service id="behat.context.dispatcher" class="%behat.context.dispatcher.class%">
<argument>%behat.context.parameters%</argument>
</service>
<service id="behat.context.class_guesser.predefined" class="%behat.context.class_guesser.predefined.class%">
<argument>%behat.context.class%</argument>
<tag name="behat.context.class_guesser" priority="10" />
</service>
<service id="behat.context.loader.translated" class="%behat.context.loader.translated.class%">
<argument type="service" id="behat.translator" />
<tag name="behat.context.loader" />
</service>
<service id="behat.context.loader.annotated" class="%behat.context.loader.annotated.class%">
<argument type="service" id="behat.definition.dispatcher" />
<argument type="service" id="behat.hook.dispatcher" />
<tag name="behat.context.loader" />
</service>
<service id="behat.context.loader.closured" class="%behat.context.loader.closured.class%">
<argument type="service">
<service class="%behat.definition.loader.closured.class%">
<argument type="service" id="behat.definition.dispatcher" />
</service>
</argument>
<argument type="service">
<service class="%behat.hook.loader.closured.class%">
<argument type="service" id="behat.hook.dispatcher" />
</service>
</argument>
<tag name="behat.context.loader" />
</service>
<!-- Definition Dispatcher -->
<service id="behat.definition.dispatcher" class="%behat.definition.dispatcher.class%">
<argument type="service" id="behat.definition.proposal_dispatcher" />
<argument type="service" id="behat.translator" />
</service>
<service id="behat.definition.proposal_dispatcher" class="%behat.definition.proposal_dispatcher.class%" />
<service id="behat.definition.proposal.closured" class="%behat.definition.proposal.closured.class%">
<tag name="behat.definition.proposal" />
</service>
<service id="behat.definition.proposal.annotated" class="%behat.definition.proposal.annotated.class%">
<tag name="behat.definition.proposal" />
</service>
<!-- Tester -->
<service id="behat.tester.feature" class="%behat.tester.feature.class%" scope="prototype">
<argument type="service" id="service_container" />
</service>
<service id="behat.tester.background" class="%behat.tester.background.class%" scope="prototype">
<argument type="service" id="service_container" />
</service>
<service id="behat.tester.scenario" class="%behat.tester.scenario.class%" scope="prototype">
<argument type="service" id="service_container" />
</service>
<service id="behat.tester.outline" class="%behat.tester.outline.class%" scope="prototype">
<argument type="service" id="service_container" />
</service>
<service id="behat.tester.step" class="%behat.tester.step.class%" scope="prototype">
<argument type="service" id="service_container" />
</service>
<!-- Format -->
<service id="behat.formatter.manager" class="%behat.formatter.manager.class%">
<argument type="service" id="behat.translator" />
<argument type="service" id="behat.event_dispatcher" />
</service>
<service id="behat.formatter.dispatcher.pretty" class="%behat.formatter.dispatcher.class%">
<argument>Behat\Behat\Formatter\PrettyFormatter</argument>
<argument>pretty</argument>
<argument>Prints the feature as is.</argument>
<tag name="behat.formatter.dispatcher" />
</service>
<service id="behat.formatter.dispatcher.progress" class="%behat.formatter.dispatcher.class%">
<argument>Behat\Behat\Formatter\ProgressFormatter</argument>
<argument>progress</argument>
<argument>Prints one character per step.</argument>
<tag name="behat.formatter.dispatcher" />
</service>
<service id="behat.formatter.dispatcher.html" class="%behat.formatter.dispatcher.class%">
<argument>Behat\Behat\Formatter\HtmlFormatter</argument>
<argument>html</argument>
<argument>Generates a nice looking HTML report.</argument>
<tag name="behat.formatter.dispatcher" />
</service>
<service id="behat.formatter.dispatcher.junit" class="%behat.formatter.dispatcher.class%">
<argument>Behat\Behat\Formatter\JUnitFormatter</argument>
<argument>junit</argument>
<argument>Generates a report similar to Ant+JUnit.</argument>
<tag name="behat.formatter.dispatcher" />
</service>
<service id="behat.formatter.dispatcher.failed" class="%behat.formatter.dispatcher.class%">
<argument>Behat\Behat\Formatter\FailedScenariosFormatter</argument>
<argument>failed</argument>
<argument>Prints list of failed scenarios.</argument>
<tag name="behat.formatter.dispatcher" />
</service>
<service id="behat.formatter.dispatcher.snippets" class="%behat.formatter.dispatcher.class%">
<argument>Behat\Behat\Formatter\SnippetsFormatter</argument>
<argument>snippets</argument>
<argument>Prints only snippets for undefined steps.</argument>
<tag name="behat.formatter.dispatcher" />
</service>
<!-- Event Dispatcher -->
<service id="behat.event_dispatcher" class="%behat.event_dispatcher.class%" />
<!-- Hook Dispatcher -->
<service id="behat.hook.dispatcher" class="%behat.hook.dispatcher.class%">
<tag name="behat.event_subscriber" priority="10" />
</service>
<!-- DataCollector -->
<service id="behat.logger" class="%behat.logger.class%">
<tag name="behat.event_subscriber" priority="0" />
</service>
<!-- HelpPrinter -->
<service id="behat.help_printer.definitions" class="%behat.help_printer.definitions.class%">
<argument type="service" id="behat.definition.dispatcher" />
<argument type="service" id="behat.translator" />
</service>
<service id="behat.help_printer.story_syntax" class="%behat.help_printer.story_syntax.class%">
<argument type="service">
<service class="%gherkin.keywords.dumper.class%">
<argument type="service" id="gherkin.keywords" />
</service>
</argument>
</service>
<!-- Translator -->
<service id="behat.translator" class="%behat.translator.class%">
<argument>en</argument>
<argument type="service">
<service class="%behat.translator.message_selector.class%" />
</argument>
<call method="setFallbackLocale">
<argument>en</argument>
</call>
<!-- Translation loaders -->
<call method="addLoader">
<argument>xliff</argument>
<argument type="service">
<service class="%behat.translator.xliff_loader.class%" />
</argument>
</call>
<call method="addLoader">
<argument>yaml</argument>
<argument type="service">
<service class="%behat.translator.yaml_loader.class%" />
</argument>
</call>
<call method="addLoader">
<argument>php</argument>
<argument type="service">
<service class="%behat.translator.php_loader.class%" />
</argument>
</call>
<call method="addLoader">
<argument>array</argument>
<argument type="service">
<service class="%behat.translator.array_loader.class%" />
</argument>
</call>
</service>
</services>
</container>
<?php
namespace Behat\Behat\DependencyInjection\Configuration;
use Symfony\Component\Config\Definition\Builder\NodeBuilder,
Symfony\Component\Config\Definition\Builder\TreeBuilder,
Symfony\Component\Config\Definition\NodeInterface,
Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Behat\Behat\Extension\ExtensionManager;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* This class contains the configuration information for the Behat
*
* This information is solely responsible for how the different configuration
* sections are normalized, and merged.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Configuration
{
/**
* Generates the configuration tree.
*
* @param ExtensionManager $extensionManager
*
* @return NodeInterface
*/
public function getConfigTree(ExtensionManager $extensionManager)
{
$tree = new TreeBuilder();
$root = $this->appendConfigChildrens($tree);
$extensionsNode = $root->fixXmlConfig('extension')->children()->arrayNode('extensions')->children();
foreach ($extensionManager->getExtensions() as $id => $extension) {
$extensionNode = $extensionsNode->arrayNode($id);
$extension->getConfig($extensionNode);
}
return $tree->buildTree();
}
/**
* Appends config childrens to configuration tree.
*
* @param TreeBuilder $tree tree builder
*
* @return ArrayNodeDefinition
*/
protected function appendConfigChildrens(TreeBuilder $tree)
{
return $tree->root('behat')->
children()->
arrayNode('paths')->
children()->
scalarNode('features')->
defaultValue('%behat.paths.base%/features')->
end()->
scalarNode('bootstrap')->
defaultValue('%behat.paths.features%/bootstrap')->
end()->
end()->
end()->
end()->
children()->
arrayNode('filters')->
children()->
scalarNode('name')->defaultNull()->end()->
scalarNode('tags')->defaultNull()->end()->
end()->
end()->
end()->
children()->
arrayNode('formatter')->
fixXmlConfig('parameter')->
children()->
scalarNode('name')->
defaultValue('pretty')->
end()->
arrayNode('classes')->
useAttributeAsKey('name')->
prototype('scalar')->end()->
end()->
arrayNode('parameters')->
useAttributeAsKey('name')->
prototype('variable')->end()->
end()->
end()->
end()->
end()->
children()->
arrayNode('options')->
fixXmlConfig('option')->
children()->
scalarNode('cache')->
defaultNull()->
end()->
booleanNode('strict')->
defaultNull()->
end()->
booleanNode('dry_run')->
defaultNull()->
end()->
scalarNode('rerun')->
defaultNull()->
end()->
scalarNode('append_snippets')->
defaultNull()->
end()->
end()->
end()->
end()->
children()->
arrayNode('context')->
fixXmlConfig('parameter')->
children()->
scalarNode('class')->
defaultValue('FeatureContext')->
end()->
arrayNode('parameters')->
useAttributeAsKey('name')->
prototype('variable')->end()->
end()->
end()->
end()->
end()
;
}
}
<?php
namespace Behat\Behat\DependencyInjection\Configuration;
use Symfony\Component\Yaml\Yaml;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat configuration reader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Loader
{
private $configPath;
private $profileFound;
/**
* Constructs reader.
*
* @param string $configPath Configuration file path
*/
public function __construct($configPath = null)
{
$this->configPath = $configPath;
}
/**
* Reads configuration sequense for specific profile.
*
* @param string $profile Profile name
*
* @return array
*/
public function loadConfiguration($profile = 'default')
{
$configs = array();
$this->profileFound = false;
// first is ENV config
foreach ($this->loadEnvironmentConfiguration() as $config) {
$configs[] = $config;
}
// second is file configuration (if there is some)
if ($this->configPath) {
foreach ($this->loadFileConfiguration($this->configPath, $profile) as $config) {
$configs[] = $config;
}
}
// if specific profile has not been found
if ('default' !== $profile && !$this->profileFound) {
throw new \RuntimeException(sprintf(
'Configuration for profile "%s" can not be found.', $profile
));
}
return $configs;
}
/**
* Loads information from ENV variable.
*
* @return array
*/
protected function loadEnvironmentConfiguration()
{
$configs = array();
if ($envConfig = getenv('BEHAT_PARAMS')) {
parse_str($envConfig, $config);
$configs[] = $this->normalizeRawConfiguration($config);
}
return $configs;
}
/**
* Loads information from YAML configuration file.
*
* @param string $configPath Config file path
* @param string $profile Profile name
*
* @return array
*
* @throws \RuntimeException
*/
protected function loadFileConfiguration($configPath, $profile)
{
if (!is_file($configPath) || !is_readable($configPath)) {
throw new \RuntimeException("Config file \"$configPath\" not found");
}
$basePath = rtrim(dirname($configPath), DIRECTORY_SEPARATOR);
$config = Yaml::parse($configPath);
$configs = array();
// first load default profile from current config
if (isset($config['default'])) {
$configs[] = $config['default'];
}
// then load profiles from import
if (isset($config['imports']) && is_array($config['imports'])) {
foreach ($config['imports'] as $path) {
foreach ($this->parseImport($basePath, $path, $profile) as $importConfig) {
$configs[] = $importConfig;
}
}
}
// then load specific profile from current config
if ('default' !== $profile && isset($config[$profile])) {
$configs[] = $config[$profile];
$this->profileFound = true;
}
return $configs;
}
private function parseImport($basePath, $path, $profile)
{
if (!file_exists($path) && file_exists($basePath.DIRECTORY_SEPARATOR.$path)) {
$path = $basePath.DIRECTORY_SEPARATOR.$path;
}
if (!file_exists($path)) {
throw new \RuntimeException(sprintf(
'Can not import config "%s": file not found.', $path
));
}
return $this->loadFileConfiguration($path, $profile);
}
private function normalizeRawConfiguration(array $config)
{
$normalize = function($value) {
if ('true' === $value || 'false' === $value) {
return 'true' === $value;
}
if (is_numeric($value)) {
return ctype_digit($value) ? intval($value) : floatval($value);
}
return $value;
};
if (isset($config['formatter']['parameters'])) {
$config['formatter']['parameters'] = array_map(
$normalize, $config['formatter']['parameters']
);
}
if (isset($config['context']['parameters'])) {
$config['context']['parameters'] = array_map(
$normalize, $config['context']['parameters']
);
}
return $config;
}
}
<?php
namespace Behat\Behat\Event;
use Symfony\Component\EventDispatcher\Event;
use Behat\Gherkin\Node\BackgroundNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Background event.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BackgroundEvent extends Event implements EventInterface
{
private $background;
private $result;
private $skipped;
/**
* Initializes background event.
*
* @param BackgroundNode $background
* @param integer $result
* @param Boolean $skipped
*/
public function __construct(BackgroundNode $background, $result = null, $skipped = false)
{
$this->background = $background;
$this->result = $result;
$this->skipped = $skipped;
}
/**
* Returns background node.
*
* @return BackgroundNode
*/
public function getBackground()
{
return $this->background;
}
/**
* Return background tester result code.
*
* @return integer
*/
public function getResult()
{
return $this->result;
}
/**
* Checks whether background were skipped.
*
* @return Boolean
*/
public function isSkipped()
{
return $this->skipped;
}
}
<?php
namespace Behat\Behat\Event;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat event interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface EventInterface
{
}
<?php
namespace Behat\Behat\Event;
use Symfony\Component\EventDispatcher\Event;
use Behat\Gherkin\Node\FeatureNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Feature event.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FeatureEvent extends Event implements EventInterface
{
private $feature;
private $result;
private $parameters;
/**
* Initializes feature event.
*
* @param FeatureNode $feature
* @param mixed $parameters
* @param integer $result
*/
public function __construct(FeatureNode $feature, $parameters, $result = null)
{
$this->feature = $feature;
$this->parameters = $parameters;
$this->result = $result;
}
/**
* Returns feature node.
*
* @return FeatureNode
*/
public function getFeature()
{
return $this->feature;
}
/**
* Returns context parameters.
*
* @return mixed
*/
public function getContextParameters()
{
return $this->parameters;
}
/**
* Returns feature tester result code.
*
* @return integer
*/
public function getResult()
{
return $this->result;
}
}
<?php
namespace Behat\Behat\Event;
use Symfony\Component\EventDispatcher\Event;
use Behat\Gherkin\Node\OutlineNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Outline event.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class OutlineEvent extends Event implements EventInterface
{
private $outline;
private $result;
/**
* Initializes outline event.
*
* @param OutlineNode $outline
* @param integer $result
*/
public function __construct(OutlineNode $outline, $result = null)
{
$this->outline = $outline;
$this->result = $result;
}
/**
* Returns outline node.
*
* @return OutlineNode
*/
public function getOutline()
{
return $this->outline;
}
/**
* Returns outline tester result code.
*
* @return integer
*/
public function getResult()
{
return $this->result;
}
}
<?php
namespace Behat\Behat\Event;
use Symfony\Component\EventDispatcher\Event;
use Behat\Behat\Context\ContextInterface;
use Behat\Gherkin\Node\OutlineNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Outline example event.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class OutlineExampleEvent extends OutlineEvent implements EventInterface
{
private $iteration;
private $context;
private $skipped;
/**
* Initializes outline example event.
*
* @param OutlineNode $outline
* @param integer $iteration iteration number
* @param ContextInterface $context
* @param integer $result
* @param Boolean $skipped
*/
public function __construct(OutlineNode $outline, $iteration, ContextInterface $context,
$result = null, $skipped = false)
{
parent::__construct($outline, $result);
$this->iteration = $iteration;
$this->context = $context;
$this->skipped = $skipped;
}
/**
* Returns example number on which event occurs.
*
* @return integer
*/
public function getIteration()
{
return $this->iteration;
}
/**
* Returns context object.
*
* @return ContextInterface
*/
public function getContext()
{
return $this->context;
}
/**
* Checks whether outline example were skipped.
*
* @return Boolean
*/
public function isSkipped()
{
return $this->skipped;
}
}
<?php
namespace Behat\Behat\Event;
use Symfony\Component\EventDispatcher\Event;
use Behat\Behat\Context\ContextInterface;
use Behat\Gherkin\Node\ScenarioNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Scenario event.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ScenarioEvent extends Event implements EventInterface
{
private $scenario;
private $context;
private $result;
private $skipped;
/**
* Initializes scenario event.
*
* @param ScenarioNode $scenario
* @param ContextInterface $context
* @param integer $result
* @param Boolean $skipped
*/
public function __construct(ScenarioNode $scenario, ContextInterface $context, $result = null,
$skipped = false)
{
$this->scenario = $scenario;
$this->context = $context;
$this->result = $result;
$this->skipped = $skipped;
}
/**
* Returns scenario node.
*
* @return ScenarioNode
*/
public function getScenario()
{
return $this->scenario;
}
/**
* Returns context object.
*
* @return ContextInterface
*/
public function getContext()
{
return $this->context;
}
/**
* Returns scenario tester result code.
*
* @return integer
*/
public function getResult()
{
return $this->result;
}
/**
* Checks whether scenario were skipped.
*
* @return Boolean
*/
public function isSkipped()
{
return $this->skipped;
}
}
<?php
namespace Behat\Behat\Event;
use Symfony\Component\EventDispatcher\Event;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Definition\DefinitionInterface,
Behat\Behat\Definition\DefinitionSnippet;
use Behat\Gherkin\Node\StepNode,
Behat\Gherkin\Node\ScenarioNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Step event.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class StepEvent extends Event implements EventInterface
{
const PASSED = 0;
const SKIPPED = 1;
const PENDING = 2;
const UNDEFINED = 3;
const FAILED = 4;
private $step;
private $parent;
private $context;
private $result;
private $definition;
private $exception;
private $snippet;
/**
* Initializes step event.
*
* @param StepNode $step
* @param ScenarioNode $parent
* @param ContextInterface $context
* @param integer $result
* @param DefinitionInterface $definition
* @param \Exception $exception
* @param DefinitionSnippet $snippet
*/
public function __construct(StepNode $step, ScenarioNode $parent, ContextInterface $context,
$result = null, DefinitionInterface $definition = null,
\Exception $exception = null, DefinitionSnippet $snippet = null)
{
$this->step = $step;
$this->parent = $parent;
$this->context = $context;
$this->result = $result;
$this->definition = $definition;
$this->exception = $exception;
$this->snippet = $snippet;
}
/**
* Returns step node.
*
* @return StepNode
*/
public function getStep()
{
return $this->step;
}
/**
* Returns logical parent to the step, which is always a ScenarioNode.
*
* @return ScenarioNode
*/
public function getLogicalParent()
{
return $this->parent;
}
/**
* Returns context object.
*
* @return ContextInterface
*/
public function getContext()
{
return $this->context;
}
/**
* Returns step tester result code.
*
* @return integer
*/
public function getResult()
{
return $this->result;
}
/**
* Returns step definition object.
*
* @return DefinitionInterface
*/
public function getDefinition()
{
return $this->definition;
}
/**
* Checks whether event contains step definition.
*
* @return Boolean
*/
public function hasDefinition()
{
return null !== $this->getDefinition();
}
/**
* Returns step tester exception.
*
* @return \Exception
*/
public function getException()
{
return $this->exception;
}
/**
* Checks whether event contains exception.
*
* @return Boolean
*/
public function hasException()
{
return null !== $this->getException();
}
/**
* Returns step snippet.
*
* @return DefinitionSnippet
*/
public function getSnippet()
{
return $this->snippet;
}
/**
* Checks whether event contains snippet.
*
* @return Boolean
*/
public function hasSnippet()
{
return null !== $this->getSnippet();
}
}
<?php
namespace Behat\Behat\Event;
use Symfony\Component\EventDispatcher\Event;
use Behat\Behat\DataCollector\LoggerDataCollector;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Suite event.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class SuiteEvent extends Event implements EventInterface
{
private $logger;
private $completed;
private $parameters;
/**
* Initializes suite event.
*
* @param LoggerDataCollector $logger suite logger
* @param mixed $parameters context parameters
* @param Boolean $completed is suite completed
*/
public function __construct(LoggerDataCollector $logger, $parameters, $completed)
{
$this->logger = $logger;
$this->parameters = $parameters;
$this->completed = (Boolean) $completed;
}
/**
* Returns suite logger.
*
* @return LoggerDataCollector
*/
public function getLogger()
{
return $this->logger;
}
/**
* Returns context parameters.
*
* @return mixed
*/
public function getContextParameters()
{
return $this->parameters;
}
/**
* Checks whether test suite was completed entirely.
*
* @return Boolean
*/
public function isCompleted()
{
return $this->completed;
}
}
<?php
namespace Behat\Behat\Exception;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Ambiguous exception.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AmbiguousException extends BehaviorException
{
protected $text;
protected $matches = array();
/**
* Initializes ambiguous exception.
*
* @param string $text step description
* @param array $matches ambigious matches (array of Definition's)
*/
public function __construct($text, array $matches)
{
$this->text = $text;
$this->matches = $matches;
$message = sprintf("Ambiguous match of \"%s\":", $text);
foreach ($matches as $definition) {
$message .= sprintf("\nto `%s` from %s", $definition->getRegex(), $definition->getPath());
}
parent::__construct($message);
}
}
<?php
namespace Behat\Behat\Exception;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Abstract Behat exception.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BehaviorException extends Exception
{
}
<?php
namespace Behat\Behat\Exception;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Error handler exception.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ErrorException extends BehaviorException
{
private $levels = array(
E_WARNING => 'Warning',
E_NOTICE => 'Notice',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_STRICT => 'Runtime Notice',
E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
);
/**
* Initializes error handler exception.
*
* @param string $level error level
* @param string $message error message
* @param string $file error file
* @param string $line error line
*/
public function __construct($level, $message, $file, $line)
{
parent::__construct(sprintf('%s: %s in %s line %d',
isset($this->levels[$level]) ? $this->levels[$level] : $level,
$message,
$file,
$line
));
}
}
<?php
namespace Behat\Behat\Exception;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat exception.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class Exception extends \Exception
{
}
<?php
namespace Behat\Behat\Exception;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat Formatter exception.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FormatterException extends Exception
{
}
<?php
namespace Behat\Behat\Exception;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Pending exception (throw this to mark step as "pending").
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class PendingException extends BehaviorException
{
/**
* Initializes pending exception.
*
* @param string $text TODO text
*/
public function __construct($text = 'write pending definition')
{
parent::__construct(sprintf('TODO: %s', $text));
}
}
<?php
namespace Behat\Behat\Exception;
use Behat\Behat\Definition\DefinitionInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Redundant exception.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class RedundantException extends BehaviorException
{
/**
* Initializes redundant exception.
*
* @param DefinitionInterface $step2 duplicate step definition
* @param DefinitionInterface $step1 firstly matched step definition
*/
public function __construct(DefinitionInterface $step2, DefinitionInterface $step1)
{
$message = sprintf("Step \"%s\" is already defined in %s\n\n%s\n%s",
$step2->getRegex(), $step1->getPath(), $step1->getPath(), $step2->getPath()
);
parent::__construct($message);
}
}
<?php
namespace Behat\Behat\Exception;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Undefined exception.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class UndefinedException extends BehaviorException
{
protected $text;
/**
* Initialize undefined exception.
*
* @param string $text step text
*/
public function __construct($text)
{
$this->text = $text;
parent::__construct(sprintf('Undefined step "%s"', $text));
}
}
<?php
namespace Behat\Behat\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Loader\XmlFileLoader,
Symfony\Component\DependencyInjection\Loader\YamlFileLoader,
Symfony\Component\Config\FileLocator,
Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat base extension class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class Extension implements ExtensionInterface
{
/**
* Loads a specific configuration.
*
* @param array $config Extension configuration hash (from behat.yml)
* @param ContainerBuilder $container ContainerBuilder instance
*/
public function load(array $config, ContainerBuilder $container)
{
if (file_exists($config = __DIR__.DIRECTORY_SEPARATOR.'services.xml')) {
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/config'));
$loader->load($config);
}
if (file_exists($config = __DIR__.DIRECTORY_SEPARATOR.'services.yml')) {
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/config'));
$loader->load($config);
}
}
/**
* Setups configuration for current extension.
*
* @param ArrayNodeDefinition $builder
*/
public function getConfig(ArrayNodeDefinition $builder)
{
$builder
->useAttributeAsKey('name')
->prototype('variable')
;
}
/**
* Returns compiler passes used by this extension.
*
* @return array
*/
public function getCompilerPasses()
{
return array();
}
}
<?php
namespace Behat\Behat\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Behat extension interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface ExtensionInterface
{
/**
* Loads a specific configuration.
*
* @param array $config Extension configuration hash (from behat.yml)
* @param ContainerBuilder $container ContainerBuilder instance
*/
public function load(array $config, ContainerBuilder $container);
/**
* Setups configuration for current extension.
*
* @param ArrayNodeDefinition $builder
*/
public function getConfig(ArrayNodeDefinition $builder);
/**
* Returns compiler passes used by this extension.
*
* @return array
*/
public function getCompilerPasses();
}
<?php
namespace Behat\Behat\Extension;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Extensions manager.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ExtensionManager
{
private $basePath;
private $extensions = array();
/**
* Initializes manager.
*
* @param string $basePath base path where to search extension files
*/
public function __construct($basePath)
{
$this->basePath = $basePath;
}
/**
* Activate extension by its id.
*
* @param string $id phar file name, php file name, class name
*/
public function activateExtension($id)
{
$extensionId = strtolower(preg_replace('/[^a-zA-Z0-9]/', '_', $id));
if (!isset($this->extensions[$extensionId])) {
$this->extensions[$extensionId] = $this->initializeExtension($id);
}
return $extensionId;
}
/**
* Returns specific extension by its id.
*
* @param string $id
*
* @return ExtensionInterface
*
* @throws \RuntimeException
*/
public function getExtension($id)
{
if (!isset($this->extensions[$id])) {
throw new \RuntimeException(
sprintf('Extension "%s" has not been activated.', $id)
);
}
return $this->extensions[$id];
}
/**
* Returns all activated extensions.
*
* @return array
*/
public function getExtensions()
{
return $this->extensions;
}
/**
* Returns activated extension classes.
*
* @return array
*/
public function getExtensionClasses()
{
return array_unique(
array_map(
function($extension) {
return get_class($extension);
},
$this->extensions
)
);
}
/**
* Initializes extension by id.
*
* @param string $id
*
* @return ExtensionInterface
*
* @throws \RuntimeException
*/
protected function initializeExtension($id)
{
$extension = null;
if (class_exists($id)) {
$extension = new $id;
} elseif (file_exists($this->basePath.DIRECTORY_SEPARATOR.$id)) {
$extension = require($this->basePath.DIRECTORY_SEPARATOR.$id);
} else {
$extension = require($id);
}
if (null === $extension) {
throw new \RuntimeException(sprintf(
'"%s" extension could not be found.', $id
));
}
if (!is_object($extension)) {
throw new \RuntimeException(sprintf(
'"%s" extension could not be initialized.', $id
));
}
if (!$extension instanceof ExtensionInterface) {
throw new \RuntimeException(sprintf(
'"%s" extension class should implement ExtensionInterface.',
get_class($extension)
));
}
return $extension;
}
}
<?php
namespace Behat\Behat\Formatter;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag,
Symfony\Component\EventDispatcher\EventDispatcher,
Symfony\Component\EventDispatcher\Event,
Symfony\Component\Translation\Translator,
Symfony\Component\Console\Output\StreamOutput,
Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Behat\Behat\Event\StepEvent,
Behat\Behat\Exception\FormatterException,
Behat\Behat\Console\Formatter\OutputFormatter;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Console formatter.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class ConsoleFormatter implements FormatterInterface
{
/**
* Formatter parameters.
*
* @var ParameterBag
*/
protected $parameters;
private $translator;
private $console;
/**
* Initialize formatter.
*
* @uses getDefaultParameters()
*/
public function __construct()
{
$defaultLanguage = null;
if (($locale = getenv('LANG')) && preg_match('/^([a-z]{2})/', $locale, $matches)) {
$defaultLanguage = $matches[1];
}
$this->parameters = new ParameterBag(array_merge(array(
'language' => $defaultLanguage,
'verbose' => false,
'decorated' => true,
'time' => true,
'base_path' => null,
'support_path' => null,
'output' => null,
'output_path' => null,
'output_styles' => array(),
'output_decorate' => null,
'snippets' => true,
'snippets_paths' => false,
'paths' => true,
'expand' => false,
'multiline_arguments' => true,
), $this->getDefaultParameters()));
}
/**
* Set formatter translator.
*
* @param Translator $translator
*/
final public function setTranslator(Translator $translator)
{
$this->translator = $translator;
}
/**
* Returns default parameters to construct ParameterBag.
*
* @return array
*/
abstract protected function getDefaultParameters();
/**
* Checks if current formatter has parameter.
*
* @param string $name
*
* @return Boolean
*/
final public function hasParameter($name)
{
return $this->parameters->has($name);
}
/**
* Sets formatter parameter.
*
* @param string $name
* @param mixed $value
*/
final public function setParameter($name, $value)
{
$this->parameters->set($name, $value);
}
/**
* Returns parameter value.
*
* @param string $name
*
* @return mixed
*/
final public function getParameter($name)
{
return $this->parameters->get($name);
}
/**
* Returns color code from tester result status code.
*
* @param integer $result tester result status code
*
* @return string passed|pending|skipped|undefined|failed
*/
final protected function getResultColorCode($result)
{
switch ($result) {
case StepEvent::PASSED: return 'passed';
case StepEvent::SKIPPED: return 'skipped';
case StepEvent::PENDING: return 'pending';
case StepEvent::UNDEFINED: return 'undefined';
case StepEvent::FAILED: return 'failed';
}
}
/**
* Writes message(s) to output console.
*
* @param string|array $messages message or array of messages
* @param Boolean $newline do we need to append newline after messages
*
* @uses getWritingConsole()
*/
final protected function write($messages, $newline = false)
{
$this->getWritingConsole()->write($messages, $newline);
}
/**
* Writes newlined message(s) to output console.
*
* @param string|array $messages message or array of messages
*/
final protected function writeln($messages = '')
{
$this->write($messages, true);
}
/**
* Returns console instance, prepared to write.
*
* @return StreamOutput
*
* @uses createOutputConsole()
* @uses configureOutputConsole()
*/
final protected function getWritingConsole()
{
if (null === $this->console) {
$this->console = $this->createOutputConsole();
}
$this->configureOutputConsole($this->console);
return $this->console;
}
/**
* Returns new output stream for console.
*
* Override this method & call flushOutputConsole() to write output in another stream
*
* @return resource
*
* @throws FormatterException
*/
protected function createOutputStream()
{
if (is_resource($stream = $this->parameters->get('output'))) {
return $stream;
}
$outputPath = $this->parameters->get('output_path');
if (null === $outputPath) {
$stream = fopen('php://stdout', 'w');
} elseif (!is_dir($outputPath)) {
$stream = fopen($outputPath, 'w');
} else {
throw new FormatterException(sprintf(
'Filename expected as "output_path" parameter of "%s" formatter, but got: "%s"',
basename(str_replace('\\', '/', get_class($this))), $outputPath
));
}
return $stream;
}
/**
* Returns new output console.
*
* @return StreamOutput
*
* @uses createOutputStream()
*/
protected function createOutputConsole()
{
$stream = $this->createOutputStream();
$format = new OutputFormatter();
// set user-defined styles
foreach ($this->parameters->get('output_styles') as $name => $options) {
$style = new OutputFormatterStyle();
if (isset($options[0])) {
$style->setForeground($options[0]);
}
if (isset($options[1])) {
$style->setBackground($options[1]);
}
if (isset($options[2])) {
$style->setOptions($options[2]);
}
$format->setStyle($name, $style);
}
return new StreamOutput(
$stream, StreamOutput::VERBOSITY_NORMAL, $this->parameters->get('output_decorate'), $format
);
}
/**
* Configure output console parameters.
*
* @param StreamOutput $console
*/
protected function configureOutputConsole(StreamOutput $console)
{
$console->setVerbosity(
$this->parameters->get('verbose') ? StreamOutput::VERBOSITY_VERBOSE : StreamOutput::VERBOSITY_NORMAL
);
$console->getFormatter()->setDecorated(
$this->parameters->get('decorated')
);
}
/**
* Clear output console, so on next write formatter will need to init (create) it again.
*
* @see createOutputConsole()
*/
final protected function flushOutputConsole()
{
$this->console = null;
}
/**
* Translates message to output language.
*
* @param string $message message to translate
* @param array $parameters message parameters
*
* @return string
*/
final protected function translate($message, array $parameters = array())
{
return $this->translator->trans(
$message, $parameters, 'behat', $this->parameters->get('language')
);
}
/**
* Translates numbered message to output language.
*
* @param string $message message specification to translate
* @param string $number choice number
* @param array $parameters message parameters
*
* @return string
*/
final protected function translateChoice($message, $number, array $parameters = array())
{
return $this->translator->transChoice(
$message, $number, $parameters, 'behat', $this->parameters->get('language')
);
}
}
<?php
namespace Behat\Behat\Formatter;
use Behat\Behat\Event\ScenarioEvent,
Behat\Behat\Event\OutlineEvent,
Behat\Behat\Event\StepEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Failed scenarios formatter.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FailedScenariosFormatter extends ConsoleFormatter
{
/**
* {@inheritdoc}
*/
protected function getDefaultParameters()
{
return array();
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
$events = array('afterScenario', 'afterOutline');
return array_combine($events, $events);
}
/**
* Listens to "scenario.after" event.
*
* @param ScenarioEvent $event
*/
public function afterScenario(ScenarioEvent $event)
{
if (StepEvent::FAILED === $event->getResult()) {
$scenario = $event->getScenario();
$this->writeln($scenario->getFile().':'.$scenario->getLine());
}
}
/**
* Listens to "outline.after" event.
*
* @param OutlineEvent $event
*/
public function afterOutline(OutlineEvent $event)
{
if (StepEvent::FAILED === $event->getResult()) {
$outline = $event->getOutline();
$this->writeln($outline->getFile().':'.$outline->getLine());
}
}
}
<?php
namespace Behat\Behat\Formatter;
use Symfony\Component\Translation\Translator,
Symfony\Component\EventDispatcher\EventDispatcher;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Formatter dispatcher.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FormatterDispatcher
{
private $class;
private $name;
private $description;
/**
* Initializes formatter dispatcher.
*
* @param string $class Formatter class
* @param string $name Name of the formatter
* @param string $description Formatter description
*
* @throws \RuntimeException
*/
public function __construct($class, $name = null, $description = null)
{
$refClass = new \ReflectionClass($class);
if (!$refClass->implementsInterface('Behat\Behat\Formatter\FormatterInterface')) {
throw new \RuntimeException(sprintf(
'Formatter class "%s" should implement FormatterInterface', $class
));
}
$this->class = $class;
$this->name = null !== $name ? strtolower($name) : null;
$this->description = $description;
}
/**
* Returns formatter name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Returns formatter description.
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Returns formatter class.
*
* @return string
*/
public function getClass()
{
return $this->class;
}
/**
* Initializes formatter instance.
*
* @return FormatterInterface
*/
public function createFormatter()
{
$class = $this->class;
return new $class();
}
}
<?php
namespace Behat\Behat\Formatter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface,
Symfony\Component\Translation\Translator;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Formatter interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface FormatterInterface extends EventSubscriberInterface
{
/**
* Set formatter translator.
*
* @param Translator $translator
*/
public function setTranslator(Translator $translator);
/**
* Checks if current formatter has parameter.
*
* @param string $name
*
* @return Boolean
*/
public function hasParameter($name);
/**
* Sets formatter parameter.
*
* @param string $name
* @param mixed $value
*/
public function setParameter($name, $value);
/**
* Returns parameter value.
*
* @param string $name
*
* @return mixed
*/
public function getParameter($name);
}
<?php
namespace Behat\Behat\Formatter;
use Symfony\Component\Translation\Translator,
Symfony\Component\EventDispatcher\EventDispatcher;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Formatters manager.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FormatterManager
{
private $translator;
private $eventDispatcher;
private $dispatchers = array();
private $formatters = array();
/**
* Initializes format manager.
*
* @param Translator $translator
* @param EventDispatcher $eventDispatcher
*/
public function __construct(Translator $translator, EventDispatcher $eventDispatcher)
{
$this->translator = $translator;
$this->eventDispatcher = $eventDispatcher;
}
/**
* Adds formatter dispatcher to the manager.
*
* @param FormatterDispatcher $dispatcher Formatter dispatcher
*/
public function addDispatcher(FormatterDispatcher $dispatcher)
{
$this->dispatchers[$dispatcher->getName()] = $dispatcher;
}
/**
* Returns registered formatter dispatchers.
*
* @return array
*/
public function getDispatchers()
{
return $this->dispatchers;
}
/**
* Inits specific formatter class by format name.
*
* @param string $name
*
* @return array
*
* @throws \RuntimeException
*/
public function initFormatter($name)
{
$name = strtolower($name);
if (class_exists($name)) {
$dispatcher = new FormatterDispatcher($name);
} elseif (isset($this->dispatchers[$name])) {
$dispatcher = $this->dispatchers[$name];
} else {
throw new \RuntimeException("Unknown formatter: \"$name\". " .
'Available formatters are: ' . implode(', ', array_keys($this->formatterClasses))
);
}
$formatter = $dispatcher->createFormatter();
$formatter->setTranslator($this->translator);
$this->eventDispatcher->addSubscriber($formatter, -5);
return $this->formatters[] = $formatter;
}
/**
* Sets specific parameter in all initialized formatters.
*
* @param string $param
* @param mixed $value
*/
public function setFormattersParameter($param, $value)
{
foreach ($this->formatters as $formatter) {
$formatter->setParameter($param, $value);
}
}
/**
* Returns all initialized formatters.
*
* @return array
*/
public function getFormatters()
{
return $this->formatters;
}
}
<?php
namespace Behat\Behat\Formatter;
use Behat\Behat\Definition\DefinitionInterface,
Behat\Behat\DataCollector\LoggerDataCollector,
Behat\Behat\Definition\DefinitionSnippet,
Behat\Behat\Exception\UndefinedException;
use Behat\Gherkin\Node\AbstractNode,
Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\BackgroundNode,
Behat\Gherkin\Node\AbstractScenarioNode,
Behat\Gherkin\Node\OutlineNode,
Behat\Gherkin\Node\ScenarioNode,
Behat\Gherkin\Node\StepNode,
Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* HTML formatter.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class HtmlFormatter extends PrettyFormatter
{
/**
* Deffered footer template part.
*
* @var string
*/
protected $footer;
/**
* {@inheritdoc}
*/
protected function getDefaultParameters()
{
return array(
'template_path' => null
);
}
/**
* {@inheritdoc}
*/
protected function printSuiteHeader(LoggerDataCollector $logger)
{
$this->parameters->set('decorated', false);
$template = $this->getHtmlTemplate();
$header = mb_substr($template, 0, mb_strpos($template, '{{content}}'));
$this->footer = mb_substr($template, mb_strpos($template, '{{content}}') + 11);
$this->writeln($header);
}
/**
* {@inheritdoc}
*/
protected function printSuiteFooter(LoggerDataCollector $logger)
{
$this->printSummary($logger);
$this->writeln($this->footer);
}
/**
* {@inheritdoc}
*/
protected function printFeatureHeader(FeatureNode $feature)
{
$this->writeln('<div class="feature">');
parent::printFeatureHeader($feature);
}
/**
* {@inheritdoc}
*/
protected function printFeatureOrScenarioTags(AbstractNode $node)
{
if (count($tags = $node->getOwnTags())) {
$this->writeln('<ul class="tags">');
foreach ($tags as $tag) {
$this->writeln("<li>@$tag</li>");
}
$this->writeln('</ul>');
}
}
/**
* {@inheritdoc}
*/
protected function printFeatureName(FeatureNode $feature)
{
$this->writeln('<h2>');
$this->writeln('<span class="keyword">' . $feature->getKeyword() . ': </span>');
$this->writeln('<span class="title">' . $feature->getTitle() . '</span>');
$this->writeln('</h2>');
}
/**
* {@inheritdoc}
*/
protected function printFeatureDescription(FeatureNode $feature)
{
$lines = explode("\n", $feature->getDescription());
$this->writeln('<p>');
foreach ($lines as $line) {
$this->writeln(htmlspecialchars($line) . "<br />");
}
$this->writeln('</p>');
}
/**
* {@inheritdoc}
*/
protected function printFeatureFooter(FeatureNode $feature)
{
$this->writeln('</div>');
}
/**
* {@inheritdoc}
*/
protected function printBackgroundHeader(BackgroundNode $background)
{
$this->writeln('<div class="scenario background">');
$this->printScenarioName($background);
}
/**
* {@inheritdoc}
*/
protected function printBackgroundFooter(BackgroundNode $background)
{
$this->writeln('</ol>');
$this->writeln('</div>');
}
/**
* {@inheritdoc}
*/
protected function printScenarioHeader(ScenarioNode $scenario)
{
$this->writeln('<div class="scenario">');
$this->printFeatureOrScenarioTags($scenario);
$this->printScenarioName($scenario);
}
/**
* {@inheritdoc}
*/
protected function printScenarioName(AbstractScenarioNode $scenario)
{
$this->writeln('<h3>');
$this->writeln('<span class="keyword">' . $scenario->getKeyword() . ': </span>');
if ($scenario->getTitle()) {
$this->writeln('<span class="title">' . $scenario->getTitle() . '</span>');
}
$this->printScenarioPath($scenario);
$this->writeln('</h3>');
$this->writeln('<ol>');
}
/**
* {@inheritdoc}
*/
protected function printScenarioFooter(ScenarioNode $scenario)
{
$this->writeln('</ol>');
$this->writeln('</div>');
}
/**
* {@inheritdoc}
*/
protected function printOutlineHeader(OutlineNode $outline)
{
$this->writeln('<div class="scenario outline">');
$this->printFeatureOrScenarioTags($outline);
$this->printScenarioName($outline);
}
/**
* {@inheritdoc}
*/
protected function printOutlineSteps(OutlineNode $outline)
{
parent::printOutlineSteps($outline);
$this->writeln('</ol>');
}
/**
* {@inheritdoc}
*/
protected function printOutlineExamplesSectionHeader(TableNode $examples)
{
$this->writeln('<div class="examples">');
if (!$this->getParameter('expand')) {
$this->writeln('<h4>' . $examples->getKeyword() . '</h4>');
$this->writeln('<table>');
$this->writeln('<thead>');
$this->printColorizedTableRow($examples->getRow(0), 'skipped');
$this->writeln('</thead>');
$this->writeln('<tbody>');
}
}
/**
* {@inheritdoc}
*/
protected function printOutlineExampleResult(TableNode $examples, $iteration, $result, $isSkipped)
{
if (!$this->getParameter('expand')) {
$color = $this->getResultColorCode($result);
$this->printColorizedTableRow($examples->getRow($iteration + 1), $color);
$this->printOutlineExampleResultExceptions($examples, $this->delayedStepEvents);
} else {
$this->write('<h4>' . $examples->getKeyword() . ': ');
foreach ($examples->getRow($iteration + 1) as $value) {
$this->write('<span>' . $value . '</span>');
}
$this->writeln('</h4>');
foreach ($this->delayedStepEvents as $event) {
$this->writeln('<ol>');
$this->printStep(
$event->getStep(),
$event->getResult(),
$event->getDefinition(),
$event->getSnippet(),
$event->getException()
);
$this->writeln('</ol>');
}
}
}
/**
* {@inheritdoc}
*/
protected function printOutlineExampleResultExceptions(TableNode $examples, array $events)
{
$colCount = count($examples->getRow(0));
foreach ($events as $event) {
$exception = $event->getException();
if ($exception && !$exception instanceof UndefinedException) {
$error = $this->relativizePathsInString($exception->getMessage());
$this->writeln('<tr class="failed exception">');
$this->writeln('<td colspan="' . $colCount . '">');
$this->writeln('<pre class="backtrace">' . htmlspecialchars($error) . '</pre>');
$this->writeln('</td>');
$this->writeln('</tr>');
}
}
}
/**
* {@inheritdoc}
*/
protected function printOutlineFooter(OutlineNode $outline)
{
if (!$this->getParameter('expand')) {
$this->writeln('</tbody>');
$this->writeln('</table>');
}
$this->writeln('</div>');
$this->writeln('</div>');
}
/**
* {@inheritdoc}
*/
protected function printStep(StepNode $step, $result, DefinitionInterface $definition = null,
$snippet = null, \Exception $exception = null)
{
$this->writeln('<li class="' . $this->getResultColorCode($result) . '">');
parent::printStep($step, $result, $definition, $snippet, $exception);
$this->writeln('</li>');
}
/**
* {@inheritdoc}
*/
protected function printStepBlock(StepNode $step, DefinitionInterface $definition = null, $color)
{
$this->writeln('<div class="step">');
$this->printStepName($step, $definition, $color);
if (null !== $definition) {
$this->printStepDefinitionPath($step, $definition);
}
$this->writeln('</div>');
}
/**
* {@inheritdoc}
*/
protected function printStepName(StepNode $step, DefinitionInterface $definition = null, $color)
{
$type = $step->getType();
$text = $this->inOutlineSteps ? $step->getCleanText() : $step->getText();
if (null !== $definition) {
$text = $this->colorizeDefinitionArguments($text, $definition, $color);
}
$this->writeln('<span class="keyword">' . $type . ' </span>');
$this->writeln('<span class="text">' . $text . '</span>');
}
/**
* {@inheritdoc}
*/
protected function printStepDefinitionPath(StepNode $step, DefinitionInterface $definition)
{
if ($this->getParameter('paths')) {
if ($this->hasParameter('paths_base_url')) {
$this->printPathLink($definition);
} else {
$this->printPathComment($this->relativizePathsInString($definition->getPath()));
}
}
}
/**
* {@inheritdoc}
*/
protected function printStepPyStringArgument(PyStringNode $pystring, $color = null)
{
$this->writeln('<pre class="argument">' . htmlspecialchars((string) $pystring) . '</pre>');
}
/**
* {@inheritdoc}
*/
protected function printStepTableArgument(TableNode $table, $color = null)
{
$this->writeln('<table class="argument">');
$this->writeln('<thead>');
$headers = $table->getRow(0);
$this->printColorizedTableRow($headers, 'row');
$this->writeln('</thead>');
$this->writeln('<tbody>');
foreach ($table->getHash() as $row) {
$this->printColorizedTableRow($row, 'row');
}
$this->writeln('</tbody>');
$this->writeln('</table>');
}
/**
* {@inheritdoc}
*/
protected function printStepException(\Exception $exception, $color)
{
$error = $this->relativizePathsInString($exception->getMessage());
$this->writeln('<pre class="backtrace">' . htmlspecialchars($error) . '</pre>');
}
/**
* {@inheritdoc}
*/
protected function printStepSnippet(DefinitionSnippet $snippet)
{
$this->writeln('<div class="snippet"><pre>' . htmlspecialchars($snippet) . '</pre></div>');
}
/**
* {@inheritdoc}
*/
protected function colorizeDefinitionArguments($text, DefinitionInterface $definition, $color)
{
$regex = $definition->getRegex();
$paramColor = $color . '_param';
// If it's just a string - skip
if ('/' !== substr($regex, 0, 1)) {
return $text;
}
// Find arguments with offsets
$matches = array();
preg_match($regex, $text, $matches, PREG_OFFSET_CAPTURE);
array_shift($matches);
// Replace arguments with colorized ones
$shift = 0;
$lastReplacementPosition = 0;
foreach ($matches as $key => $match) {
if (!is_numeric($key) || -1 === $match[1] || false !== strpos($match[0], '<')) {
continue;
}
$offset = $match[1] + $shift;
$value = $match[0];
// Skip inner matches
if ($lastReplacementPosition > $offset) {
continue;
}
$lastReplacementPosition = $offset + strlen($value);
$begin = substr($text, 0, $offset);
$end = substr($text, $offset + strlen($value));
$format = "{+strong class=\"$paramColor\"-}%s{+/strong-}";
$text = sprintf('%s'.$format.'%s', $begin, $value, $end);
// Keep track of how many extra characters are added
$shift += strlen($format) - 2;
$lastReplacementPosition += strlen($format) - 2;
}
// Replace "<", ">" with colorized ones
$text = preg_replace('/(<[^>]+>)/', "{+strong class=\"$paramColor\"-}\$1{+/strong-}", $text);
$text = htmlspecialchars($text, ENT_NOQUOTES);
$text = strtr($text, array('{+' => '<', '-}' => '>'));
return $text;
}
/**
* {@inheritdoc}
*/
protected function printColorizedTableRow($row, $color)
{
$this->writeln('<tr class="' . $color . '">');
foreach ($row as $column) {
$this->writeln('<td>' . $column . '</td>');
}
$this->writeln('</tr>');
}
/**
* Prints path link, which links to the source containing the step definition.
*
* @param DefinitionInterface $definition
*/
protected function printPathLink(DefinitionInterface $definition)
{
$url = $this->getParameter('paths_base_url')
. $this->relativizePathsInString($definition->getCallbackReflection()->getFileName());
$path = $this->relativizePathsInString($definition->getPath());
$this->writeln('<span class="path"><a href="' . $url . '">' . $path . '</a></span>');
}
/**
* {@inheritdoc}
*/
protected function printPathComment($path, $indentCount = 0)
{
$this->writeln('<span class="path">' . $path . '</span>');
}
/**
* {@inheritdoc}
*/
protected function printSummary(LoggerDataCollector $logger)
{
$results = $logger->getScenariosStatuses();
$result = $results['failed'] > 0 ? 'failed' : 'passed';
$this->writeln('<div class="summary '.$result.'">');
$this->writeln('<div class="counters">');
parent::printSummary($logger);
$this->writeln('</div>');
$this->writeln(<<<'HTML'
<div class="switchers">
<a href="javascript:void(0)" id="behat_show_all">[+] all</a>
<a href="javascript:void(0)" id="behat_hide_all">[-] all</a>
</div>
HTML
);
$this->writeln('</div>');
}
/**
* {@inheritdoc}
*/
protected function printScenariosSummary(LoggerDataCollector $logger)
{
$this->writeln('<p class="scenarios">');
parent::printScenariosSummary($logger);
$this->writeln('</p>');
}
/**
* {@inheritdoc}
*/
protected function printStepsSummary(LoggerDataCollector $logger)
{
$this->writeln('<p class="steps">');
parent::printStepsSummary($logger);
$this->writeln('</p>');
}
/**
* {@inheritdoc}
*/
protected function printTimeSummary(LoggerDataCollector $logger)
{
$this->writeln('<p class="time">');
parent::printTimeSummary($logger);
$this->writeln('</p>');
}
/**
* {@inheritdoc}
*/
protected function printStatusesSummary(array $statusesStatistics)
{
$statuses = array();
$statusTpl = '<strong class="%s">%s</strong>';
foreach ($statusesStatistics as $status => $count) {
if ($count) {
$transStatus = $this->translateChoice(
"{$status}_count", $count, array('%1%' => $count)
);
$statuses[] = sprintf($statusTpl, $status, $transStatus);
}
}
if (count($statuses)) {
$this->writeln(' ('.implode(', ', $statuses).')');
}
}
/**
* Get HTML template.
*
* @return string
*/
protected function getHtmlTemplate()
{
$templatePath = $this->parameters->get('template_path')
?: $this->parameters->get('support_path') . DIRECTORY_SEPARATOR . 'html.tpl';
if (file_exists($templatePath)) {
return file_get_contents($templatePath);
}
return
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns ="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html;charset=utf-8"/>
<title>Behat Test Suite</title>
<style type="text/css">
' . $this->getHtmlTemplateStyle() . '
</style>
<style type="text/css" media="print">
' . $this->getHtmlTemplatePrintStyle() . '
</style>
</head>
<body>
<div id="behat">
{{content}}
</div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script type="text/javascript">
' . $this->getHtmlTemplateScript() . '
</script>
</body>
</html>';
}
/**
* Get HTML template style.
*
* @return string
*/
protected function getHtmlTemplateStyle()
{
return <<<'HTMLTPL'
body {
margin:0px;
padding:0px;
position:relative;
padding-top:75px;
}
#behat {
float:left;
font-family: Georgia, serif;
font-size:18px;
line-height:26px;
width:100%;
}
#behat .statistics {
float:left;
width:100%;
margin-bottom:15px;
}
#behat .statistics p {
text-align:right;
padding:5px 15px;
margin:0px;
border-right:10px solid #000;
}
#behat .statistics.failed p {
border-color:#C20000;
}
#behat .statistics.passed p {
border-color:#3D7700;
}
#behat .feature {
margin:15px;
}
#behat h2, #behat h3, #behat h4 {
margin:0px 0px 5px 0px;
padding:0px;
font-family:Georgia;
}
#behat h2 .title, #behat h3 .title, #behat h4 .title {
font-weight:normal;
}
#behat .path {
font-size:10px;
font-weight:normal;
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Courier, monospace !important;
color:#999;
padding:0px 5px;
float:right;
}
#behat .path a:link,
#behat .path a:visited {
color:#999;
}
#behat .path a:hover,
#behat .path a:active {
background-color:#000;
color:#fff;
}
#behat h3 .path {
margin-right:4%;
}
#behat ul.tags {
font-size:14px;
font-weight:bold;
color:#246AC1;
list-style:none;
margin:0px;
padding:0px;
}
#behat ul.tags li {
display:inline;
}
#behat ul.tags li:after {
content:' ';
}
#behat ul.tags li:last-child:after {
content:'';
}
#behat .feature > p {
margin-top:0px;
margin-left:20px;
}
#behat .scenario {
margin-left:20px;
margin-bottom:20px;
}
#behat .scenario > ol,
#behat .scenario .examples > ol {
margin:0px;
list-style:none;
padding:0px;
}
#behat .scenario > ol {
margin-left:20px;
}
#behat .scenario > ol:after,
#behat .scenario .examples > ol:after {
content:'';
display:block;
clear:both;
}
#behat .scenario > ol li,
#behat .scenario .examples > ol li {
float:left;
width:95%;
padding-left:5px;
border-left:5px solid;
margin-bottom:4px;
}
#behat .scenario > ol li .argument,
#behat .scenario .examples > ol li .argument {
margin:10px 20px;
font-size:16px;
overflow:hidden;
}
#behat .scenario > ol li table.argument,
#behat .scenario .examples > ol li table.argument {
border:1px solid #d2d2d2;
}
#behat .scenario > ol li table.argument thead td,
#behat .scenario .examples > ol li table.argument thead td {
font-weight: bold;
}
#behat .scenario > ol li table.argument td,
#behat .scenario .examples > ol li table.argument td {
padding:5px 10px;
background:#f3f3f3;
}
#behat .scenario > ol li .keyword,
#behat .scenario .examples > ol li .keyword {
font-weight:bold;
}
#behat .scenario > ol li .path,
#behat .scenario .examples > ol li .path {
float:right;
}
#behat .scenario .examples {
margin-top:20px;
margin-left:40px;
}
#behat .scenario .examples h4 span {
font-weight:normal;
background:#f3f3f3;
color:#999;
padding:0 5px;
margin-left:10px;
}
#behat .scenario .examples table {
margin-left:20px;
}
#behat .scenario .examples table thead td {
font-weight:bold;
text-align:center;
}
#behat .scenario .examples table td {
padding:2px 10px;
font-size:16px;
}
#behat .scenario .examples table .failed.exception td {
border-left:5px solid #000;
border-color:#C20000 !important;
padding-left:0px;
}
pre {
font-family:monospace;
}
.snippet {
font-size:14px;
color:#000;
margin-left:20px;
}
.backtrace {
font-size:12px;
line-height:18px;
color:#000;
overflow:hidden;
margin-left:20px;
padding:15px;
border-left:2px solid #C20000;
background: #fff;
margin-right:15px;
}
#behat .passed {
background:#DBFFB4;
border-color:#65C400 !important;
color:#3D7700;
}
#behat .failed {
background:#FFFBD3;
border-color:#C20000 !important;
color:#C20000;
}
#behat .undefined, #behat .pending {
border-color:#FAF834 !important;
background:#FCFB98;
color:#000;
}
#behat .skipped {
background:lightCyan;
border-color:cyan !important;
color:#000;
}
#behat .summary {
position: absolute;
top: 0px;
left: 0px;
width:100%;
font-family: Arial, sans-serif;
font-size: 14px;
line-height: 18px;
}
#behat .summary .counters {
padding: 10px;
border-top: 0px;
border-bottom: 0px;
border-right: 0px;
border-left: 5px;
border-style: solid;
height: 52px;
overflow: hidden;
}
#behat .summary .switchers {
position: absolute;
right: 15px;
top: 25px;
}
#behat .summary .switcher {
text-decoration: underline;
cursor: pointer;
}
#behat .summary .switchers a {
margin-left: 10px;
color: #000;
}
#behat .summary .switchers a:hover {
text-decoration:none;
}
#behat .summary p {
margin:0px;
}
#behat .jq-toggle > .scenario,
#behat .jq-toggle > ol,
#behat .jq-toggle > .examples {
display:none;
}
#behat .jq-toggle-opened > .scenario,
#behat .jq-toggle-opened > ol,
#behat .jq-toggle-opened > .examples {
display:block;
}
#behat .jq-toggle > h2,
#behat .jq-toggle > h3 {
cursor:pointer;
}
#behat .jq-toggle > h2:after,
#behat .jq-toggle > h3:after {
content:' |+';
font-weight:bold;
}
#behat .jq-toggle-opened > h2:after,
#behat .jq-toggle-opened > h3:after {
content:' |-';
font-weight:bold;
}
HTMLTPL;
}
/**
* Get HTML template style.
*
* @return string
*/
protected function getHtmlTemplatePrintStyle()
{
return <<<'HTMLTPL'
body {
padding:0px;
}
#behat {
font-size:11px;
}
#behat .jq-toggle > .scenario,
#behat .jq-toggle > .scenario .examples,
#behat .jq-toggle > ol {
display:block;
}
#behat .summary {
position:relative;
}
#behat .summary .counters {
border:none;
}
#behat .summary .switchers {
display:none;
}
#behat .step .path {
display:none;
}
#behat .jq-toggle > h2:after,
#behat .jq-toggle > h3:after {
content:'';
font-weight:bold;
}
#behat .jq-toggle-opened > h2:after,
#behat .jq-toggle-opened > h3:after {
content:'';
font-weight:bold;
}
#behat .scenario > ol li,
#behat .scenario .examples > ol li {
border-left:none;
}
HTMLTPL;
}
/**
* Get HTML template script.
*
* @return string
*/
protected function getHtmlTemplateScript()
{
return <<<'HTMLTPL'
$(document).ready(function(){
$('#behat .feature h2').click(function(){
$(this).parent().toggleClass('jq-toggle-opened');
}).parent().addClass('jq-toggle');
$('#behat .scenario h3').click(function(){
$(this).parent().toggleClass('jq-toggle-opened');
}).parent().addClass('jq-toggle');
$('#behat_show_all').click(function(){
$('#behat .feature').addClass('jq-toggle-opened');
$('#behat .scenario').addClass('jq-toggle-opened');
});
$('#behat_hide_all').click(function(){
$('#behat .feature').removeClass('jq-toggle-opened');
$('#behat .scenario').removeClass('jq-toggle-opened');
});
$('#behat .summary .counters .scenarios .passed')
.addClass('switcher')
.click(function(){
var $scenario = $('.feature .scenario:not(:has(.failed, .pending))');
var $feature = $scenario.parent();
$('#behat_hide_all').click();
$scenario.addClass('jq-toggle-opened');
$feature.addClass('jq-toggle-opened');
});
$('#behat .summary .counters .steps .passed')
.addClass('switcher')
.click(function(){
var $scenario = $('.feature .scenario:has(.passed)');
var $feature = $scenario.parent();
$('#behat_hide_all').click();
$scenario.addClass('jq-toggle-opened');
$feature.addClass('jq-toggle-opened');
});
$('#behat .summary .counters .failed')
.addClass('switcher')
.click(function(){
var $scenario = $('.feature .scenario:has(.failed)');
var $feature = $scenario.parent();
$('#behat_hide_all').click();
$scenario.addClass('jq-toggle-opened');
$feature.addClass('jq-toggle-opened');
});
$('#behat .summary .counters .skipped')
.addClass('switcher')
.click(function(){
var $scenario = $('.feature .scenario:has(.skipped)');
var $feature = $scenario.parent();
$('#behat_hide_all').click();
$scenario.addClass('jq-toggle-opened');
$feature.addClass('jq-toggle-opened');
});
$('#behat .summary .counters .pending')
.addClass('switcher')
.click(function(){
var $scenario = $('.feature .scenario:has(.pending)');
var $feature = $scenario.parent();
$('#behat_hide_all').click();
$scenario.addClass('jq-toggle-opened');
$feature.addClass('jq-toggle-opened');
});
});
HTMLTPL;
}
}
<?php
namespace Behat\Behat\Formatter;
use Behat\Behat\Event\EventInterface,
Behat\Behat\Event\FeatureEvent,
Behat\Behat\Event\ScenarioEvent,
Behat\Behat\Event\OutlineExampleEvent,
Behat\Behat\Event\StepEvent;
use Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\ScenarioNode,
Behat\Gherkin\Node\StepNode,
Behat\Behat\Exception\FormatterException;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Progress formatter.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class JUnitFormatter extends ConsoleFormatter
{
/**
* Current XML filename.
*
* @var string
*/
protected $filename;
/**
* Test cases.
*
* @var array
*/
protected $testcases = array();
/**
* Total steps count.
*
* @var integer
*/
protected $stepsCount = 0;
/**
* Total exceptions count.
*
* @var integer
*/
protected $exceptionsCount = 0;
/**
* Step exceptions.
*
* @var array
*/
protected $exceptions = array();
/**
* Feature start time.
*
* @var float
*/
protected $featureStartTime;
/**
* Scenario start time.
*
* @var float
*/
protected $scenarioStartTime;
/**
* {@inheritdoc}
*/
protected function getDefaultParameters()
{
return array();
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
$events = array(
'beforeFeature', 'afterFeature', 'beforeScenario', 'afterScenario',
'beforeOutlineExample', 'afterOutlineExample', 'afterStep'
);
return array_combine($events, $events);
}
/**
* Listens to "feature.before" event.
*
* @param FeatureEvent $event
*
* @uses printTestSuiteHeader()
*/
public function beforeFeature(FeatureEvent $event)
{
$feature = $event->getFeature();
$this->filename = 'TEST-' . basename($feature->getFile(), '.feature') . '.xml';
$this->printTestSuiteHeader($feature);
$this->stepsCount = 0;
$this->testcases = array();
$this->exceptionsCount = 0;
$this->featureStartTime = microtime(true);
}
/**
* Listens to "feature.after" event.
*
* @param FeatureEvent $event
*
* @uses printTestSuiteFooter()
* @uses flushOutputConsole()
*/
public function afterFeature(FeatureEvent $event)
{
$this->printTestSuiteFooter($event->getFeature(), microtime(true) - $this->featureStartTime);
$this->flushOutputConsole();
}
/**
* Listens to "scenario.before" event.
*
* @param ScenarioEvent $event
*/
public function beforeScenario(ScenarioEvent $event)
{
$this->scenarioStartTime = microtime(true);
}
/**
* Listens to "scenario.after" event.
*
* @param ScenarioEvent $event
*
* @uses printTestCase()
*/
public function afterScenario(ScenarioEvent $event)
{
$this->printTestCase($event->getScenario(), microtime(true) - $this->scenarioStartTime, $event);
}
/**
* Listens to "outline.example.before" event.
*
* @param OutlineExampleEvent $event
*/
public function beforeOutlineExample(OutlineExampleEvent $event)
{
$this->scenarioStartTime = microtime(true);
}
/**
* Listens to "outline.example.after" event.
*
* @param OutlineExampleEvent $event
*
* @uses printTestCase()
*/
public function afterOutlineExample(OutlineExampleEvent $event)
{
$this->printTestCase($event->getOutline(), microtime(true) - $this->scenarioStartTime, $event);
}
/**
* Listens to "step.after" event.
*
* @param StepEvent $event
*/
public function afterStep(StepEvent $event)
{
if ($event->hasException()) {
$this->exceptions[] = $event->getException();
$this->exceptionsCount++;
}
++$this->stepsCount;
}
/**
* Prints testsuite header.
*
* @param FeatureNode $feature
*/
protected function printTestSuiteHeader(FeatureNode $feature)
{
$this->writeln('<?xml version="1.0" encoding="UTF-8"?>');
}
/**
* Prints testsuite footer.
*
* @param FeatureNode $feature
* @param float $time
*/
protected function printTestSuiteFooter(FeatureNode $feature, $time)
{
$suiteStats = sprintf('classname="behat.features" errors="0" failures="%d" name="%s" file="%s" tests="%d" time="%F"',
$this->exceptionsCount,
htmlspecialchars($feature->getTitle()),
htmlspecialchars($feature->getFile()),
$this->stepsCount,
$time
);
$this->writeln("<testsuite $suiteStats>");
$this->writeln(implode("\n", $this->testcases));
$this->writeln('</testsuite>');
}
/**
* Prints testcase.
*
* @param ScenarioNode $scenario
* @param float $time
* @param EventInterface $event
*/
protected function printTestCase(ScenarioNode $scenario, $time, EventInterface $event)
{
$className = $scenario->getFeature()->getTitle();
$name = $scenario->getTitle();
$name .= $event instanceof OutlineExampleEvent
? ', Ex #' . ($event->getIteration() + 1)
: '';
$caseStats = sprintf('classname="%s" name="%s" time="%F"',
htmlspecialchars($className),
htmlspecialchars($name),
$time
);
$xml = " <testcase $caseStats>\n";
foreach ($this->exceptions as $exception) {
$xml .= sprintf(
' <failure message="%s" type="%s">',
htmlspecialchars($exception->getMessage()),
$this->getResultColorCode($event->getResult())
);
$exception = str_replace(array('<![CDATA[', ']]>'), '', (string) $exception);
$xml .= "<![CDATA[\n$exception\n]]></failure>\n";
}
$this->exceptions = array();
$xml .= " </testcase>";
$this->testcases[] = $xml;
}
/**
* {@inheritdoc}
*/
protected function createOutputStream()
{
$outputPath = $this->parameters->get('output_path');
if (null === $outputPath) {
throw new FormatterException(sprintf(
'You should specify "output_path" parameter for %s', get_class($this)
));
} elseif (is_file($outputPath)) {
throw new FormatterException(sprintf(
'Directory path expected as "output_path" parameter of %s, but got: %s',
get_class($this),
$outputPath
));
}
if (!is_dir($outputPath)) {
mkdir($outputPath, 0777, true);
}
return fopen($outputPath . DIRECTORY_SEPARATOR . $this->filename, 'w');
}
}
<?php
namespace Behat\Behat\Formatter;
use Behat\Behat\Definition\DefinitionInterface,
Behat\Behat\Definition\DefinitionSnippet,
Behat\Behat\DataCollector\LoggerDataCollector,
Behat\Behat\Event\SuiteEvent,
Behat\Behat\Event\FeatureEvent,
Behat\Behat\Event\ScenarioEvent,
Behat\Behat\Event\BackgroundEvent,
Behat\Behat\Event\OutlineEvent,
Behat\Behat\Event\OutlineExampleEvent,
Behat\Behat\Event\StepEvent,
Behat\Behat\Event\EventInterface,
Behat\Behat\Exception\UndefinedException;
use Behat\Gherkin\Node\AbstractNode,
Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\BackgroundNode,
Behat\Gherkin\Node\AbstractScenarioNode,
Behat\Gherkin\Node\OutlineNode,
Behat\Gherkin\Node\ScenarioNode,
Behat\Gherkin\Node\StepNode,
Behat\Gherkin\Node\ExampleStepNode,
Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Pretty formatter.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class PrettyFormatter extends ProgressFormatter
{
/**
* Maximum line length.
*
* @var integer
*/
protected $maxLineLength = 0;
/**
* Are we in background.
*
* @var Boolean
*/
protected $inBackground = false;
/**
* Is background printed.
*
* @var Boolean
*/
protected $isBackgroundPrinted = false;
/**
* Are we in outline steps.
*
* @var Boolean
*/
protected $inOutlineSteps = false;
/**
* Are we in outline example.
*
* @var Boolean
*/
protected $inOutlineExample = false;
/**
* Is outline headline printed.
*
* @var Boolean
*/
protected $isOutlineHeaderPrinted = false;
/**
* Delayed scenario event.
*
* @var EventInterface
*/
protected $delayedScenarioEvent;
/**
* Delayed step events.
*
* @var array
*/
protected $delayedStepEvents = array();
/**
* Current step indentation.
*
* @var integer
*/
protected $stepIndent = ' ';
/**
* {@inheritdoc}
*/
protected function getDefaultParameters()
{
return array();
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
$events = array(
'beforeSuite', 'afterSuite', 'beforeFeature', 'afterFeature', 'beforeScenario',
'afterScenario', 'beforeBackground', 'afterBackground', 'beforeOutline', 'afterOutline',
'beforeOutlineExample', 'afterOutlineExample', 'afterStep'
);
return array_combine($events, $events);
}
/**
* Listens to "suite.before" event.
*
* @param SuiteEvent $event
*
* @uses printSuiteHeader()
*/
public function beforeSuite(SuiteEvent $event)
{
$this->printSuiteHeader($event->getLogger());
}
/**
* Listens to "suite.after" event.
*
* @param SuiteEvent $event
*
* @uses printSuiteFooter()
*/
public function afterSuite(SuiteEvent $event)
{
$this->printSuiteFooter($event->getLogger());
}
/**
* Listens to "feature.before" event.
*
* @param FeatureEvent $event
*
* @uses printFeatureHeader()
*/
public function beforeFeature(FeatureEvent $event)
{
$this->isBackgroundPrinted = false;
$this->printFeatureHeader($event->getFeature());
}
/**
* Listens to "feature.after" event.
*
* @param FeatureEvent $event
*
* @uses printFeatureFooter()
*/
public function afterFeature(FeatureEvent $event)
{
$this->printFeatureFooter($event->getFeature());
}
/**
* Listens to "background.before" event.
*
* @param BackgroundEvent $event
*
* @uses printBackgroundHeader()
*/
public function beforeBackground(BackgroundEvent $event)
{
$this->inBackground = true;
if ($this->isBackgroundPrinted) {
return;
}
$this->printBackgroundHeader($event->getBackground());
}
/**
* Listens to "background.after" event.
*
* @param BackgroundEvent $event
*
* @uses printBackgroundFooter()
*/
public function afterBackground(BackgroundEvent $event)
{
$this->inBackground = false;
if ($this->isBackgroundPrinted) {
return;
}
$this->isBackgroundPrinted = true;
$this->printBackgroundFooter($event->getBackground());
if (null !== $this->delayedScenarioEvent) {
$method = $this->delayedScenarioEvent[0];
$event = $this->delayedScenarioEvent[1];
$this->$method($event);
}
}
/**
* Listens to "outline.before" event.
*
* @param OutlineEvent $event
*
* @uses printOutlineHeader()
*/
public function beforeOutline(OutlineEvent $event)
{
$outline = $event->getOutline();
if (!$this->isBackgroundPrinted && $outline->getFeature()->hasBackground()) {
$this->delayedScenarioEvent = array(__FUNCTION__, $event);
return;
}
$this->isOutlineHeaderPrinted = false;
$this->printOutlineHeader($outline);
}
/**
* Listens to "outline.example.before" event.
*
* @param OutlineExampleEvent $event
*
* @uses printOutlineExampleHeader()
*/
public function beforeOutlineExample(OutlineExampleEvent $event)
{
$this->inOutlineExample = true;
$this->delayedStepEvents = array();
$this->printOutlineExampleHeader($event->getOutline(), $event->getIteration());
}
/**
* Listens to "outline.example.after" event.
*
* @param OutlineExampleEvent $event
*
* @uses printOutlineExampleFooter()
*/
public function afterOutlineExample(OutlineExampleEvent $event)
{
$this->inOutlineExample = false;
$this->printOutlineExampleFooter(
$event->getOutline(), $event->getIteration(), $event->getResult(), $event->isSkipped()
);
}
/**
* Listens to "outline.after" event.
*
* @param OutlineEvent $event
*
* @uses printOutlineFooter()
*/
public function afterOutline(OutlineEvent $event)
{
$this->printOutlineFooter($event->getOutline());
}
/**
* Listens to "scenario.before" event.
*
* @param ScenarioEvent $event
*
* @uses printScenarioHeader()
*/
public function beforeScenario(ScenarioEvent $event)
{
$scenario = $event->getScenario();
if (!$this->isBackgroundPrinted && $scenario->getFeature()->hasBackground()) {
$this->delayedScenarioEvent = array(__FUNCTION__, $event);
return;
}
$this->printScenarioHeader($scenario);
}
/**
* Listens to "scenario.after" event.
*
* @param ScenarioEvent $event
*
* @uses printScenarioFooter()
*/
public function afterScenario(ScenarioEvent $event)
{
$this->printScenarioFooter($event->getScenario());
}
/**
* Listens to "step.after" event.
*
* @param StepEvent $event
*
* @uses printStep()
*/
public function afterStep(StepEvent $event)
{
if ($this->inBackground && $this->isBackgroundPrinted) {
return;
}
if (!$this->inBackground && $this->inOutlineExample) {
$this->delayedStepEvents[] = $event;
return;
}
$this->printStep(
$event->getStep(),
$event->getResult(),
$event->getDefinition(),
$event->getSnippet(),
$event->getException()
);
}
/**
* Prints feature header.
*
* @param FeatureNode $feature
*
* @uses printFeatureOrScenarioTags()
* @uses printFeatureName()
* @uses printFeatureDescription()
*/
protected function printFeatureHeader(FeatureNode $feature)
{
$this->printFeatureOrScenarioTags($feature);
$this->printFeatureName($feature);
if (null !== $feature->getDescription()) {
$this->printFeatureDescription($feature);
}
$this->writeln();
}
/**
* Prints node tags.
*
* @param AbstractNode $node
*/
protected function printFeatureOrScenarioTags(AbstractNode $node)
{
if (count($tags = $node->getOwnTags())) {
$tags = implode(' ', array_map(function($tag){
return '@' . $tag;
}, $tags));
if ($node instanceof FeatureNode) {
$indent = '';
} else {
$indent = ' ';
}
$this->writeln("$indent{+tag}$tags{-tag}");
}
}
/**
* Prints feature keyword and name.
*
* @param FeatureNode $feature
*
* @uses getFeatureOrScenarioName()
*/
protected function printFeatureName(FeatureNode $feature)
{
$this->writeln($this->getFeatureOrScenarioName($feature));
}
/**
* Prints feature description.
*
* @param FeatureNode $feature
*/
protected function printFeatureDescription(FeatureNode $feature)
{
$lines = explode("\n", $feature->getDescription());
foreach ($lines as $line) {
$this->writeln(" $line");
}
}
/**
* Prints feature footer.
*
* @param FeatureNode $feature
*/
protected function printFeatureFooter(FeatureNode $feature)
{
}
/**
* Prints scenario keyword and name.
*
* @param AbstractScenarioNode $scenario
*
* @uses getFeatureOrScenarioName()
* @uses printScenarioPath()
*/
protected function printScenarioName(AbstractScenarioNode $scenario)
{
$title = explode("\n", $this->getFeatureOrScenarioName($scenario));
$this->write(array_shift($title));
$this->printScenarioPath($scenario);
if (count($title)) {
$this->writeln(implode("\n", $title));
}
}
/**
* Prints scenario definition path.
*
* @param AbstractScenarioNode $scenario
*
* @uses getFeatureOrScenarioName()
* @uses printPathComment()
*/
protected function printScenarioPath(AbstractScenarioNode $scenario)
{
if ($this->getParameter('paths')) {
$lines = explode("\n", $this->getFeatureOrScenarioName($scenario));
$nameLength = mb_strlen(current($lines));
$indentCount = $nameLength > $this->maxLineLength ? 0 : $this->maxLineLength - $nameLength;
$this->printPathComment(
$this->relativizePathsInString($scenario->getFile()).':'.$scenario->getLine(), $indentCount
);
} else {
$this->writeln();
}
}
/**
* Prints background header.
*
* @param BackgroundNode $background
*
* @uses printScenarioName()
* @uses printScenarioPath()
*/
protected function printBackgroundHeader(BackgroundNode $background)
{
$this->maxLineLength = $this->getMaxLineLength($this->maxLineLength, $background);
$this->printScenarioName($background);
}
/**
* Prints background footer.
*
* @param BackgroundNode $background
*/
protected function printBackgroundFooter(BackgroundNode $background)
{
$this->writeln();
}
/**
* Prints outline header.
*
* @param OutlineNode $outline
*
* @uses printFeatureOrScenarioTags()
* @uses printScenarioName()
*/
protected function printOutlineHeader(OutlineNode $outline)
{
$this->maxLineLength = $this->getMaxLineLength($this->maxLineLength, $outline);
$this->printFeatureOrScenarioTags($outline);
$this->printScenarioName($outline);
}
/**
* Prints outline footer.
*
* @param OutlineNode $outline
*/
protected function printOutlineFooter(OutlineNode $outline)
{
$this->writeln();
}
/**
* Prints outline example header.
*
* @param OutlineNode $outline
* @param integer $iteration
*/
protected function printOutlineExampleHeader(OutlineNode $outline, $iteration)
{
}
/**
* Prints outline example result.
*
* @param OutlineNode $outline outline instance
* @param integer $iteration example row number
* @param integer $result result code
* @param Boolean $skipped is outline example skipped
*
* @uses printOutlineSteps()
* @uses printOutlineExamplesSectionHeader()
* @uses printOutlineExampleResult()
*/
protected function printOutlineExampleFooter(OutlineNode $outline, $iteration, $result, $skipped)
{
if (!$this->isOutlineHeaderPrinted) {
$this->printOutlineSteps($outline);
$this->printOutlineExamplesSectionHeader($outline->getExamples());
$this->isOutlineHeaderPrinted = true;
}
$this->printOutlineExampleResult($outline->getExamples(), $iteration, $result, $skipped);
}
/**
* Prints outline steps.
*
* @param OutlineNode $outline
*/
protected function printOutlineSteps(OutlineNode $outline)
{
$this->inOutlineSteps = true;
foreach ($this->delayedStepEvents as $event) {
$this->printStep($event->getStep(), StepEvent::SKIPPED, $event->getDefinition());
}
$this->inOutlineSteps = false;
}
/**
* Prints outline examples header.
*
* @param TableNode $examples
*
* @uses printColorizedTableRow()
*/
protected function printOutlineExamplesSectionHeader(TableNode $examples)
{
$this->writeln();
$keyword = $examples->getKeyword();
if (!$this->getParameter('expand')) {
$this->writeln(" $keyword:");
$this->printColorizedTableRow($examples->getRowAsString(0), 'skipped');
}
}
/**
* Prints outline example result.
*
* @param TableNode $examples examples table
* @param integer $iteration example row
* @param integer $result result code
* @param boolean $isSkipped is outline example skipped
*
* @uses printColorizedTableRow()
* @uses printOutlineExampleResultExceptions()
*/
protected function printOutlineExampleResult(TableNode $examples, $iteration, $result, $isSkipped)
{
if (!$this->getParameter('expand')) {
$color = $this->getResultColorCode($result);
$this->printColorizedTableRow($examples->getRowAsString($iteration + 1), $color);
$this->printOutlineExampleResultExceptions($examples, $this->delayedStepEvents);
} else {
$this->write(' ' . $examples->getKeyword() . ': ');
$this->writeln('| ' . implode(' | ', $examples->getRow($iteration + 1)) . ' |');
$this->stepIndent = ' ';
foreach ($this->delayedStepEvents as $event) {
$this->printStep(
$event->getStep(),
$event->getResult(),
$event->getDefinition(),
$event->getSnippet(),
$event->getException()
);
}
$this->stepIndent = ' ';
if ($iteration < count($examples->getRows()) - 2) {
$this->writeln();
}
}
}
/**
* Prints outline example exceptions.
*
* @param TableNode $examples examples table
* @param array $events failed steps events
*/
protected function printOutlineExampleResultExceptions(TableNode $examples, array $events)
{
foreach ($events as $event) {
$exception = $event->getException();
if ($exception && !$exception instanceof UndefinedException) {
$color = $this->getResultColorCode($event->getResult());
if ($this->parameters->get('verbose')) {
$error = (string) $exception;
} else {
$error = $exception->getMessage();
}
$error = $this->relativizePathsInString($error);
$this->writeln(
" {+$color}" . strtr($error, array("\n" => "\n ")) . "{-$color}"
);
}
}
}
/**
* Prints scenario header.
*
* @param ScenarioNode $scenario
*
* @uses printFeatureOrScenarioTags()
* @uses printScenarioName()
*/
protected function printScenarioHeader(ScenarioNode $scenario)
{
$this->maxLineLength = $this->getMaxLineLength($this->maxLineLength, $scenario);
$this->printFeatureOrScenarioTags($scenario);
$this->printScenarioName($scenario);
}
/**
* Prints scenario footer.
*
* @param ScenarioNode $scenario
*/
protected function printScenarioFooter(ScenarioNode $scenario)
{
$this->writeln();
}
/**
* Prints step.
*
* @param StepNode $step step node
* @param integer $result result code
* @param DefinitionInterface $definition definition (if found one)
* @param string $snippet snippet (if step is undefined)
* @param \Exception $exception exception (if step is failed)
*
* @uses printStepBlock()
* @uses printStepArguments()
* @uses printStepException()
* @uses printStepSnippet()
*/
protected function printStep(StepNode $step, $result, DefinitionInterface $definition = null,
$snippet = null, \Exception $exception = null)
{
$color = $this->getResultColorCode($result);
$this->printStepBlock($step, $definition, $color);
if ($this->parameters->get('multiline_arguments')) {
$this->printStepArguments($step->getArguments(), $color);
}
if (null !== $exception &&
(!$exception instanceof UndefinedException || null === $snippet)) {
$this->printStepException($exception, $color);
}
if (null !== $snippet && $this->getParameter('snippets')) {
$this->printStepSnippet($snippet);
}
}
/**
* Prints step block (name & definition path).
*
* @param StepNode $step step node
* @param DefinitionInterface $definition definition (if found one)
* @param string $color color code
*
* @uses printStepName()
* @uses printStepDefinitionPath()
*/
protected function printStepBlock(StepNode $step, DefinitionInterface $definition = null, $color)
{
$this->printStepName($step, $definition, $color);
if (null !== $definition) {
$this->printStepDefinitionPath($step, $definition);
} else {
$this->writeln();
}
}
/**
* Prints step name.
*
* @param StepNode $step step node
* @param DefinitionInterface $definition definition (if found one)
* @param string $color color code
*
* @uses colorizeDefinitionArguments()
*/
protected function printStepName(StepNode $step, DefinitionInterface $definition = null, $color)
{
$type = $step->getType();
$text = $this->inOutlineSteps ? $step->getCleanText() : $step->getText();
$indent = $this->stepIndent;
if (null !== $definition) {
$text = $this->colorizeDefinitionArguments($text, $definition, $color);
}
$this->write("$indent{+$color}$type $text{-$color}");
}
/**
* Prints step definition path.
*
* @param StepNode $step step node
* @param DefinitionInterface $definition definition (if found one)
*
* @uses printPathComment()
*/
protected function printStepDefinitionPath(StepNode $step, DefinitionInterface $definition)
{
if ($this->getParameter('paths')) {
$type = $step->getType();
$text = $this->inOutlineSteps ? $step->getCleanText() : $step->getText();
$indent = $this->stepIndent;
$nameLength = mb_strlen("$indent$type $text");
$indentCount = $nameLength > $this->maxLineLength ? 0 : $this->maxLineLength - $nameLength;
$this->printPathComment(
$this->relativizePathsInString($definition->getPath()), $indentCount
);
if ($this->getParameter('expand')) {
$this->maxLineLength = max($this->maxLineLength, $nameLength);
}
} else {
$this->writeln();
}
}
/**
* Prints step arguments.
*
* @param array $arguments step arguments
* @param string $color color name
*
* @uses printStepPyStringArgument()
* @uses printStepTableArgument()
*/
protected function printStepArguments(array $arguments, $color)
{
foreach ($arguments as $argument) {
if ($argument instanceof PyStringNode) {
$this->printStepPyStringArgument($argument, $color);
} elseif ($argument instanceof TableNode) {
$this->printStepTableArgument($argument, $color);
}
}
}
/**
* Prints step exception.
*
* @param \Exception $exception
* @param string $color
*/
protected function printStepException(\Exception $exception, $color)
{
$indent = $this->stepIndent;
if ($this->parameters->get('verbose')) {
$error = (string) $exception;
} else {
$error = $exception->getMessage();
}
$error = $this->relativizePathsInString($error);
$this->writeln(
"$indent {+$color}" . strtr($error, array("\n" => "\n$indent ")) . "{-$color}"
);
}
/**
* Prints step snippet
*
* @param DefinitionSnippet $snippet
*/
protected function printStepSnippet(DefinitionSnippet $snippet)
{
}
/**
* Prints PyString argument.
*
* @param PyStringNode $pystring pystring node
* @param string $color color name
*/
protected function printStepPyStringArgument(PyStringNode $pystring, $color = null)
{
$indent = $this->stepIndent;
$string = strtr(
sprintf("$indent \"\"\"\n%s\n\"\"\"", (string) $pystring), array("\n" => "\n$indent ")
);
if (null !== $color) {
$this->writeln("{+$color}$string{-$color}");
} else {
$this->writeln($string);
}
}
/**
* Prints table argument.
*
* @param TableNode $table
* @param string $color
*/
protected function printStepTableArgument(TableNode $table, $color = null)
{
$indent = $this->stepIndent;
$string = strtr("$indent " . (string) $table, array("\n" => "\n$indent "));
if (null !== $color) {
$this->writeln("{+$color}$string{-$color}");
} else {
$this->writeln($string);
}
}
/**
* Prints table row in color.
*
* @param array $row
* @param string $color
*/
protected function printColorizedTableRow($row, $color)
{
$string = preg_replace(
'/|([^|]*)|/',
"{+$color}\$1{-$color}",
' ' . $row
);
$this->writeln($string);
}
/**
* Prints suite header.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printSuiteHeader(LoggerDataCollector $logger)
{
}
/**
* Prints suite footer information.
*
* @param LoggerDataCollector $logger suite logger
*
* @uses printSummary()
* @uses printUndefinedStepsSnippets()
*/
protected function printSuiteFooter(LoggerDataCollector $logger)
{
$this->printSummary($logger);
$this->printUndefinedStepsSnippets($logger);
}
/**
* Returns feature or scenario name.
*
* @param AbstractNode $node
* @param Boolean $haveBaseIndent
*
* @return string
*/
protected function getFeatureOrScenarioName(AbstractNode $node, $haveBaseIndent = true)
{
$keyword = $node->getKeyword();
$baseIndent = ($node instanceof FeatureNode) || !$haveBaseIndent ? '' : ' ';
$lines = explode("\n", $node->getTitle());
$title = array_shift($lines);
if (count($lines)) {
foreach ($lines as $line) {
$title .= "\n" . $baseIndent.' '.$line;
}
}
return "$baseIndent$keyword:" . ($title ? ' ' . $title : '');
}
/**
* Returns step text with colorized arguments.
*
* @param string $text
* @param DefinitionInterface $definition
* @param string $color
*
* @return string
*/
protected function colorizeDefinitionArguments($text, DefinitionInterface $definition, $color)
{
$regex = $definition->getRegex();
$paramColor = $color . '_param';
// If it's just a string - skip
if ('/' !== substr($regex, 0, 1)) {
return $text;
}
// Find arguments with offsets
$matches = array();
preg_match($regex, $text, $matches, PREG_OFFSET_CAPTURE);
array_shift($matches);
// Replace arguments with colorized ones
$shift = 0;
$lastReplacementPosition = 0;
foreach ($matches as $key => $match) {
if (!is_numeric($key) || -1 === $match[1] || false !== strpos($match[0], '<')) {
continue;
}
$offset = $match[1] + $shift;
$value = $match[0];
// Skip inner matches
if ($lastReplacementPosition > $offset) {
continue;
}
$lastReplacementPosition = $offset + strlen($value);
$begin = substr($text, 0, $offset);
$end = substr($text, $lastReplacementPosition);
$format = "{-$color}{+$paramColor}%s{-$paramColor}{+$color}";
$text = sprintf("%s{$format}%s", $begin, $value, $end);
// Keep track of how many extra characters are added
$shift += strlen($format) - 2;
$lastReplacementPosition += strlen($format) - 2;
}
// Replace "<", ">" with colorized ones
$text = preg_replace('/(<[^>]+>)/',
"{-$color}{+$paramColor}\$1{-$paramColor}{+$color}",
$text
);
return $text;
}
/**
* Returns max lines size for section elements.
*
* @param integer $max previous max value
* @param AbstractScenarioNode $scenario element for calculations
*
* @return integer
*/
protected function getMaxLineLength($max, AbstractScenarioNode $scenario)
{
$lines = explode("\n", $this->getFeatureOrScenarioName($scenario, false));
$max = max($max, mb_strlen(current($lines)) + 2);
foreach ($scenario->getSteps() as $step) {
$text = $step instanceof ExampleStepNode ? $step->getCleanText() : $step->getText();
$stepDescription = $step->getType() . ' ' . $text;
$max = max($max, mb_strlen($stepDescription) + 4);
}
return $max;
}
}
<?php
namespace Behat\Behat\Formatter;
use Symfony\Component\EventDispatcher\EventDispatcher,
Symfony\Component\EventDispatcher\Event;
use Behat\Behat\Definition\DefinitionInterface,
Behat\Behat\DataCollector\LoggerDataCollector,
Behat\Behat\Exception\PendingException,
Behat\Behat\Event\SuiteEvent,
Behat\Behat\Event\StepEvent;
use Behat\Gherkin\Node\BackgroundNode,
Behat\Gherkin\Node\StepNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Progress formatter.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ProgressFormatter extends ConsoleFormatter
{
/**
* Maximum line length.
*
* @var integer
*/
protected $maxLineLength = 0;
/**
* {@inheritdoc}
*/
protected function getDefaultParameters()
{
return array();
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
$events = array('afterSuite', 'afterStep');
return array_combine($events, $events);
}
/**
* Listens to "suite.after" event.
*
* @param SuiteEvent $event
*
* @uses printFailedSteps()
* @uses printPendingSteps()
* @uses printSummary()
* @uses printUndefinedStepsSnippets()
*/
public function afterSuite(SuiteEvent $event)
{
$logger = $event->getLogger();
$this->writeln("\n");
$this->printFailedSteps($logger);
$this->printPendingSteps($logger);
$this->printSummary($logger);
$this->printUndefinedStepsSnippets($logger);
}
/**
* Listens to "step.after" event.
*
* @param StepEvent $event
*
* @uses printStep()
*/
public function afterStep(StepEvent $event)
{
$this->printStep(
$event->getStep(),
$event->getResult(),
$event->getDefinition(),
$event->getSnippet(),
$event->getException()
);
}
/**
* Prints step.
*
* @param StepNode $step step node
* @param integer $result step result code
* @param DefinitionInterface $definition definition instance (if step defined)
* @param string $snippet snippet (if step is undefined)
* @param \Exception $exception exception (if step is failed)
*
* @uses StepEvent
*/
protected function printStep(StepNode $step, $result, DefinitionInterface $definition = null,
$snippet = null, \Exception $exception = null)
{
switch ($result) {
case StepEvent::PASSED:
$this->write('{+passed}.{-passed}');
break;
case StepEvent::SKIPPED:
$this->write('{+skipped}-{-skipped}');
break;
case StepEvent::PENDING:
$this->write('{+pending}P{-pending}');
break;
case StepEvent::UNDEFINED:
$this->write('{+undefined}U{-undefined}');
break;
case StepEvent::FAILED:
$this->write('{+failed}F{-failed}');
break;
}
}
/**
* Prints all failed steps info.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printFailedSteps(LoggerDataCollector $logger)
{
if (count($logger->getFailedStepsEvents())) {
$header = $this->translate('failed_steps_title');
$this->writeln("{+failed}(::) $header (::){-failed}\n");
$this->printExceptionEvents($logger->getFailedStepsEvents());
}
}
/**
* Prints all pending steps information.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printPendingSteps(LoggerDataCollector $logger)
{
if (count($logger->getPendingStepsEvents())) {
$header = $this->translate('pending_steps_title');
$this->writeln("{+pending}(::) $header (::){-pending}\n");
$this->printExceptionEvents($logger->getPendingStepsEvents());
}
}
/**
* Prints exceptions information.
*
* @param array $events failed step events
*/
protected function printExceptionEvents(array $events)
{
foreach ($events as $number => $event) {
$exception = $event->getException();
if (null !== $exception) {
$color = $exception instanceof PendingException ? 'pending' : 'failed';
if ($this->parameters->get('verbose')) {
$error = (string) $exception;
} else {
$error = $exception->getMessage();
}
$error = sprintf("%s. %s",
str_pad((string) ($number + 1), 2, '0', STR_PAD_LEFT),
strtr($error, array("\n" => "\n "))
);
$error = $this->relativizePathsInString($error);
$this->writeln("{+$color}$error{-$color}");
}
$this->printStepPath($event->getStep(), $event->getDefinition(), $exception);
}
}
/**
* Prints path to step.
*
* @param StepNode $step step node
* @param DefinitionInterface $definition definition (if step defined)
* @param \Exception $exception exception (if step failed)
*/
protected function printStepPath(StepNode $step, DefinitionInterface $definition = null,
\Exception $exception = null)
{
$color = $exception instanceof PendingException ? 'pending' : 'failed';
$type = $step->getType();
$text = $step->getText();
$stepPath = "In step `$type $text'.";
$stepPathLn = mb_strlen($stepPath);
$node = $step->getParent();
if ($node instanceof BackgroundNode) {
$scenarioPath = "From scenario background.";
} else {
$title = $node->getTitle();
$title = $title ? "`$title'" : '***';
$scenarioPath = "From scenario $title.";
}
$scenarioPathLn = mb_strlen($scenarioPath);
$this->maxLineLength = max($this->maxLineLength, $stepPathLn);
$this->maxLineLength = max($this->maxLineLength, $scenarioPathLn);
$this->write(" {+$color}$stepPath{-$color}");
if (null !== $definition) {
$indentCount = $this->maxLineLength - $stepPathLn;
$this->printPathComment(
$this->relativizePathsInString($definition->getPath()), $indentCount
);
} else {
$this->writeln();
}
$this->write(" {+$color}$scenarioPath{-$color}");
$indentCount = $this->maxLineLength - $scenarioPathLn;
$this->printPathComment(
$this->relativizePathsInString($node->getFile()) . ':' . $node->getLine(), $indentCount
);
$this->writeln();
}
/**
* Prints summary suite run information.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printSummary(LoggerDataCollector $logger)
{
$this->printScenariosSummary($logger);
$this->printStepsSummary($logger);
if ($this->parameters->get('time')) {
$this->printTimeSummary($logger);
}
}
/**
* Prints scenarios summary information.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printScenariosSummary(LoggerDataCollector $logger)
{
$count = $logger->getScenariosCount();
$header = $this->translateChoice('scenarios_count', $count, array('%1%' => $count));
$this->write($header);
$this->printStatusesSummary($logger->getScenariosStatuses());
}
/**
* Prints steps summary information.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printStepsSummary(LoggerDataCollector $logger)
{
$count = $logger->getStepsCount();
$header = $this->translateChoice('steps_count', $count, array('%1%' => $count));
$this->write($header);
$this->printStatusesSummary($logger->getStepsStatuses());
}
/**
* Prints statuses summary.
*
* @param array $statusesStatistics statuses statistic hash (status => count)
*/
protected function printStatusesSummary(array $statusesStatistics)
{
$statuses = array();
foreach ($statusesStatistics as $status => $count) {
if ($count) {
$transStatus = $this->translateChoice(
"{$status}_count", $count, array('%1%' => $count)
);
$statuses[] = "{+$status}$transStatus{-$status}";
}
}
$this->writeln(count($statuses) ? ' ' . sprintf('(%s)', implode(', ', $statuses)) : '');
}
/**
* Prints suite run time inforamtion.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printTimeSummary(LoggerDataCollector $logger)
{
$time = $logger->getTotalTime();
$minutes = floor($time / 60);
$seconds = round($time - ($minutes * 60), 3);
$this->writeln($minutes . 'm' . $seconds . 's');
}
/**
* Prints undefined steps snippets.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printUndefinedStepsSnippets(LoggerDataCollector $logger)
{
if ($this->getParameter('snippets') && count($logger->getDefinitionsSnippets())) {
$header = $this->translate('proposal_title');
$this->writeln("\n{+undefined}$header{-undefined}\n");
$this->printSnippets($logger);
}
}
/**
* Prints steps snippets.
*
* @param LoggerDataCollector $logger suite logger
*/
protected function printSnippets(LoggerDataCollector $logger)
{
foreach ($logger->getDefinitionsSnippets() as $snippet) {
$snippetText = $snippet->getSnippet();
if ($this->getParameter('snippets_paths')) {
$indent = str_pad(
'', mb_strlen($snippetText) - mb_strlen(ltrim($snippetText)), ' '
);
$this->writeln("{+undefined}$indent/**{-undefined}");
foreach ($snippet->getSteps() as $step) {
$this->writeln(sprintf(
'{+undefined}%s * %s %s # %s:%d{-undefined}', $indent,
$step->getType(), $step->getText(),
$this->relativizePathsInString($step->getFile()), $step->getLine()
));
}
if (false !== mb_strpos($snippetText, '/**')) {
$snippetText = str_replace('/**', ' *', $snippetText);
} else {
$this->writeln("{+undefined}$indent */{-undefined}");
}
}
$this->writeln("{+undefined}$snippetText{-undefined}\n");
}
}
/**
* Prints path comment.
*
* @param string $path item path
* @param integer $indentCount indenation number
*/
protected function printPathComment($path, $indentCount = 0)
{
$indent = str_repeat(' ', $indentCount);
$this->writeln("$indent {+comment}# $path{-comment}");
}
/**
* Returns string with relativized paths.
*
* @param string $string
*
* @return string
*/
protected function relativizePathsInString($string)
{
if ($basePath = $this->parameters->get('base_path')) {
$basePath = realpath($basePath) . DIRECTORY_SEPARATOR;
$string = str_replace($basePath, '', $string);
}
return $string;
}
}
<?php
namespace Behat\Behat\Formatter;
use Behat\Behat\Event\SuiteEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Snippets formatter.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class SnippetsFormatter extends ProgressFormatter
{
/**
* {@inheritdoc}
*/
protected function getDefaultParameters()
{
return array();
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return array('afterSuite' => 'afterSuite');
}
/**
* Listens to "suite.after" event.
*
* @param SuiteEvent $event
*
* @uses printUndefinedStepsSnippets()
*/
public function afterSuite(SuiteEvent $event)
{
$logger = $event->getLogger();
$this->writeln();
$this->printSnippets($logger);
}
}
<?php
namespace Behat\Behat\Gherkin\Loader;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Behat\Gherkin\Loader\AbstractFileLoader,
Behat\Gherkin\Gherkin;
use Symfony\Component\Finder\Finder;
/**
* Gherkin loader with features/ path support.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FeatureSuiteLoader extends AbstractFileLoader
{
private $featuresPath;
private $gherkin;
/**
* Initializes loader.
*
* @param string $featuresPath
* @param Gherkin $gherkin
*/
public function __construct($featuresPath, Gherkin $gherkin)
{
$this->featuresPath = $featuresPath;
$this->gherkin = $gherkin;
}
/**
* Checks if current loader supports provided resource.
*
* @param mixed $resource Resource to load
*
* @return Boolean
*/
public function supports($resource)
{
return '' === $resource
&& is_dir($this->featuresPath);
}
/**
* Loads features from provided resource.
*
* @param mixed $resource Resource to load
*
* @return array
*/
public function load($resource)
{
$iterator = Finder::create()
->depth(0)
->sortByName()
->in($this->featuresPath)
;
$features = array();
foreach ($iterator as $path) {
$resource = (string) $path;
$loader = $this->gherkin->resolveLoader($resource);
if (null !== $loader) {
$features = array_merge($features, $loader->load($resource));
}
}
return $features;
}
}
<?php
namespace Behat\Behat\HelpPrinter;
use Behat\Behat\Definition\DefinitionDispatcher;
use Symfony\Component\Console\Output\OutputInterface,
Symfony\Component\Console\Formatter\OutputFormatterStyle;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Definitions printer.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class DefinitionsPrinter
{
private $dispatcher;
/**
* Initializes definition dispatcher.
*
* @param DefinitionDispatcher $dispatcher
*/
public function __construct(DefinitionDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Prints step definitions into console.
*
* @param OutputInterface $output
* @param string $search
* @param string $language
* @param Boolean $shortNotation
*/
public function printDefinitions(OutputInterface $output, $search = null, $language = 'en', $shortNotation = true)
{
$output->getFormatter()->setStyle(
'capture', new OutputFormatterStyle('yellow', null, array('bold'))
);
$output->getFormatter()->setStyle(
'path', new OutputFormatterStyle('black')
);
$output->writeln($this->getDefinitionsForPrint($search, $language, $shortNotation));
}
/**
* Returns available definitions in string.
*
* @param string $search search string
* @param string $language default definitions language
* @param Boolean $shortNotation show short notation instead of full one
*
* @return string
*/
private function getDefinitionsForPrint($search = null, $language = 'en', $shortNotation = true)
{
if ($shortNotation) {
$template = '<info>{type}</info> <comment>{regex}</comment>';
} else {
$template = <<<TPL
<info>{type}</info> <comment>{regex}</comment>
{description}<path># {path}</path>
TPL;
}
$definitions = array();
foreach ($this->dispatcher->getDefinitions() as $regex => $definition) {
$regex = $this->dispatcher->translateDefinitionRegex($regex, $language);
if ($search && !preg_match('/'.str_replace(' ', '.*', preg_quote($search, '/').'/'), $regex)) {
continue;
}
$regex = preg_replace_callback('/\([^\)]*\)/', function($capture) {
return "</comment><capture>{$capture[0]}</capture><comment>";
}, $regex);
$definitions[] = strtr($template, array(
'{regex}' => $regex,
'{type}' => str_pad($definition->getType(), 5, ' ', STR_PAD_LEFT),
'{description}' => $definition->getDescription() ? '- '.$definition->getDescription()."\n " : '',
'{path}' => $definition->getPath()
));
}
return implode("\n", $definitions);
}
}
<?php
namespace Behat\Behat\HelpPrinter;
use Behat\Gherkin\Keywords\KeywordsDumper;
use Symfony\Component\Console\Output\OutputInterface,
Symfony\Component\Console\Formatter\OutputFormatterStyle;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Story syntax printer.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class StorySyntaxPrinter
{
private $dumper;
/**
* Initializes definition dispatcher.
*
* @param KeywordsDumper $dumper
*/
public function __construct(KeywordsDumper $dumper)
{
$dumper->setKeywordsDumperFunction(array($this, 'dumpKeywords'));
$this->dumper = $dumper;
}
/**
* Prints example story syntax into console.
*
* @param OutputInterface $output
* @param string $language
*/
public function printSyntax(OutputInterface $output, $language = 'en')
{
$output->getFormatter()->setStyle('comment', new OutputFormatterStyle('yellow'));
$output->getFormatter()->setStyle(
'keyword', new OutputFormatterStyle('green', null, array('bold'))
);
$story = $this->dumper->dump($language);
$story = preg_replace('/^\#.*/', '<comment>$0</comment>', $story);
$output->writeln($story);
}
/**
* Keywords dumper.
*
* @param array $keywords keywords list
*
* @return string
*/
public function dumpKeywords(array $keywords)
{
$dump = '<keyword>'.implode('</keyword>|<keyword>', $keywords).'</keyword>';
if (1 < count($keywords)) {
return '['.$dump.']';
}
return $dump;
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* AfterFeature hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AfterFeature extends FeatureHook
{
/**
* {@inheritdoc}
*/
public function getEventName()
{
return 'afterFeature';
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* AfterScenario hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AfterScenario extends ScenarioHook
{
/**
* {@inheritdoc}
*/
public function getEventName()
{
return 'afterScenario';
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* AfterStep hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AfterStep extends StepHook
{
/**
* {@inheritdoc}
*/
public function getEventName()
{
return 'afterStep';
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* AfterSuite hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AfterSuite extends SuiteHook
{
/**
* {@inheritdoc}
*/
public function getEventName()
{
return 'afterSuite';
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* BeforeFeature hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BeforeFeature extends FeatureHook
{
/**
* {@inheritdoc}
*/
public function getEventName()
{
return 'beforeFeature';
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* BeforeScenario hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BeforeScenario extends ScenarioHook
{
/**
* {@inheritdoc}
*/
public function getEventName()
{
return 'beforeScenario';
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* BeforeStep hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BeforeStep extends StepHook
{
/**
* {@inheritdoc}
*/
public function getEventName()
{
return 'beforeStep';
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* BeforeSuite hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BeforeSuite extends SuiteHook
{
/**
* {@inheritdoc}
*/
public function getEventName()
{
return 'beforeSuite';
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
use Behat\Behat\Event\EventInterface;
use Behat\Gherkin\Filter\TagFilter,
Behat\Gherkin\Filter\NameFilter;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* FeatureHook hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class FeatureHook extends FilterableHook
{
/**
* {@inheritdoc}
*/
public function __construct($callback, $filterString = null)
{
parent::__construct($callback, $filterString);
if (!$this->isClosure()) {
$methodRefl = new \ReflectionMethod($callback[0], $callback[1]);
if (!$methodRefl->isStatic()) {
throw new \InvalidArgumentException(sprintf(
'"%s" hook callback: %s::%s() must be a static method',
basename(str_replace('\\', '/', get_class($this))), $callback[0], $callback[1]
));
}
}
}
/**
* {@inheritdoc}
*/
public function filterMatches(EventInterface $event)
{
if (null === ($filterString = $this->getFilter())) {
return true;
}
$feature = $event->getFeature();
if (false !== strpos($filterString, '@')) {
$filter = new TagFilter($filterString);
if ($filter->isFeatureMatch($feature)) {
return true;
}
} elseif (!empty($filterString)) {
$filter = new NameFilter($filterString);
if ($filter->isFeatureMatch($feature)) {
return true;
}
}
return false;
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
use Behat\Behat\Event\EventInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Base filterable hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class FilterableHook extends Hook
{
private $filter;
/**
* Initializes hook.
*
* @param callback $callback callback
* @param string $filterString hook filter
*/
public function __construct($callback, $filterString = null)
{
parent::__construct($callback);
$this->filter = $filterString;
}
/**
* Returns filter string.
*
* @return stirng
*/
public function getFilter()
{
return $this->filter;
}
/**
* Checks that current hook matches provided event object.
*
* @param EventInterface $event
*
* @return Boolean
*/
abstract public function filterMatches(EventInterface $event);
}
<?php
namespace Behat\Behat\Hook\Annotation;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Event\EventInterface,
Behat\Behat\Hook\HookInterface,
Behat\Behat\Annotation\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Base hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class Hook extends Annotation implements HookInterface
{
/**
* Constructs annotation.
*
* @param callback $callback
*
* @throws \InvalidArgumentException
*/
public function __construct($callback)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf(
'"%s" hook callback should be a valid callable, but %s given',
basename(str_replace('\\', '/', get_class($this))), gettype($callback)
));
}
parent::__construct($callback);
}
/**
* Runs hook callback.
*
* @param EventInterface $event
*/
public function run(EventInterface $event)
{
call_user_func($this->getCallback(), $event);
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
use Behat\Behat\Event\EventInterface,
Behat\Behat\Event\ScenarioEvent;
use Behat\Gherkin\Filter\TagFilter,
Behat\Gherkin\Filter\NameFilter;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* ScenarioHook hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class ScenarioHook extends FilterableHook
{
/**
* {@inheritdoc}
*/
public function filterMatches(EventInterface $event)
{
if (null === ($filterString = $this->getFilter())) {
return true;
}
if ($event instanceof ScenarioEvent) {
$scenario = $event->getScenario();
} else {
$scenario = $event->getOutline();
}
if (false !== strpos($filterString, '@')) {
$filter = new TagFilter($filterString);
if ($filter->isScenarioMatch($scenario)) {
return true;
}
} elseif (!empty($filterString)) {
$filter = new NameFilter($filterString);
if ($filter->isScenarioMatch($scenario)) {
return true;
}
}
return false;
}
/**
* Runs hook callback.
*
* @param EventInterface $event
*/
public function run(EventInterface $event)
{
call_user_func($this->getCallbackForContext($event->getContext()), $event);
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
use Behat\Behat\Event\EventInterface;
use Behat\Gherkin\Filter\TagFilter,
Behat\Gherkin\Filter\NameFilter,
Behat\Gherkin\Node\BackgroundNode;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* StepHook hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class StepHook extends FilterableHook
{
/**
* {@inheritdoc}
*/
public function filterMatches(EventInterface $event)
{
if (null === ($filterString = $this->getFilter())) {
return true;
}
$scenario = $event->getLogicalParent();
if (false !== strpos($filterString, '@')) {
$filter = new TagFilter($filterString);
if ($filter->isScenarioMatch($scenario)) {
return true;
}
} elseif (!empty($filterString)) {
$filter = new NameFilter($filterString);
if ($filter->isScenarioMatch($scenario)) {
return true;
}
}
return false;
}
/**
* Runs hook callback.
*
* @param EventInterface $event
*/
public function run(EventInterface $event)
{
call_user_func($this->getCallbackForContext($event->getContext()), $event);
}
}
<?php
namespace Behat\Behat\Hook\Annotation;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* SuiteHook hook class.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class SuiteHook extends Hook
{
/**
* {@inheritdoc}
*/
public function __construct($callback)
{
parent::__construct($callback);
if (!$this->isClosure()) {
$methodRefl = new \ReflectionMethod($callback[0], $callback[1]);
if (!$methodRefl->isStatic()) {
throw new \InvalidArgumentException(sprintf(
'"%s" hook callback: %s::%s() must be a static method',
basename(str_replace('\\', '/', get_class($this))), $callback[0], $callback[1]
));
}
}
}
}
<?php
namespace Behat\Behat\Hook;
use Symfony\Component\EventDispatcher\EventDispatcher,
Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Behat\Behat\Event\EventInterface,
Behat\Behat\Event\SuiteEvent,
Behat\Behat\Event\FeatureEvent,
Behat\Behat\Event\ScenarioEvent,
Behat\Behat\Event\OutlineExampleEvent,
Behat\Behat\Event\StepEvent,
Behat\Behat\Hook\Annotation\FilterableHook,
Behat\Behat\Exception\ErrorException;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Hook dispatcher.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class HookDispatcher implements EventSubscriberInterface
{
private $hooks = array();
private $dryRun = false;
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
$events = array(
'beforeSuite', 'afterSuite', 'beforeFeature', 'afterFeature', 'beforeScenario',
'afterScenario', 'beforeOutlineExample', 'afterOutlineExample', 'beforeStep', 'afterStep'
);
return array_combine($events, $events);
}
/**
* Sets hook dispatcher to dry-run mode.
*
* @param Boolean $dryRun
*/
public function setDryRun($dryRun = true)
{
$this->dryRun = (bool) $dryRun;
}
/**
* Adds hook into dispatcher.
*
* @param HookInterface $hook
*/
public function addHook(HookInterface $hook)
{
if (!isset($this->hooks[$hook->getEventName()])) {
$this->hooks[$hook->getEventName()] = array();
}
$this->hooks[$hook->getEventName()][] = $hook;
}
/**
* Returns all available hooks.
*
* @return array
*/
public function getHooks()
{
return $this->hooks;
}
/**
* Cleans dispatcher.
*/
public function clean()
{
$this->hooks = array();
}
/**
* Listens to "suite.before" event.
*
* @param SuiteEvent $event
*
* @uses fireSuiteHooks()
*/
public function beforeSuite(SuiteEvent $event)
{
$this->fireHooks(__FUNCTION__, $event);
}
/**
* Listens to "suite.after" event.
*
* @param SuiteEvent $event
*
* @uses fireSuiteHooks()
*/
public function afterSuite(SuiteEvent $event)
{
$this->fireHooks(__FUNCTION__, $event);
}
/**
* Listens to "feature.before" event.
*
* @param FeatureEvent $event
*
* @uses fireFeatureHooks()
*/
public function beforeFeature(FeatureEvent $event)
{
$this->fireHooks(__FUNCTION__, $event);
}
/**
* Listens to "feature.after" event.
*
* @param FeatureEvent $event
*
* @uses fireFeatureHooks()
*/
public function afterFeature(FeatureEvent $event)
{
$this->fireHooks(__FUNCTION__, $event);
}
/**
* Listens to "scenario.before" event.
*
* @param ScenarioEvent $event
*
* @uses fireScenarioHooks()
*/
public function beforeScenario(ScenarioEvent $event)
{
$this->fireHooks(__FUNCTION__, $event);
}
/**
* Listens to "scenario.after" event.
*
* @param ScenarioEvent $event
*
* @uses fireScenarioHooks()
*/
public function afterScenario(ScenarioEvent $event)
{
$this->fireHooks(__FUNCTION__, $event);
}
/**
* Listens to "outline.example.before" event.
*
* @param OutlineExampleEvent $event
*
* @uses fireScenarioHooks()
*/
public function beforeOutlineExample(OutlineExampleEvent $event)
{
$this->fireHooks('beforeScenario', $event);
}
/**
* Listens to "outline.example.after" event.
*
* @param OutlineExampleEvent $event
*
* @uses fireScenarioHooks()
*/
public function afterOutlineExample(OutlineExampleEvent $event)
{
$this->fireHooks('afterScenario', $event);
}
/**
* Listens to "step.before" event.
*
* @param StepEvent $event
*
* @uses fireStepHooks()
*/
public function beforeStep(StepEvent $event)
{
$this->fireHooks(__FUNCTION__, $event);
}
/**
* Listens to "step.after" event.
*
* @param StepEvent $event
*
* @uses fireStepHooks()
*/
public function afterStep(StepEvent $event)
{
$this->fireHooks(__FUNCTION__, $event);
}
/**
* Custom error handler.
*
* This method used as custom error handler when step is running.
*
* @see set_error_handler()
*
* @param $code
* @param $message
* @param $file
* @param $line
*
* @throws \Behat\Behat\Exception\ErrorException
*/
public function errorHandler($code, $message, $file, $line)
{
if (0 === error_reporting()) {
return; // error reporting turned off or more likely suppresed with @
}
throw new ErrorException($code, $message, $file, $line);
}
/**
* Runs hooks with specified name.
*
* @param string $name hooks name
* @param EventInterface $event event to which hooks glued
*
* @throws \Exception
*/
protected function fireHooks($name, EventInterface $event)
{
if ($this->dryRun) {
return;
}
$hooks = isset($this->hooks[$name]) ? $this->hooks[$name] : array();
foreach ($hooks as $hook) {
$runable = $hook instanceof FilterableHook ? $hook->filterMatches($event) : true;
if ($runable) {
if (defined('BEHAT_ERROR_REPORTING')) {
$errorLevel = BEHAT_ERROR_REPORTING;
} else {
$errorLevel = E_ALL ^ E_WARNING;
}
$oldHandler = set_error_handler(array($this, 'errorHandler'), $errorLevel);
try {
$hook->run($event);
} catch (\Exception $e) {
$this->addHookInformationToException($hook, $e);
throw $e;
}
if (null !== $oldHandler) {
set_error_handler($oldHandler);
}
}
}
}
/**
* Adds hook information to exception thrown from it.
*
* @param HookInterface $hook hook instance
* @param \Exception $exception exception
*/
private function addHookInformationToException(HookInterface $hook, \Exception $exception)
{
$refl = new \ReflectionObject($exception);
$message = $refl->getProperty('message');
$message->setAccessible(true);
$message->setValue($exception, sprintf(
'Exception has been thrown in "%s" hook, defined in %s'."\n\n%s",
$hook->getEventName(),
$hook->getPath(),
$exception->getMessage()
));
}
}
<?php
namespace Behat\Behat\Hook;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Event\EventInterface,
Behat\Behat\Annotation\AnnotationInterface;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Hook interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface HookInterface
{
/**
* Returns hooked event type.
*
* @return string
*/
public function getEventName();
/**
* Runs hook callback.
*
* @param EventInterface $event
*/
public function run(EventInterface $event);
}
<?php
namespace Behat\Behat\Hook\Loader;
use Behat\Behat\Hook\HookDispatcher,
Behat\Behat\Hook\Annotation\BeforeSuite,
Behat\Behat\Hook\Annotation\AfterSuite,
Behat\Behat\Hook\Annotation\BeforeFeature,
Behat\Behat\Hook\Annotation\AfterFeature,
Behat\Behat\Hook\Annotation\BeforeScenario,
Behat\Behat\Hook\Annotation\AfterScenario,
Behat\Behat\Hook\Annotation\BeforeStep,
Behat\Behat\Hook\Annotation\AfterStep;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Closured hook definitions loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ClosuredHookLoader implements HookLoaderInterface
{
private $dispatcher;
/**
* Initializes loader.
*
* @param HookDispatcher $dispatcher
*/
public function __construct(HookDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Loads definitions from provided resource.
*
* @param mixed $resource
*/
public function load($resource)
{
$hooks = $this;
require($resource);
}
/**
* Hooks into "suite.before".
*
* @param callback $callback hook callback
*/
public function beforeSuite($callback)
{
$this->dispatcher->addHook(new BeforeSuite($callback));
}
/**
* Hooks into "suite.after".
*
* @param callback $callback hook callback
*/
public function afterSuite($callback)
{
$this->dispatcher->addHook(new AfterSuite($callback));
}
/**
* Hooks into "feature.before".
*
* @param string $filter filter string (tags or name)
* @param callback $callback hook callback
*/
public function beforeFeature($filter, $callback)
{
$this->dispatcher->addHook(new BeforeFeature($callback, '' !== $filter ? $filter : null));
}
/**
* Hooks into "feature.after".
*
* @param string $filter filter string (tags or name)
* @param callback $callback hook callback
*/
public function afterFeature($filter, $callback)
{
$this->dispatcher->addHook(new AfterFeature($callback, '' !== $filter ? $filter : null));
}
/**
* Hooks into "scenario.before" OR "outline.example.before".
*
* @param string $filter filter string (tags or name)
* @param callback $callback hook callback
*/
public function beforeScenario($filter, $callback)
{
$this->dispatcher->addHook(new BeforeScenario($callback, '' !== $filter ? $filter : null));
}
/**
* Hooks into "scenario.after" OR "outline.example.after".
*
* @param string $filter filter string (tags or name)
* @param callback $callback hook callback
*/
public function afterScenario($filter, $callback)
{
$this->dispatcher->addHook(new AfterScenario($callback, '' !== $filter ? $filter : null));
}
/**
* Hooks into "step.before".
*
* @param string $filter filter string (tags or name)
* @param callback $callback hook callback
*/
public function beforeStep($filter, $callback)
{
$this->dispatcher->addHook(new BeforeStep($callback, '' !== $filter ? $filter : null));
}
/**
* Hooks into "step.after".
*
* @param string $filter filter string (tags or name)
* @param callback $callback hook callback
*/
public function afterStep($filter, $callback)
{
$this->dispatcher->addHook(new AfterStep($callback, '' !== $filter ? $filter : null));
}
}
<?php
namespace Behat\Behat\Hook\Loader;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Hook loader interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface HookLoaderInterface
{
/**
* Loads definitions from provided resource.
*
* @param mixed $resource
*/
public function load($resource);
}
<?php
namespace Behat\Behat\Tester;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Behat\Gherkin\Node\NodeVisitorInterface,
Behat\Gherkin\Node\AbstractNode,
Behat\Gherkin\Node\ScenarioNode;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Event\BackgroundEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Background tester.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BackgroundTester implements NodeVisitorInterface
{
private $logicalParent;
private $container;
private $dispatcher;
private $context;
private $dryRun = false;
/**
* Initializes tester.
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->dispatcher = $container->get('behat.event_dispatcher');
}
/**
* Sets logical parent of the step, which is always a ScenarioNode.
*
* @param ScenarioNode $parent
*/
public function setLogicalParent(ScenarioNode $parent)
{
$this->logicalParent = $parent;
}
/**
* Sets run context.
*
* @param ContextInterface $context
*/
public function setContext(ContextInterface $context)
{
$this->context = $context;
}
/**
* Sets tester to dry-run mode.
*
* @param Boolean $dryRun
*/
public function setDryRun($dryRun = true)
{
$this->dryRun = (bool) $dryRun;
}
/**
* Visits & tests BackgroundNode.
*
* @param AbstractNode $background
*
* @return integer
*/
public function visit(AbstractNode $background)
{
$this->dispatcher->dispatch('beforeBackground', new BackgroundEvent($background));
$result = 0;
$skip = false;
// Visit & test steps
foreach ($background->getSteps() as $step) {
$tester = $this->container->get('behat.tester.step');
$tester->setLogicalParent($this->logicalParent);
$tester->setContext($this->context);
$tester->skip($skip || $this->dryRun);
$stResult = $step->accept($tester);
if (0 !== $stResult) {
$skip = true;
}
$result = max($result, $stResult);
}
$this->dispatcher->dispatch('afterBackground', new BackgroundEvent($background, $result, $skip));
return $result;
}
}
<?php
namespace Behat\Behat\Tester;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Behat\Gherkin\Node\NodeVisitorInterface,
Behat\Gherkin\Node\AbstractNode,
Behat\Gherkin\Node\ScenarioNode,
Behat\Gherkin\Node\OutlineNode;
use Behat\Behat\Exception\BehaviorException,
Behat\Behat\Event\FeatureEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Feature tester.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FeatureTester implements NodeVisitorInterface
{
private $container;
private $dispatcher;
private $parameters;
private $dryRun = false;
/**
* Initializes tester.
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->dispatcher = $container->get('behat.event_dispatcher');
$this->parameters = $container->get('behat.context.dispatcher')->getContextParameters();
}
/**
* Sets tester to dry-run mode.
*
* @param Boolean $dryRun
*/
public function setDryRun($dryRun = true)
{
$this->dryRun = (bool) $dryRun;
}
/**
* Visits & tests FeatureNode.
*
* @param AbstractNode $feature
*
* @return integer
*
* @throws BehaviorException if unknown scenario type (neither Outline or Scenario) found in feature
*/
public function visit(AbstractNode $feature)
{
$result = 0;
// If feature has scenarios - run them
if ($feature->hasScenarios()) {
$this->dispatcher->dispatch(
'beforeFeature', new FeatureEvent($feature, $this->parameters)
);
foreach ($feature->getScenarios() as $scenario) {
if ($scenario instanceof OutlineNode) {
$tester = $this->container->get('behat.tester.outline');
} elseif ($scenario instanceof ScenarioNode) {
$tester = $this->container->get('behat.tester.scenario');
} else {
throw new BehaviorException(
'Unknown scenario type found: ' . get_class($scenario)
);
}
$tester->setDryRun($this->dryRun);
$result = max($result, $scenario->accept($tester));
}
$this->dispatcher->dispatch(
'afterFeature', new FeatureEvent($feature, $this->parameters, $result)
);
}
return $result;
}
}
<?php
namespace Behat\Behat\Tester;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\EventDispatcher\Event;
use Behat\Gherkin\Node\NodeVisitorInterface,
Behat\Gherkin\Node\AbstractNode,
Behat\Gherkin\Node\OutlineNode;
use Behat\Behat\Event\OutlineEvent,
Behat\Behat\Event\OutlineExampleEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Outline tester.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class OutlineTester extends ScenarioTester
{
/**
* Initializes tester.
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->dispatcher = $container->get('behat.event_dispatcher');
}
/**
* Visits & tests OutlineNode.
*
* @param AbstractNode $outline
*
* @return integer
*/
public function visit(AbstractNode $outline)
{
$this->dispatcher->dispatch('beforeOutline', new OutlineEvent($outline));
$result = 0;
// Run examples of outline
foreach ($outline->getExamples()->getHash() as $iteration => $tokens) {
$itResult = $this->visitOutlineExample($outline, $iteration, $tokens);
$result = max($result, $itResult);
}
$this->dispatcher->dispatch('afterOutline', new OutlineEvent($outline, $result));
return $result;
}
/**
* Visits & tests OutlineNode example.
*
* @param OutlineNode $outline outline instance
* @param integer $row row number
* @param array $tokens step replacements for tokens
*
* @return integer
*/
private function visitOutlineExample(OutlineNode $outline, $row, array $tokens = array())
{
$context = $this->container->get('behat.context.dispatcher')->createContext();
$itResult = 0;
$skip = false;
$this->dispatcher->dispatch('beforeOutlineExample', new OutlineExampleEvent(
$outline, $row, $context
));
// Visit & test background if has one
if ($outline->getFeature()->hasBackground()) {
$bgResult = $this->visitBackground(
$outline->getFeature()->getBackground(), $outline, $context
);
if (0 !== $bgResult) {
$skip = true;
}
$itResult = max($itResult, $bgResult);
}
// Visit & test steps
foreach ($outline->getSteps() as $step) {
$stResult = $this->visitStep($step, $outline, $context, $tokens, $skip);
if (0 !== $stResult) {
$skip = true;
}
$itResult = max($itResult, $stResult);
}
$this->dispatcher->dispatch('afterOutlineExample', new OutlineExampleEvent(
$outline, $row, $context, $itResult, $skip
));
return $itResult;
}
}
<?php
namespace Behat\Behat\Tester;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\Event;
use Behat\Gherkin\Node\NodeVisitorInterface,
Behat\Gherkin\Node\AbstractNode,
Behat\Gherkin\Node\BackgroundNode,
Behat\Gherkin\Node\OutlineNode,
Behat\Gherkin\Node\ScenarioNode,
Behat\Gherkin\Node\StepNode;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Event\ScenarioEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Scenario Tester.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ScenarioTester implements NodeVisitorInterface
{
protected $container;
protected $dispatcher;
private $context;
private $dryRun = false;
/**
* Initializes tester.
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->dispatcher = $container->get('behat.event_dispatcher');
$this->context = $container->get('behat.context.dispatcher')->createContext();
}
/**
* Sets tester to dry-run mode.
*
* @param Boolean $dryRun
*/
public function setDryRun($dryRun = true)
{
$this->dryRun = (bool) $dryRun;
}
/**
* Visits & tests ScenarioNode.
*
* @param AbstractNode $scenario
*
* @return integer
*/
public function visit(AbstractNode $scenario)
{
$this->dispatcher->dispatch('beforeScenario', new ScenarioEvent($scenario, $this->context));
$result = 0;
$skip = false;
// Visit & test background if has one
if ($scenario->getFeature()->hasBackground()) {
$bgResult = $this->visitBackground(
$scenario->getFeature()->getBackground(), $scenario, $this->context
);
if (0 !== $bgResult) {
$skip = true;
}
$result = max($result, $bgResult);
}
// Visit & test steps
foreach ($scenario->getSteps() as $step) {
$stResult = $this->visitStep($step, $scenario, $this->context, array(), $skip);
if (0 !== $stResult) {
$skip = true;
}
$result = max($result, $stResult);
}
$this->dispatcher->dispatch('afterScenario', new ScenarioEvent(
$scenario, $this->context, $result, $skip
));
return $result;
}
/**
* Visits & tests BackgroundNode.
*
* @param BackgroundNode $background
* @param ScenarioNode $logicalParent
* @param ContextInterface $context
*
* @see BackgroundTester::visit()
*
* @return integer
*/
protected function visitBackground(BackgroundNode $background, ScenarioNode $logicalParent,
ContextInterface $context)
{
$tester = $this->container->get('behat.tester.background');
$tester->setLogicalParent($logicalParent);
$tester->setContext($context);
$tester->setDryRun($this->dryRun);
return $background->accept($tester);
}
/**
* Visits & tests StepNode.
*
* @param StepNode $step step instance
* @param ScenarioNode $logicalParent logical parent of the step
* @param ContextInterface $context context instance
* @param array $tokens step replacements for tokens
* @param boolean $skip mark step as skipped?
*
* @see StepTester::visit()
*
* @return integer
*/
protected function visitStep(StepNode $step, ScenarioNode $logicalParent,
ContextInterface $context, array $tokens = array(), $skip = false)
{
if ($logicalParent instanceof OutlineNode) {
$step = $step->createExampleRowStep($tokens);
}
$tester = $this->container->get('behat.tester.step');
$tester->setLogicalParent($logicalParent);
$tester->setContext($context);
$tester->skip($skip || $this->dryRun);
return $step->accept($tester);
}
}
<?php
namespace Behat\Behat\Tester;
use Symfony\Component\DependencyInjection\ContainerInterface,
Symfony\Component\EventDispatcher\Event;
use Behat\Gherkin\Node\NodeVisitorInterface,
Behat\Gherkin\Node\AbstractNode,
Behat\Gherkin\Node\StepNode,
Behat\Gherkin\Node\ScenarioNode;
use Behat\Behat\Context\ContextInterface,
Behat\Behat\Context\Step\SubstepInterface,
Behat\Behat\Definition\DefinitionInterface,
Behat\Behat\Exception\AmbiguousException,
Behat\Behat\Exception\UndefinedException,
Behat\Behat\Exception\PendingException,
Behat\Behat\Event\StepEvent;
/*
* This file is part of the Behat.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Step Tester.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class StepTester implements NodeVisitorInterface
{
private $logicalParent;
private $dispatcher;
private $context;
private $definitions;
private $skip = false;
/**
* Initializes tester.
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->dispatcher = $container->get('behat.event_dispatcher');
$this->definitions = $container->get('behat.definition.dispatcher');
}
/**
* Sets logical parent of the step, which is always a ScenarioNode.
*
* @param ScenarioNode $parent
*/
public function setLogicalParent(ScenarioNode $parent)
{
$this->logicalParent = $parent;
}
/**
* Sets run context.
*
* @param ContextInterface $context
*/
public function setContext(ContextInterface $context)
{
$this->context = $context;
}
/**
* Marks test as skipped.
*
* @param Boolean $skip skip test?
*/
public function skip($skip = true)
{
$this->skip = $skip;
}
/**
* Visits & tests StepNode.
*
* @param AbstractNode $step
*
* @return integer
*/
public function visit(AbstractNode $step)
{
$this->dispatcher->dispatch('beforeStep', new StepEvent(
$step, $this->logicalParent, $this->context
));
$afterEvent = $this->executeStep($step);
$this->dispatcher->dispatch('afterStep', $afterEvent);
return $afterEvent->getResult();
}
/**
* Searches and runs provided step with DefinitionDispatcher.
*
* @param StepNode $step step node
*
* @return StepEvent
*/
protected function executeStep(StepNode $step)
{
$context = $this->context;
$result = null;
$definition = null;
$exception = null;
$snippet = null;
try {
$definition = $this->definitions->findDefinition($this->context, $step);
if ($this->skip) {
return new StepEvent(
$step, $this->logicalParent, $context, StepEvent::SKIPPED, $definition
);
}
try {
$this->executeStepDefinition($step, $definition);
$result = StepEvent::PASSED;
} catch (PendingException $e) {
$result = StepEvent::PENDING;
$exception = $e;
} catch (\Exception $e) {
$result = StepEvent::FAILED;
$exception = $e;
}
} catch (UndefinedException $e) {
$result = StepEvent::UNDEFINED;
$snippet = $this->definitions->proposeDefinition($this->context, $step);
$exception = $e;
} catch (\Exception $e) {
$result = StepEvent::FAILED;
$exception = $e;
}
return new StepEvent(
$step, $this->logicalParent, $context, $result, $definition, $exception, $snippet
);
}
/**
* Executes provided step definition.
*
* @param StepNode $step step node
* @param DefinitionInterface $definition step definition
*/
protected function executeStepDefinition(StepNode $step, DefinitionInterface $definition)
{
$this->executeStepsChain($step, $definition->run($this->context));
}
/**
* Executes steps chain (if there's one).
*
* @param StepNode $step step node
* @param mixed $chain chain
*
* @throws \Exception
*/
private function executeStepsChain(StepNode $step, $chain = null)
{
if (null === $chain) {
return;
}
$chain = is_array($chain) ? $chain : array($chain);
foreach ($chain as $chainItem) {
if ($chainItem instanceof SubstepInterface) {
$substepNode = $chainItem->getStepNode();
$substepNode->setParent($step->getParent());
$substepEvent = $this->executeStep($substepNode);
if (StepEvent::PASSED !== $substepEvent->getResult()) {
throw $substepEvent->getException();
}
} elseif (is_callable($chainItem)) {
$this->executeStepsChain($step, call_user_func($chainItem));
}
}
}
}
<?php
$UTF8_TO_ASCII[0x00] = array(
'','','','','','','','','',' ','
',' ',' ',' ','','','','','','','','','','','','','','','','','','',' ','!','"','#','$','%','&',"'",'(',')','*','+',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?','@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',']','\\',']','^','_','`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','{','|','}','~','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','',' ','!','C/','PS','$?','Y=','|','SS','"','(c)','a','<<','!','','(r)','-','deg','+-','2','3',"'",'u','P','*',',','1','o','>>','1/4','1/2','3/4','?','A','A','A','A','A','A','AE','C','E','E','E','E','I','I','I','I','D','N','O','O','O','O','O','x','O','U','U','U','U','U','Th','ss','a','a','a','a','a','a','ae','c','e','e','e','e','i','i','i','i','d','n','o','o','o','o','o','/','o','u','u','u','u','y','th','y',
);
<?php
$UTF8_TO_ASCII[0x01] = array(
'A','a','A','a','A','a','C','c','C','c','C','c','C','c','D','d','D','d','E','e','E','e','E','e','E','e','E','e','G','g','G','g','G','g','G','g','H','h','H','h','I','i','I','i','I','i','I','i','I','i','IJ','','J','j','K','k','k','L','l','L','l','L','l','L','l','L','l','N','n','N','n','N','n',"'n",'ng','NG','O','o','O','o','O','o','OE','oe','R','r','R','r','R','r','S','s','S','s','S','s','S','s','T','t','T','t','T','t','U','u','U','u','U','u','U','u','U','u','U','u','W','w','Y','y','Y','Z','z','Z','z','Z','z','s','b','B','B','b','6','6','O','C','c','D','D','D','d','d','3','@','E','F','f','G','G','hv','I','I','K','k','l','l','W','N','n','O','O','o','OI','oi','P','p','YR','2','2','SH','sh','t','T','t','T','U','u','Y','V','Y','y','Z','z','ZH','ZH','zh','zh','2','5','5','ts','w','|','||','|=','!','DZ','Dz','dz','LJ','Lj','lj','NJ','Nj','nj','A','a','I','i','O','o','U','u','U','u','U','u','U','u','U','u','@','A','a','A','a','AE','ae','G','g','G','g','K','k','O','o','O','o','ZH','zh','j','DZ','D','dz','G','g','HV','W','N','n','A','a','AE','ae','O','o',
);
<?php
$UTF8_TO_ASCII[0x02] = array(
'A','a','A','a','E','e','E','e','I','i','I','i','O','o','O','o','R','r','R','r','U','u','U','u','S','s','T','t','Y','y','H','h','[?]','[?]','OU','ou','Z','z','A','a','E','e','O','o','O','o','O','o','O','o','Y','y','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','a','a','a','b','o','c','d','d','e','@','@','e','e','e','e','j','g','g','g','g','u','Y','h','h','i','i','I','l','l','l','lZ','W','W','m','n','n','n','o','OE','O','F','R','R','R','R','r','r','R','R','R','s','S','j','S','S','t','t','U','U','v','^','W','Y','Y','z','z','Z','Z','?','?','?','C','@','B','E','G','H','j','k','L','q','?','?','dz','dZ','dz','ts','tS','tC','fN','ls','lz','WW',']]','[?]','[?]','k','h','j','r','r','r','r','w','y',"'",'"','`',"'",'`','`',"'",'?','?','<','>','^','V','^','V',"'",'-','/','\\',',','_','\\','/',':','.','`',"'",'^','V','+','-','V','.','@',',','~','"','R','X','G','l','s','x','?','','','','','','','','V','=','"','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x03] = array(
'','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',"'",',','[?]','[?]','[?]','[?]','','[?]','[?]','[?]','?','[?]','[?]','[?]','[?]','[?]','','','A',';','E','E','I','[?]','O','[?]','U','O','I','A','B','G','D','E','Z','E','Th','I','K','L','M','N','Ks','O','P','R','[?]','S','T','U','Ph','Kh','Ps','O','I','U','a','e','e','i','u','a','b','g','d','e','z','e','th','i','k','l','m','n','x','o','p','r','s','s','t','u','ph','kh','ps','o','i','u','o','u','o','[?]','b','th','U','U','U','ph','p','&','[?]','[?]','St','st','W','w','Q','q','Sp','sp','Sh','sh','F','f','Kh','kh','H','h','G','g','CH','ch','Ti','ti','k','r','c','j','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x04] = array(
'Ie','Io','Dj','Gj','Ie','Dz','I','Yi','J','Lj','Nj','Tsh','Kj','I','U','Dzh','A','B','V','G','D','Ie','Zh','Z','I','I','K','L','M','N','O','P','R','S','T','U','F','Kh','Ts','Ch','Sh','Shch','','Y',"'",'E','Iu','Ia','a','b','v','gh','d','ie','zh','z','i','i','k','l','m','n','o','p','r','s','t','u','f','kh','ts','ch','sh','shch','','y',"'",'e','iu','ia','ie','io','dj','gj','ie','dz','i','yi','j','lj','nj','tsh','kj','i','u','dzh','O','o','E','e','Ie','ie','E','e','Ie','ie','O','o','Io','io','Ks','ks','Ps','ps','F','f','Y','y','Y','y','u','u','O','o','O','o','Ot','ot','Q','q','*1000*','','','','','[?]','*100.000*','*1.000.000*','[?]','[?]','"','"',"R'","r'","G'","g'","G'","g'","G'","g'","Zh'","zh'","Z'","z'","K'","k'","K'","k'","K'","k'","K'","k'","N'","n'",'Ng','ng',"P'","p'",'Kh','kh',"S'","s'","T'","t'",'U','u',"U'","u'","Kh'","kh'",'Tts','tts',"Ch'","ch'","Ch'","ch'",'H','h','Ch','ch',"Ch'","ch'",'`','Zh','zh',"K'","k'",'[?]','[?]',"N'","n'",'[?]','[?]','Ch','ch','[?]','[?]','[?]','a','a','A','a','Ae','ae','Ie','ie','@','@','@','@','Zh','zh','Z','z','Dz','dz','I','i','I','i','O','o','O','o','O','o','E','e','U','u','U','u','U','u','Ch','ch','[?]','[?]','Y','y','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x05] = array(
'[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','A','B','G','D','E','Z','E','E','T`','Zh','I','L','Kh','Ts','K','H','Dz','Gh','Ch','M','Y','N','Sh','O','Ch`','P','J','Rh','S','V','T','R','Ts`','W','P`','K`','O','F','[?]','[?]','<',"'",'/','!',',','?','.','[?]','a','b','g','d','e','z','e','e','t`','zh','i','l','kh','ts','k','h','dz','gh','ch','m','y','n','sh','o','ch`','p','j','rh','s','v','t','r','ts`','w','p`','k`','o','f','ew','[?]','.','-','[?]','[?]','[?]','[?]','[?]','[?]','','','','','','','','','','','','','','','','','','[?]','','','','','','','','','','','','','','@','e','a','o','i','e','e','a','a','o','[?]','u',"'",'','','','','','',':','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','','b','g','d','h','v','z','kh','t','y','k','k','l','m','m','n','n','s','`','p','p','ts','ts','q','r','sh','t','[?]','[?]','[?]','[?]','[?]','V','oy','i',"'",'"','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x06] = array(
'[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',',','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',';','[?]','[?]','[?]','?','[?]','','a',"'","w'",'',"y'",'','b','@','t','th','j','H','kh','d','dh','r','z','s','sh','S','D','T','Z','`','G','[?]','[?]','[?]','[?]','[?]','','f','q','k','l','m','n','h','w','~','y','an','un','in','a','u','i','W','','',"'","'",'[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','%','.',',','*','[?]','[?]','',"'","'","'",'',"'","'w","'u","'y",'tt','tth','b','t','T','p','th','bh',"'h",'H','ny','dy','H','ch','cch','dd','D','D','Dt','dh','ddh','d','D','D','rr','R','R','R','R','R','R','j','R','S','S','S','S','S','T','GH','F','F','F','v','f','ph','Q','Q','kh','k','K','K','ng','K','g','G','N','G','G','G','L','L','L','L','N','N','N','N','N','h','Ch','hy','h','H','@','W','oe','oe','u','yu','yu','W','v','y','Y','Y','W','','','y',"y'",'.','ae','','','','','','','','@','#','','','','','','','','','','','^','','','','','[?]','[?]','0','1','2','3','4','5','6','7','8','9','Sh','D','Gh','&','+m',
);
<?php
$UTF8_TO_ASCII[0x07] = array(
'//','/',',','!','!','-',',',',',';','?','~','{','}','*','[?]','',"'",'','b','g','g','d','d','h','w','z','H','t','t','y','yh','k','l','m','n','s','s','`','p','p','S','q','r','sh','t','[?]','[?]','[?]','a','a','a','A','A','A','e','e','e','E','i','i','u','u','u','o','','`',"'",'','','X','Q','@','@','|','+','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','h','sh','n','r','b','L','k',"'",'v','m','f','dh','th','l','g','ny','s','d','z','t','y','p','j','ch','tt','hh','kh','th','z','sh','s','d','t','z','`','gh','q','w','a','aa','i','ee','u','oo','e','ey','o','oa','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x09] = array(
);
<?php
$UTF8_TO_ASCII[0x0a] = array(
'[?]','N','N','H','[?]','a','aa','i','ii','u','uu','R','L','eN','e','e','ai','oN','o','o','au','k','kh','g','gh','ng','c','ch','j','jh','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','nnn','p','ph','b','bh','m','y','r','rr','l','l','lll','v','sh','ss','s','h','[?]','[?]',"'","'",'aa','i','ii','u','uu','R','RR','eN','e','e','ai','oN','o','o','au','','[?]','[?]','AUM',"'","'",'`',"'",'[?]','[?]','[?]','q','khh','ghh','z','dddh','rh','f','yy','RR','LL','L','LL',' / ',' // ','0','1','2','3','4','5','6','7','8','9','.','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','N','N','H','[?]','a','aa','i','ii','u','uu','R','RR','[?]','[?]','e','ai','[?]','[?]','o','au','k','kh','g','gh','ng','c','ch','j','jh','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','[?]','p','ph','b','bh','m','y','r','[?]','l','[?]','[?]','[?]','sh','ss','s','h','[?]','[?]',"'",'[?]','aa','i','ii','u','uu','R','RR','[?]','[?]','e','ai','[?]','[?]','o','au','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','+','[?]','[?]','[?]','[?]','rr','rh','[?]','yy','RR','LL','L','LL','[?]','[?]','0','1','2','3','4','5','6','7','8','9',"r'",'r`','Rs','Rs','1/','2/','3/','4/',' 1 - 1/','/16','','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x0b] = array(
'[?]','[?]','N','[?]','[?]','a','aa','i','ii','u','uu','[?]','[?]','[?]','[?]','ee','ai','[?]','[?]','oo','au','k','kh','g','gh','ng','c','ch','j','jh','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','[?]','p','ph','b','bb','m','y','r','[?]','l','ll','[?]','v','sh','[?]','s','h','[?]','[?]',"'",'[?]','aa','i','ii','u','uu','[?]','[?]','[?]','[?]','ee','ai','[?]','[?]','oo','au','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','khh','ghh','z','rr','[?]','f','[?]','[?]','[?]','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','N','H','','','G.E.O.','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','N','N','H','[?]','a','aa','i','ii','u','uu','R','[?]','eN','[?]','e','ai','oN','[?]','o','au','k','kh','g','gh','ng','c','ch','j','jh','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','[?]','p','ph','b','bh','m','ya','r','[?]','l','ll','[?]','v','sh','ss','s','h','[?]','[?]',"'","'",'aa','i','ii','u','uu','R','RR','eN','[?]','e','ai','oN','[?]','o','au','','[?]','[?]','AUM','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','RR','[?]','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x0c] = array(
'[?]','N','N','H','[?]','a','aa','i','ii','u','uu','R','L','[?]','[?]','e','ai','[?]','[?]','o','au','k','kh','g','gh','ng','c','ch','j','jh','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','[?]','p','ph','b','bh','m','y','r','[?]','l','ll','[?]','','sh','ss','s','h','[?]','[?]',"'","'",'aa','i','ii','u','uu','R','[?]','[?]','[?]','e','ai','[?]','[?]','o','au','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','+','+','[?]','[?]','[?]','[?]','rr','rh','[?]','yy','RR','LL','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','N','H','[?]','a','aa','i','ii','u','uu','[?]','[?]','[?]','e','ee','ai','[?]','o','oo','au','k','[?]','[?]','[?]','ng','c','[?]','j','[?]','ny','tt','[?]','[?]','[?]','nn','t','[?]','[?]','[?]','n','nnn','p','[?]','[?]','[?]','m','y','r','rr','l','ll','lll','v','[?]','ss','s','h','[?]','[?]','[?]','[?]','aa','i','ii','u','uu','[?]','[?]','[?]','e','ee','ai','[?]','o','oo','au','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','+','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','+10+','+100+','+1000+','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x0d] = array(
'[?]','N','N','H','[?]','a','aa','i','ii','u','uu','R','L','[?]','e','ee','ai','[?]','o','oo','au','k','kh','g','gh','ng','c','ch','j','jh','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','[?]','p','ph','b','bh','m','y','r','rr','l','ll','[?]','v','sh','ss','s','h','[?]','[?]','[?]','[?]','aa','i','ii','u','uu','R','RR','[?]','e','ee','ai','[?]','o','oo','au','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','+','+','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','RR','LL','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','N','H','[?]','a','aa','i','ii','u','uu','R','L','[?]','e','ee','ai','[?]','o','oo','au','k','kh','g','gh','ng','c','ch','j','jh','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','[?]','p','ph','b','bh','m','y','r','rr','l','ll','[?]','v','sh','ss','s','h','[?]','[?]','[?]','[?]','aa','i','ii','u','uu','R','RR','[?]','e','ee','ai','[?]','o','oo','au','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','+','+','[?]','[?]','[?]','[?]','[?]','[?]','[?]','lll','[?]','RR','LL','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x0e] = array(
'[?]','[?]','N','H','[?]','a','aa','i','ii','u','uu','R','L','[?]','e','ee','ai','[?]','o','oo','au','k','kh','g','gh','ng','c','ch','j','jh','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','[?]','p','ph','b','bh','m','y','r','rr','l','ll','lll','v','sh','ss','s','h','[?]','[?]','[?]','[?]','aa','i','ii','u','uu','R','[?]','[?]','e','ee','ai','','o','oo','au','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','+','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','RR','LL','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','N','H','[?]','a','aa','ae','aae','i','ii','u','uu','R','RR','L','LL','e','ee','ai','o','oo','au','[?]','[?]','[?]','k','kh','g','gh','ng','nng','c','ch','j','jh','ny','jny','nyj','tt','tth','dd','ddh','nn','nndd','t','th','d','dh','n','[?]','nd','p','ph','b','bh','m','mb','y','r','[?]','l','[?]','[?]','v','sh','ss','s','h','ll','f','[?]','[?]','[?]','','[?]','[?]','[?]','[?]','aa','ae','aae','i','ii','u','[?]','uu','[?]','R','e','ee','ai','o','oo','au','L','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','RR','LL',' . ','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x0f] = array(
'[?]','k','kh','kh','kh','kh','kh','ng','cch','ch','ch','ch','ch','y','d','t','th','th','th','n','d','t','th','th','th','n','b','p','ph','f','ph','f','ph','m','y','r','R','l','L','w','s','s','s','h','l','`','h','~','a','a','aa','am','i','ii','ue','uue','u','uu',"'",'[?]','[?]','[?]','[?]','Bh.','e','ae','o','ai','ai','ao','+','','','','','','','M','',' * ','0','1','2','3','4','5','6','7','8','9',' // ',' /// ','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','k','kh','[?]','kh','[?]','[?]','ng','ch','[?]','s','[?]','[?]','ny','[?]','[?]','[?]','[?]','[?]','[?]','d','h','th','th','[?]','n','b','p','ph','f','ph','f','[?]','m','y','r','[?]','l','[?]','w','[?]','[?]','s','h','[?]','`','','~','a','','aa','am','i','ii','y','yy','u','uu','[?]','o','l','ny','[?]','[?]','e','ei','o','ay','ai','[?]','+','[?]','','','','','','M','[?]','[?]','0','1','2','3','4','5','6','7','8','9','[?]','[?]','hn','hm','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x10] = array(
'AUM','','','','','','','',' // ',' * ','','-',' / ',' / ',' // ',' -/ ',' +/ ',' X/ ',' /XX/ ',' /X/ ',', ','','','','','','','','','','','','0','1','2','3','4','5','6','7','8','9','.5','1.5','2.5','3.5','4.5','5.5','6.5','7.5','8.5','-.5','+','*','^','_','','~','[?]',']','[[',']]','','','k','kh','g','gh','ng','c','ch','j','[?]','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','p','ph','b','bh','m','ts','tsh','dz','dzh','w','zh','z',"'",'y','r','l','sh','ssh','s','h','a','kss','r','[?]','[?]','[?]','[?]','[?]','[?]','aa','i','ii','u','uu','R','RR','L','LL','e','ee','o','oo','M','H','i','ii','','','','','','','','','','','[?]','[?]','[?]','[?]','k','kh','g','gh','ng','c','ch','j','[?]','ny','tt','tth','dd','ddh','nn','t','th','d','dh','n','p','ph','b','bh','m','ts','tsh','dz','dzh','w','zh','z',"'",'y','r','l','sh','ss','s','h','a','kss','w','y','r','[?]','X',' :X: ',' /O/ ',' /o/ ',' \\o\ ',' (O) ','','','','','','','','','','[?]','[?]','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x11] = array(
'k','kh','g','gh','ng','c','ch','j','jh','ny','nny','tt','tth','dd','ddh','nn','tt','th','d','dh','n','p','ph','b','bh','m','y','r','l','w','s','h','ll','a','[?]','i','ii','u','uu','e','[?]','o','au','[?]','aa','i','ii','u','uu','e','ai','[?]','[?]','[?]','N',"'",':','','[?]','[?]','[?]','[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9',' / ',' // ','n*','r*','l*','e*','sh','ss','R','RR','L','LL','R','RR','L','LL','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','A','B','G','D','E','V','Z','T`','I','K','L','M','N','O','P','Zh','R','S','T','U','P`','K`',"G'",'Q','Sh','Ch`','C`',"Z'",'C','Ch','X','J','H','E','Y','W','Xh','OE','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','a','b','g','d','e','v','z','t`','i','k','l','m','n','o','p','zh','r','s','t','u','p`','k`',"g'",'q','sh','ch`','c`',"z'",'c','ch','x','j','h','e','y','w','xh','oe','f','[?]','[?]','[?]','[?]',' // ','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x12] = array(
'g','gg','n','d','dd','r','m','b','bb','s','ss','','j','jj','c','k','t','p','h','ng','nn','nd','nb','dg','rn','rr','rh','rN','mb','mN','bg','bn','','bs','bsg','bst','bsb','bss','bsj','bj','bc','bt','bp','bN','bbN','sg','sn','sd','sr','sm','sb','sbg','sss','s','sj','sc','sk','st','sp','sh','','','','','Z','g','d','m','b','s','Z','','j','c','t','p','N','j','','','','','ck','ch','','','pb','pN','hh','Q','[?]','[?]','[?]','[?]','[?]','','','a','ae','ya','yae','eo','e','yeo','ye','o','wa','wae','oe','yo','u','weo','we','wi','yu','eu','yi','i','a-o','a-u','ya-o','ya-yo','eo-o','eo-u','eo-eu','yeo-o','yeo-u','o-eo','o-e','o-ye','o-o','o-u','yo-ya','yo-yae','yo-yeo','yo-o','yo-i','u-a','u-ae','u-eo-eu','u-ye','u-u','yu-a','yu-eo','yu-e','yu-yeo','yu-ye','yu-u','yu-i','eu-u','eu-eu','yi-u','i-a','i-ya','i-o','i-u','i-eu','i-U','U','U-eo','U-u','U-i','UU','[?]','[?]','[?]','[?]','[?]','g','gg','gs','n','nj','nh','d','l','lg','lm','lb','ls','lt','lp','lh','m','b','bs','s','ss','ng','j','c','k','t','p','h','gl','gsg','ng','nd','ns','nZ','nt','dg','tl','lgs','ln','ld','lth','ll','lmg','lms','lbs','lbh','rNp','lss','lZ','lk','lQ','mg','ml','mb','ms','mss','mZ','mc','mh','mN','bl','bp','ph','pN','sg','sd','sl','sb','Z','g','ss','','kh','N','Ns','NZ','pb','pN','hn','hl','hm','hb','Q','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x13] = array(
'ha','hu','hi','haa','hee','he','ho','[?]','la','lu','li','laa','lee','le','lo','lwa','hha','hhu','hhi','hhaa','hhee','hhe','hho','hhwa','ma','mu','mi','maa','mee','me','mo','mwa','sza','szu','szi','szaa','szee','sze','szo','szwa','ra','ru','ri','raa','ree','re','ro','rwa','sa','su','si','saa','see','se','so','swa','sha','shu','shi','shaa','shee','she','sho','shwa','qa','qu','qi','qaa','qee','qe','qo','[?]','qwa','[?]','qwi','qwaa','qwee','qwe','[?]','[?]','qha','qhu','qhi','qhaa','qhee','qhe','qho','[?]','qhwa','[?]','qhwi','qhwaa','qhwee','qhwe','[?]','[?]','ba','bu','bi','baa','bee','be','bo','bwa','va','vu','vi','vaa','vee','ve','vo','vwa','ta','tu','ti','taa','tee','te','to','twa','ca','cu','ci','caa','cee','ce','co','cwa','xa','xu','xi','xaa','xee','xe','xo','[?]','xwa','[?]','xwi','xwaa','xwee','xwe','[?]','[?]','na','nu','ni','naa','nee','ne','no','nwa','nya','nyu','nyi','nyaa','nyee','nye','nyo','nywa',"'a","'u",'[?]',"'aa","'ee","'e","'o","'wa",'ka','ku','ki','kaa','kee','ke','ko','[?]','kwa','[?]','kwi','kwaa','kwee','kwe','[?]','[?]','kxa','kxu','kxi','kxaa','kxee','kxe','kxo','[?]','kxwa','[?]','kxwi','kxwaa','kxwee','kxwe','[?]','[?]','wa','wu','wi','waa','wee','we','wo','[?]','`a','`u','`i','`aa','`ee','`e','`o','[?]','za','zu','zi','zaa','zee','ze','zo','zwa','zha','zhu','zhi','zhaa','zhee','zhe','zho','zhwa','ya','yu','yi','yaa','yee','ye','yo','[?]','da','du','di','daa','dee','de','do','dwa','dda','ddu','ddi','ddaa','ddee','dde','ddo','ddwa',
);
<?php
$UTF8_TO_ASCII[0x14] = array(
'ja','ju','ji','jaa','jee','je','jo','jwa','ga','gu','gi','gaa','gee','ge','go','[?]','gwa','[?]','gwi','gwaa','gwee','gwe','[?]','[?]','gga','ggu','ggi','ggaa','ggee','gge','ggo','[?]','tha','thu','thi','thaa','thee','the','tho','thwa','cha','chu','chi','chaa','chee','che','cho','chwa','pha','phu','phi','phaa','phee','phe','pho','phwa','tsa','tsu','tsi','tsaa','tsee','tse','tso','tswa','tza','tzu','tzi','tzaa','tzee','tze','tzo','[?]','fa','fu','fi','faa','fee','fe','fo','fwa','pa','pu','pi','paa','pee','pe','po','pwa','rya','mya','fya','[?]','[?]','[?]','[?]','[?]','[?]',' ','.',',',';',':',':: ','?','//','1','2','3','4','5','6','7','8','9','10+','20+','30+','40+','50+','60+','70+','80+','90+','100+','10,000+','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','a','e','i','o','u','v','ga','ka','ge','gi','go','gu','gv','ha','he','hi','ho','hu','hv','la','le','li','lo','lu','lv','ma','me','mi','mo','mu','na','hna','nah','ne','ni','no','nu','nv','qua','que','qui','quo','quu','quv','sa','s','se','si','so','su','sv','da','ta','de','te','di','ti','do','du','dv','dla','tla','tle','tli','tlo','tlu','tlv','tsa','tse','tsi','tso','tsu','tsv','wa','we','wi','wo','wu','wv','ya','ye','yi','yo','yu','yv','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x15] = array(
'[?]','e','aai','i','ii','o','oo','oo','ee','i','a','aa','we','we','wi','wi','wii','wii','wo','wo','woo','woo','woo','wa','wa','waa','waa','waa','ai','w',"'",'t','k','sh','s','n','w','n','[?]','w','c','?','l','en','in','on','an','pe','paai','pi','pii','po','poo','poo','hee','hi','pa','paa','pwe','pwe','pwi','pwi','pwii','pwii','pwo','pwo','pwoo','pwoo','pwa','pwa','pwaa','pwaa','pwaa','p','p','h','te','taai','ti','tii','to','too','too','dee','di','ta','taa','twe','twe','twi','twi','twii','twii','two','two','twoo','twoo','twa','twa','twaa','twaa','twaa','t','tte','tti','tto','tta','ke','kaai','ki','kii','ko','koo','koo','ka','kaa','kwe','kwe','kwi','kwi','kwii','kwii','kwo','kwo','kwoo','kwoo','kwa','kwa','kwaa','kwaa','kwaa','k','kw','keh','kih','koh','kah','ce','caai','ci','cii','co','coo','coo','ca','caa','cwe','cwe','cwi','cwi','cwii','cwii','cwo','cwo','cwoo','cwoo','cwa','cwa','cwaa','cwaa','cwaa','c','th','me','maai','mi','mii','mo','moo','moo','ma','maa','mwe','mwe','mwi','mwi','mwii','mwii','mwo','mwo','mwoo','mwoo','mwa','mwa','mwaa','mwaa','mwaa','m','m','mh','m','m','ne','naai','ni','nii','no','noo','noo','na','naa','nwe','nwe','nwa','nwa','nwaa','nwaa','nwaa','n','ng','nh','le','laai','li','lii','lo','loo','loo','la','laa','lwe','lwe','lwi','lwi','lwii','lwii','lwo','lwo','lwoo','lwoo','lwa','lwa','lwaa','lwaa','l','l','l','se','saai','si','sii','so','soo','soo','sa','saa','swe','swe','swi','swi','swii','swii','swo','swo','swoo','swoo',
);
<?php
$UTF8_TO_ASCII[0x16] = array(
'swa','swa','swaa','swaa','swaa','s','s','sw','s','sk','skw','sW','spwa','stwa','skwa','scwa','she','shi','shii','sho','shoo','sha','shaa','shwe','shwe','shwi','shwi','shwii','shwii','shwo','shwo','shwoo','shwoo','shwa','shwa','shwaa','shwaa','sh','ye','yaai','yi','yii','yo','yoo','yoo','ya','yaa','ywe','ywe','ywi','ywi','ywii','ywii','ywo','ywo','ywoo','ywoo','ywa','ywa','ywaa','ywaa','ywaa','y','y','y','yi','re','re','le','raai','ri','rii','ro','roo','lo','ra','raa','la','rwaa','rwaa','r','r','r','fe','faai','fi','fii','fo','foo','fa','faa','fwaa','fwaa','f','the','the','thi','thi','thii','thii','tho','thoo','tha','thaa','thwaa','thwaa','th','tthe','tthi','ttho','ttha','tth','tye','tyi','tyo','tya','he','hi','hii','ho','hoo','ha','haa','h','h','hk','qaai','qi','qii','qo','qoo','qa','qaa','q','tlhe','tlhi','tlho','tlha','re','ri','ro','ra','ngaai','ngi','ngii','ngo','ngoo','nga','ngaa','ng','nng','she','shi','sho','sha','the','thi','tho','tha','th','lhi','lhii','lho','lhoo','lha','lhaa','lh','the','thi','thii','tho','thoo','tha','thaa','th','b','e','i','o','a','we','wi','wo','wa','ne','ni','no','na','ke','ki','ko','ka','he','hi','ho','ha','ghu','gho','ghe','ghee','ghi','gha','ru','ro','re','ree','ri','ra','wu','wo','we','wee','wi','wa','hwu','hwo','hwe','hwee','hwi','hwa','thu','tho','the','thee','thi','tha','ttu','tto','tte','ttee','tti','tta','pu','po','pe','pee','pi','pa','p','gu','go','ge','gee','gi','ga','khu','kho','khe','khee','khi','kha','kku','kko','kke','kkee','kki',
);
<?php
$UTF8_TO_ASCII[0x17] = array(
'kka','kk','nu','no','ne','nee','ni','na','mu','mo','me','mee','mi','ma','yu','yo','ye','yee','yi','ya','ju','ju','jo','je','jee','ji','ji','ja','jju','jjo','jje','jjee','jji','jja','lu','lo','le','lee','li','la','dlu','dlo','dle','dlee','dli','dla','lhu','lho','lhe','lhee','lhi','lha','tlhu','tlho','tlhe','tlhee','tlhi','tlha','tlu','tlo','tle','tlee','tli','tla','zu','zo','ze','zee','zi','za','z','z','dzu','dzo','dze','dzee','dzi','dza','su','so','se','see','si','sa','shu','sho','she','shee','shi','sha','sh','tsu','tso','tse','tsee','tsi','tsa','chu','cho','che','chee','chi','cha','ttsu','ttso','ttse','ttsee','ttsi','ttsa','X','.','qai','ngai','nngi','nngii','nngo','nngoo','nnga','nngaa','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',' ','b','l','f','s','n','h','d','t','c','q','m','g','ng','z','r','a','o','u','e','i','ch','th','ph','p','x','p','<','>','[?]','[?]','[?]','f','v','u','yr','y','w','th','th','a','o','ac','ae','o','o','o','oe','on','r','k','c','k','g','ng','g','g','w','h','h','h','h','n','n','n','i','e','j','g','ae','a','eo','p','z','s','s','s','c','z','t','t','d','b','b','p','p','e','m','m','m','l','l','ng','ng','d','o','ear','ior','qu','qu','qu','s','yr','yr','yr','q','x','.',':','+','17','18','19','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x18] = array(
'[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','k','kh','g','gh','ng','c','ch','j','jh','ny','t','tth','d','ddh','nn','t','th','d','dh','n','p','ph','b','bh','m','y','r','l','v','sh','ss','s','h','l','q','a','aa','i','ii','u','uk','uu','uuv','ry','ryy','ly','lyy','e','ai','oo','oo','au','a','aa','aa','i','ii','y','yy','u','uu','ua','oe','ya','ie','e','ae','ai','oo','au','M','H','a`','','','','r','','!','','','','','','.',' // ',':','+','++',' * ',' /// ','KR',"'",'[?]','[?]','[?]','0','1','2','3','4','5','6','7','8','9','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x1e] = array(
' @ ',' ... ',', ','. ',': ',' // ','','-',', ','. ','','','','','','[?]','0','1','2','3','4','5','6','7','8','9','[?]','[?]','[?]','[?]','[?]','[?]','a','e','i','o','u','O','U','ee','n','ng','b','p','q','g','m','l','s','sh','t','d','ch','j','y','r','w','f','k','kha','ts','z','h','zr','lh','zh','ch','-','e','i','o','u','O','U','ng','b','p','q','g','m','t','d','ch','j','ts','y','w','k','g','h','jy','ny','dz','e','i','iy','U','u','ng','k','g','h','p','sh','t','d','j','f','g','h','ts','z','r','ch','zh','i','k','r','f','zh','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','H','X','W','M',' 3 ',' 333 ','a','i','k','ng','c','tt','tth','dd','nn','t','d','p','ph','ss','zh','z','a','t','zh','gh','ng','c','jh','tta','ddh','t','dh','ss','cy','zh','z','u','y','bh',"'",'[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x1f] = array(
);
<?php
$UTF8_TO_ASCII[0x20] = array(
);
<?php
$UTF8_TO_ASCII[0x21] = array(
);
<?php
$UTF8_TO_ASCII[0x22] = array(
);
<?php
$UTF8_TO_ASCII[0x23] = array(
);
<?php
$UTF8_TO_ASCII[0x24] = array(
'A','a','B','b','B','b','B','b','C','c','D','d','D','d','D','d','D','d','D','d','E','e','E','e','E','e','E','e','E','e','F','f','G','g','H','h','H','h','H','h','H','h','H','h','I','i','I','i','K','k','K','k','K','k','L','l','L','l','L','l','L','l','M','m','M','m','M','m','N','n','N','n','N','n','N','n','O','o','O','o','O','o','O','o','P','p','P','p','R','r','R','r','R','r','R','r','S','s','S','s','S','s','S','s','S','s','T','t','T','t','T','t','T','t','U','u','U','u','U','u','U','u','U','u','V','v','V','v','W','w','W','w','W','w','W','w','W','w','X','x','X','x','Y','y','Z','z','Z','z','Z','z','h','t','w','y','a','S','[?]','[?]','[?]','[?]','A','a','A','a','A','a','A','a','A','a','A','a','A','a','A','a','A','a','A','a','A','a','A','a','E','e','E','e','E','e','E','e','E','e','E','e','E','e','E','e','I','i','I','i','O','o','O','o','O','o','O','o','O','o','O','o','O','o','O','o','O','o','O','o','O','o','O','o','U','u','U','u','U','u','U','u','U','u','U','u','U','u','Y','y','Y','y','Y','y','Y','y','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x25] = array(
'a','a','a','a','a','a','a','a','A','A','A','A','A','A','A','A','e','e','e','e','e','e','[?]','[?]','E','E','E','E','E','E','[?]','[?]','e','e','e','e','e','e','e','e','E','E','E','E','E','E','E','E','i','i','i','i','i','i','i','i','I','I','I','I','I','I','I','I','o','o','o','o','o','o','[?]','[?]','O','O','O','O','O','O','[?]','[?]','u','u','u','u','u','u','u','u','[?]','U','[?]','U','[?]','U','[?]','U','o','o','o','o','o','o','o','o','O','O','O','O','O','O','O','O','a','a','e','e','e','e','i','i','o','o','u','u','o','o','[?]','[?]','a','a','a','a','a','a','a','a','A','A','A','A','A','A','A','A','e','e','e','e','e','e','e','e','E','E','E','E','E','E','E','E','o','o','o','o','o','o','o','o','O','O','O','O','O','O','O','O','a','a','a','a','a','[?]','a','a','A','A','A','A','A',"'",'i',"'",'~','"~','e','e','e','[?]','e','e','E','E','E','E','E',"'`","''","'~",'i','i','i','i','[?]','[?]','i','i','I','I','I','I','[?]',"`'","`'",'`~','u','u','u','u','R','R','u','u','U','U','U','U','R','"`',"0x22'",'`','[?]','[?]','o','o','o','[?]','o','o','O','O','O','O','O',"'",'`',
);
<?php
$UTF8_TO_ASCII[0x26] = array(
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','','','','','-','-','-','-','--','--','||','_',"'","'",',',"'",'"','"',',,','"','+','++','*','*>','.','..','...','.','
','
','','','','','',' ','%0','%00',"'","''","'''",'`','``','```','^','<','>','*','!!','!?','-','_','-','^','***','--','/','-[',']-','[?]','?!','!?','7','PP','(]','[)','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','','','','','','','0','','','','4','5','6','7','8','9','+','-','=','(',')','n','0','1','2','3','4','5','6','7','8','9','+','-','=','(',')','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','ECU','CL','Cr','FF','L','mil','N','Pts','Rs','W','NS','D','EU','K','T','Dr','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','','','','','','','','','','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x27] = array(
'','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',' 1/3 ',' 2/3 ',' 1/5 ',' 2/5 ',' 3/5 ',' 4/5 ',' 1/6 ',' 5/6 ',' 1/8 ',' 3/8 ',' 5/8 ',' 7/8 ',' 1/','I','II','III','IV','V','VI','VII','VIII','IX','X','XI','XII','L','C','D','M','i','ii','iii','iv','v','vi','vii','viii','ix','x','xi','xii','l','c','d','m','(D','D)','((|))',')','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','-','|','-','|','-','|','\\','/','\\','/','-','-','~','~','-','|','-','|','-','-','-','|','-','|','|','-','-','-','-','-','-','|','|','|','|','|','|','|','^','V','\\','=','V','^','-','-','|','|','-','-','|','|','=','|','=','=','|','=','|','=','=','=','=','=','=','|','=','|','=','|','\\','/','\\','/','=','=','~','~','|','|','-','|','-','|','-','-','-','|','-','|','|','|','|','|','|','|','-','\\','\\','|','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x28] = array(
'[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x2e] = array(
'[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x2f] = array(
'','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x30] = array(
'-','-','|','|','-','-','|','|','-','-','|','|','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','-','-','|','|','-','|','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','+','/','\\','X','-','|','-','|','-','|','-','|','-','|','-','|','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','-','|','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','^','^','^','^','>','>','>','>','>','>','V','V','V','V','<','<','<','<','<','<','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','#','#','#','#','#','^','^','^','O','#','#','#','#','#','#','#','#','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x31] = array(
'','','','','','','','','','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x32] = array(
'[?]','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','[?]','[?]','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','[?]','','','','','','','','','','','','','','','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x33] = array(
' ','a','1','b',"'",'k','2','l','@','c','i','f','/','m','s','p','"','e','3','h','9','o','6','r','^','d','j','g','>','n','t','q',',','*','5','<','-','u','8','v','.','%','[','$','+','x','!','&',';',':','4','\\','0','z','7','(','_','?','w',']','#','y',')','=','[d7]','[d17]','[d27]','[d127]','[d37]','[d137]','[d237]','[d1237]','[d47]','[d147]','[d247]','[d1247]','[d347]','[d1347]','[d2347]','[d12347]','[d57]','[d157]','[d257]','[d1257]','[d357]','[d1357]','[d2357]','[d12357]','[d457]','[d1457]','[d2457]','[d12457]','[d3457]','[d13457]','[d23457]','[d123457]','[d67]','[d167]','[d267]','[d1267]','[d367]','[d1367]','[d2367]','[d12367]','[d467]','[d1467]','[d2467]','[d12467]','[d3467]','[d13467]','[d23467]','[d123467]','[d567]','[d1567]','[d2567]','[d12567]','[d3567]','[d13567]','[d23567]','[d123567]','[d4567]','[d14567]','[d24567]','[d124567]','[d34567]','[d134567]','[d234567]','[d1234567]','[d8]','[d18]','[d28]','[d128]','[d38]','[d138]','[d238]','[d1238]','[d48]','[d148]','[d248]','[d1248]','[d348]','[d1348]','[d2348]','[d12348]','[d58]','[d158]','[d258]','[d1258]','[d358]','[d1358]','[d2358]','[d12358]','[d458]','[d1458]','[d2458]','[d12458]','[d3458]','[d13458]','[d23458]','[d123458]','[d68]','[d168]','[d268]','[d1268]','[d368]','[d1368]','[d2368]','[d12368]','[d468]','[d1468]','[d2468]','[d12468]','[d3468]','[d13468]','[d23468]','[d123468]','[d568]','[d1568]','[d2568]','[d12568]','[d3568]','[d13568]','[d23568]','[d123568]','[d4568]','[d14568]','[d24568]','[d124568]','[d34568]','[d134568]','[d234568]','[d1234568]','[d78]','[d178]','[d278]','[d1278]','[d378]','[d1378]','[d2378]','[d12378]','[d478]','[d1478]','[d2478]','[d12478]','[d3478]','[d13478]','[d23478]','[d123478]','[d578]','[d1578]','[d2578]','[d12578]','[d3578]','[d13578]','[d23578]','[d123578]','[d4578]','[d14578]','[d24578]','[d124578]','[d34578]','[d134578]','[d234578]','[d1234578]','[d678]','[d1678]','[d2678]','[d12678]','[d3678]','[d13678]','[d23678]','[d123678]','[d4678]','[d14678]','[d24678]','[d124678]','[d34678]','[d134678]','[d234678]','[d1234678]','[d5678]','[d15678]','[d25678]','[d125678]','[d35678]','[d135678]','[d235678]','[d1235678]','[d45678]','[d145678]','[d245678]','[d1245678]','[d345678]','[d1345678]','[d2345678]','[d12345678]',
);
<?php
$UTF8_TO_ASCII[0x4d] = array(
);
<?php
$UTF8_TO_ASCII[0x4e] = array(
);
<?php
$UTF8_TO_ASCII[0x4f] = array(
);
<?php
$UTF8_TO_ASCII[0x50] = array(
);
<?php
$UTF8_TO_ASCII[0x51] = array(
);
<?php
$UTF8_TO_ASCII[0x52] = array(
'[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?]','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x53] = array(
'[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x54] = array(
' ',', ','. ','"','[JIS]','"','/','0','<','> ','<<','>> ','[','] ','{','} ','[(',')] ','@','X ','[','] ','[[',']] ','((',')) ','[[',']] ','~ ','``',"''",',,','@','1','2','3','4','5','6','7','8','9','','','','','','','~','+','+','+','+','','@',' // ','+10+','+20+','+30+','[?]','[?]','[?]','','','[?]','a','a','i','i','u','u','e','e','o','o','ka','ga','ki','gi','ku','gu','ke','ge','ko','go','sa','za','si','zi','su','zu','se','ze','so','zo','ta','da','ti','di','tu','tu','du','te','de','to','do','na','ni','nu','ne','no','ha','ba','pa','hi','bi','pi','hu','bu','pu','he','be','pe','ho','bo','po','ma','mi','mu','me','mo','ya','ya','yu','yu','yo','yo','ra','ri','ru','re','ro','wa','wa','wi','we','wo','n','vu','[?]','[?]','[?]','[?]','','','','','"','"','[?]','[?]','a','a','i','i','u','u','e','e','o','o','ka','ga','ki','gi','ku','gu','ke','ge','ko','go','sa','za','si','zi','su','zu','se','ze','so','zo','ta','da','ti','di','tu','tu','du','te','de','to','do','na','ni','nu','ne','no','ha','ba','pa','hi','bi','pi','hu','bu','pu','he','be','pe','ho','bo','po','ma','mi','mu','me','mo','ya','ya','yu','yu','yo','yo','ra','ri','ru','re','ro','wa','wa','wi','we','wo','n','vu','ka','ke','va','vi','ve','vo','','','"','"',
);
<?php
$UTF8_TO_ASCII[0x55] = array(
'[?]','[?]','[?]','[?]','[?]','B','P','M','F','D','T','N','L','G','K','H','J','Q','X','ZH','CH','SH','R','Z','C','S','A','O','E','EH','AI','EI','AU','OU','AN','EN','ANG','ENG','ER','I','U','IU','V','NG','GN','[?]','[?]','[?]','[?]','g','gg','gs','n','nj','nh','d','dd','r','lg','lm','lb','ls','lt','lp','rh','m','b','bb','bs','s','ss','','j','jj','c','k','t','p','h','a','ae','ya','yae','eo','e','yeo','ye','o','wa','wae','oe','yo','u','weo','we','wi','yu','eu','yi','i','','nn','nd','ns','nZ','lgs','ld','lbs','lZ','lQ','mb','ms','mZ','mN','bg','','bsg','bst','bj','bt','bN','bbN','sg','sn','sd','sb','sj','Z','','N','Ns','NZ','pN','hh','Q','yo-ya','yo-yae','yo-i','yu-yeo','yu-ye','yu-i','U','U-i','[?]','','','','','','','','','','','','','','','','','BU','ZI','JI','GU','EE','ENN','OO','ONN','IR','ANN','INN','UNN','IM','NGG','AINN','AUNN','AM','OM','ONG','INNN','P','T','K','H','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x56] = array(
'(g)','(n)','(d)','(r)','(m)','(b)','(s)','()','(j)','(c)','(k)','(t)','(p)','(h)','(ga)','(na)','(da)','(ra)','(ma)','(ba)','(sa)','(a)','(ja)','(ca)','(ka)','(ta)','(pa)','(ha)','(ju)','[?]','[?]','[?]','(1) ','(2) ','(3) ','(4) ','(5) ','(6) ','(7) ','(8) ','(9) ','(10) ','(Yue) ','(Huo) ','(Shui) ','(Mu) ','(Jin) ','(Tu) ','(Ri) ','(Zhu) ','(You) ','(She) ','(Ming) ','(Te) ','(Cai) ','(Zhu) ','(Lao) ','(Dai) ','(Hu) ','(Xue) ','(Jian) ','(Qi) ','(Zi) ','(Xie) ','(Ji) ','(Xiu) ','<<','>>','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','(g)','(n)','(d)','(r)','(m)','(b)','(s)','()','(j)','(c)','(k)','(t)','(p)','(h)','(ga)','(na)','(da)','(ra)','(ma)','(ba)','(sa)','(a)','(ja)','(ca)','(ka)','(ta)','(pa)','(ha)','[?]','[?]','[?]','KIS ','(1) ','(2) ','(3) ','(4) ','(5) ','(6) ','(7) ','(8) ','(9) ','(10) ','(Yue) ','(Huo) ','(Shui) ','(Mu) ','(Jin) ','(Tu) ','(Ri) ','(Zhu) ','(You) ','(She) ','(Ming) ','(Te) ','(Cai) ','(Zhu) ','(Lao) ','(Mi) ','(Nan) ','(Nu) ','(Shi) ','(You) ','(Yin) ','(Zhu) ','(Xiang) ','(Xiu) ','(Xie) ','(Zheng) ','(Shang) ','(Zhong) ','(Xia) ','(Zuo) ','(You) ','(Yi) ','(Zong) ','(Xue) ','(Jian) ','(Qi) ','(Zi) ','(Xie) ','(Ye) ','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','1M','2M','3M','4M','5M','6M','7M','8M','9M','10M','11M','12M','[?]','[?]','[?]','[?]','a','i','u','u','o','ka','ki','ku','ke','ko','sa','si','su','se','so','ta','ti','tu','te','to','na','ni','nu','ne','no','ha','hi','hu','he','ho','ma','mi','mu','me','mo','ya','yu','yo','ra','ri','ru','re','ro','wa','wi','we','wo',
);
<?php
$UTF8_TO_ASCII[0x57] = array(
'apartment','alpha','ampere','are','inning','inch','won','escudo','acre','ounce','ohm','kai-ri','carat','calorie','gallon','gamma','giga','guinea','curie','guilder','kilo','kilogram','kilometer','kilowatt','gram','gram ton','cruzeiro','krone','case','koruna','co-op','cycle','centime','shilling','centi','cent','dozen','desi','dollar','ton','nano','knot','heights','percent','parts','barrel','piaster','picul','pico','building','farad','feet','bushel','franc','hectare','peso','pfennig','hertz','pence','page','beta','point','volt','hon','pound','hall','horn','micro','mile','mach','mark','mansion','micron','milli','millibar','mega','megaton','meter','yard','yard','yuan','liter','lira','rupee','ruble','rem','roentgen','watt','0h','1h','2h','3h','4h','5h','6h','7h','8h','9h','10h','11h','12h','13h','14h','15h','16h','17h','18h','19h','20h','21h','22h','23h','24h','HPA','da','AU','bar','oV','pc','[?]','[?]','[?]','[?]','Heisei','Syouwa','Taisyou','Meiji','Inc.','pA','nA','microamp','mA','kA','kB','MB','GB','cal','kcal','pF','nF','microFarad','microgram','mg','kg','Hz','kHz','MHz','GHz','THz','microliter','ml','dl','kl','fm','nm','micrometer','mm','cm','km','mm^2','cm^2','m^2','km^2','mm^4','cm^3','m^3','km^3','m/s','m/s^2','Pa','kPa','MPa','GPa','rad','rad/s','rad/s^2','ps','ns','microsecond','ms','pV','nV','microvolt','mV','kV','MV','pW','nW','microwatt','mW','kW','MW','kOhm','MOhm','a.m.','Bq','cc','cd','C/kg','Co.','dB','Gy','ha','HP','in','K.K.','KM','kt','lm','ln','log','lx','mb','mil','mol','pH','p.m.','PPM','PR','sr','Sv','Wb','[?]','[?]','1d','2d','3d','4d','5d','6d','7d','8d','9d','10d','11d','12d','13d','14d','15d','16d','17d','18d','19d','20d','21d','22d','23d','24d','25d','26d','27d','28d','29d','30d','31d',
);
<?php
$UTF8_TO_ASCII[0x58] = array(
);
<?php
$UTF8_TO_ASCII[0x59] = array(
);
<?php
$UTF8_TO_ASCII[0x5a] = array(
);
<?php
$UTF8_TO_ASCII[0x5b] = array(
);
<?php
$UTF8_TO_ASCII[0x5c] = array(
);
<?php
$UTF8_TO_ASCII[0x5d] = array(
);
<?php
$UTF8_TO_ASCII[0x5e] = array(
);
<?php
$UTF8_TO_ASCII[0x5f] = array(
);
<?php
$UTF8_TO_ASCII[0x60] = array(
);
<?php
$UTF8_TO_ASCII[0x61] = array(
);
<?php
$UTF8_TO_ASCII[0x62] = array(
);
<?php
$UTF8_TO_ASCII[0x63] = array(
);
<?php
$UTF8_TO_ASCII[0x64] = array(
);
<?php
$UTF8_TO_ASCII[0x65] = array(
);
<?php
$UTF8_TO_ASCII[0x66] = array(
);
<?php
$UTF8_TO_ASCII[0x67] = array(
);
<?php
$UTF8_TO_ASCII[0x68] = array(
);
<?php
$UTF8_TO_ASCII[0x69] = array(
);
<?php
$UTF8_TO_ASCII[0x6a] = array(
);
<?php
$UTF8_TO_ASCII[0x6b] = array(
);
<?php
$UTF8_TO_ASCII[0x6c] = array(
);
<?php
$UTF8_TO_ASCII[0x6d] = array(
);
<?php
$UTF8_TO_ASCII[0x6e] = array(
);
<?php
$UTF8_TO_ASCII[0x6f] = array(
);
<?php
$UTF8_TO_ASCII[0x70] = array(
);
<?php
$UTF8_TO_ASCII[0x71] = array(
'[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?] ','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0x72] = array(
'[?] ','Ding ','Kao ','Qi ','Shang ','Xia ','[?] ','Mo ','Zhang ','San ','Shang ','Xia ','Ji ','Bu ','Yu ','Mian ','Gai ','Chou ','Chou ','Zhuan ','Qie ','Pi ','Shi ','Shi ','Qiu ','Bing ','Ye ','Cong ','Dong ','Si ','Cheng ','Diu ','Qiu ','Liang ','Diu ','You ','Liang ','Yan ','Bing ','Sang ','Gun ','Jiu ','Ge ','Ya ','Qiang ','Zhong ','Ji ','Jie ','Feng ','Guan ','Chuan ','Chan ','Lin ','Zhuo ','Zhu ','Ha ','Wan ','Dan ','Wei ','Zhu ','Jing ','Li ','Ju ','Pie ','Fu ','Yi ','Yi ','Nai ','Shime ','Jiu ','Jiu ','Zhe ','Yao ','Yi ','[?] ','Zhi ','Wu ','Zha ','Hu ','Fa ','Le ','Zhong ','Ping ','Pang ','Qiao ','Hu ','Guai ','Cheng ','Cheng ','Yi ','Yin ','[?] ','Mie ','Jiu ','Qi ','Ye ','Xi ','Xiang ','Gai ','Diu ','Hal ','[?] ','Shu ','Twul ','Shi ','Ji ','Nang ','Jia ','Kel ','Shi ','[?] ','Ol ','Mai ','Luan ','Cal ','Ru ','Xue ','Yan ','Fu ','Sha ','Na ','Gan ','Sol ','El ','Cwul ','[?] ','Gan ','Chi ','Gui ','Gan ','Luan ','Lin ','Yi ','Jue ','Liao ','Ma ','Yu ','Zheng ','Shi ','Shi ','Er ','Chu ','Yu ','Yu ','Yu ','Yun ','Hu ','Qi ','Wu ','Jing ','Si ','Sui ','Gen ','Gen ','Ya ','Xie ','Ya ','Qi ','Ya ','Ji ','Tou ','Wang ','Kang ','Ta ','Jiao ','Hai ','Yi ','Chan ','Heng ','Mu ','[?] ','Xiang ','Jing ','Ting ','Liang ','Xiang ','Jing ','Ye ','Qin ','Bo ','You ','Xie ','Dan ','Lian ','Duo ','Wei ','Ren ','Ren ','Ji ','La ','Wang ','Yi ','Shi ','Ren ','Le ','Ding ','Ze ','Jin ','Pu ','Chou ','Ba ','Zhang ','Jin ','Jie ','Bing ','Reng ','Cong ','Fo ','San ','Lun ','Sya ','Cang ','Zi ','Shi ','Ta ','Zhang ','Fu ','Xian ','Xian ','Tuo ','Hong ','Tong ','Ren ','Qian ','Gan ','Yi ','Di ','Dai ','Ling ','Yi ','Chao ','Chang ','Sa ','[?] ','Yi ','Mu ','Men ','Ren ','Jia ','Chao ','Yang ','Qian ','Zhong ','Pi ','Wan ','Wu ','Jian ','Jie ','Yao ','Feng ','Cang ','Ren ','Wang ','Fen ','Di ','Fang ',
);
<?php
$UTF8_TO_ASCII[0x73] = array(
'Zhong ','Qi ','Pei ','Yu ','Diao ','Dun ','Wen ','Yi ','Xin ','Kang ','Yi ','Ji ','Ai ','Wu ','Ji ','Fu ','Fa ','Xiu ','Jin ','Bei ','Dan ','Fu ','Tang ','Zhong ','You ','Huo ','Hui ','Yu ','Cui ','Chuan ','San ','Wei ','Chuan ','Che ','Ya ','Xian ','Shang ','Chang ','Lun ','Cang ','Xun ','Xin ','Wei ','Zhu ','[?] ','Xuan ','Nu ','Bo ','Gu ','Ni ','Ni ','Xie ','Ban ','Xu ','Ling ','Zhou ','Shen ','Qu ','Si ','Beng ','Si ','Jia ','Pi ','Yi ','Si ','Ai ','Zheng ','Dian ','Han ','Mai ','Dan ','Zhu ','Bu ','Qu ','Bi ','Shao ','Ci ','Wei ','Di ','Zhu ','Zuo ','You ','Yang ','Ti ','Zhan ','He ','Bi ','Tuo ','She ','Yu ','Yi ','Fo ','Zuo ','Kou ','Ning ','Tong ','Ni ','Xuan ','Qu ','Yong ','Wa ','Qian ','[?] ','Ka ','[?] ','Pei ','Huai ','He ','Lao ','Xiang ','Ge ','Yang ','Bai ','Fa ','Ming ','Jia ','Er ','Bing ','Ji ','Hen ','Huo ','Gui ','Quan ','Tiao ','Jiao ','Ci ','Yi ','Shi ','Xing ','Shen ','Tuo ','Kan ','Zhi ','Gai ','Lai ','Yi ','Chi ','Kua ','Guang ','Li ','Yin ','Shi ','Mi ','Zhu ','Xu ','You ','An ','Lu ','Mou ','Er ','Lun ','Tong ','Cha ','Chi ','Xun ','Gong ','Zhou ','Yi ','Ru ','Jian ','Xia ','Jia ','Zai ','Lu ','Ko ','Jiao ','Zhen ','Ce ','Qiao ','Kuai ','Chai ','Ning ','Nong ','Jin ','Wu ','Hou ','Jiong ','Cheng ','Zhen ','Zuo ','Chou ','Qin ','Lu ','Ju ','Shu ','Ting ','Shen ','Tuo ','Bo ','Nan ','Hao ','Bian ','Tui ','Yu ','Xi ','Cu ','E ','Qiu ','Xu ','Kuang ','Ku ','Wu ','Jun ','Yi ','Fu ','Lang ','Zu ','Qiao ','Li ','Yong ','Hun ','Jing ','Xian ','San ','Pai ','Su ','Fu ','Xi ','Li ','Fu ','Ping ','Bao ','Yu ','Si ','Xia ','Xin ','Xiu ','Yu ','Ti ','Che ','Chou ','[?] ','Yan ','Lia ','Li ','Lai ','[?] ','Jian ','Xiu ','Fu ','He ','Ju ','Xiao ','Pai ','Jian ','Biao ','Chu ','Fei ','Feng ','Ya ','An ','Bei ','Yu ','Xin ','Bi ','Jian ',
);
<?php
$UTF8_TO_ASCII[0x74] = array(
'Chang ','Chi ','Bing ','Zan ','Yao ','Cui ','Lia ','Wan ','Lai ','Cang ','Zong ','Ge ','Guan ','Bei ','Tian ','Shu ','Shu ','Men ','Dao ','Tan ','Jue ','Chui ','Xing ','Peng ','Tang ','Hou ','Yi ','Qi ','Ti ','Gan ','Jing ','Jie ','Sui ','Chang ','Jie ','Fang ','Zhi ','Kong ','Juan ','Zong ','Ju ','Qian ','Ni ','Lun ','Zhuo ','Wei ','Luo ','Song ','Leng ','Hun ','Dong ','Zi ','Ben ','Wu ','Ju ','Nai ','Cai ','Jian ','Zhai ','Ye ','Zhi ','Sha ','Qing ','[?] ','Ying ','Cheng ','Jian ','Yan ','Nuan ','Zhong ','Chun ','Jia ','Jie ','Wei ','Yu ','Bing ','Ruo ','Ti ','Wei ','Pian ','Yan ','Feng ','Tang ','Wo ','E ','Xie ','Che ','Sheng ','Kan ','Di ','Zuo ','Cha ','Ting ','Bei ','Ye ','Huang ','Yao ','Zhan ','Chou ','Yan ','You ','Jian ','Xu ','Zha ','Ci ','Fu ','Bi ','Zhi ','Zong ','Mian ','Ji ','Yi ','Xie ','Xun ','Si ','Duan ','Ce ','Zhen ','Ou ','Tou ','Tou ','Bei ','Za ','Lu ','Jie ','Wei ','Fen ','Chang ','Gui ','Sou ','Zhi ','Su ','Xia ','Fu ','Yuan ','Rong ','Li ','Ru ','Yun ','Gou ','Ma ','Bang ','Dian ','Tang ','Hao ','Jie ','Xi ','Shan ','Qian ','Jue ','Cang ','Chu ','San ','Bei ','Xiao ','Yong ','Yao ','Tan ','Suo ','Yang ','Fa ','Bing ','Jia ','Dai ','Zai ','Tang ','[?] ','Bin ','Chu ','Nuo ','Can ','Lei ','Cui ','Yong ','Zao ','Zong ','Peng ','Song ','Ao ','Chuan ','Yu ','Zhai ','Cou ','Shang ','Qiang ','Jing ','Chi ','Sha ','Han ','Zhang ','Qing ','Yan ','Di ','Xi ','Lu ','Bei ','Piao ','Jin ','Lian ','Lu ','Man ','Qian ','Xian ','Tan ','Ying ','Dong ','Zhuan ','Xiang ','Shan ','Qiao ','Jiong ','Tui ','Zun ','Pu ','Xi ','Lao ','Chang ','Guang ','Liao ','Qi ','Deng ','Chan ','Wei ','Ji ','Fan ','Hui ','Chuan ','Jian ','Dan ','Jiao ','Jiu ','Seng ','Fen ','Xian ','Jue ','E ','Jiao ','Jian ','Tong ','Lin ','Bo ','Gu ','[?] ','Su ','Xian ','Jiang ','Min ','Ye ','Jin ','Jia ','Qiao ','Pi ','Feng ','Zhou ','Ai ','Sai ',
);
<?php
$UTF8_TO_ASCII[0x75] = array(
'Yi ','Jun ','Nong ','Chan ','Yi ','Dang ','Jing ','Xuan ','Kuai ','Jian ','Chu ','Dan ','Jiao ','Sha ','Zai ','[?] ','Bin ','An ','Ru ','Tai ','Chou ','Chai ','Lan ','Ni ','Jin ','Qian ','Meng ','Wu ','Ning ','Qiong ','Ni ','Chang ','Lie ','Lei ','Lu ','Kuang ','Bao ','Du ','Biao ','Zan ','Zhi ','Si ','You ','Hao ','Chen ','Chen ','Li ','Teng ','Wei ','Long ','Chu ','Chan ','Rang ','Shu ','Hui ','Li ','Luo ','Zan ','Nuo ','Tang ','Yan ','Lei ','Nang ','Er ','Wu ','Yun ','Zan ','Yuan ','Xiong ','Chong ','Zhao ','Xiong ','Xian ','Guang ','Dui ','Ke ','Dui ','Mian ','Tu ','Chang ','Er ','Dui ','Er ','Xin ','Tu ','Si ','Yan ','Yan ','Shi ','Shi ','Dang ','Qian ','Dou ','Fen ','Mao ','Shen ','Dou ','Bai ','Jing ','Li ','Huang ','Ru ','Wang ','Nei ','Quan ','Liang ','Yu ','Ba ','Gong ','Liu ','Xi ','[?] ','Lan ','Gong ','Tian ','Guan ','Xing ','Bing ','Qi ','Ju ','Dian ','Zi ','Ppwun ','Yang ','Jian ','Shou ','Ji ','Yi ','Ji ','Chan ','Jiong ','Mao ','Ran ','Nei ','Yuan ','Mao ','Gang ','Ran ','Ce ','Jiong ','Ce ','Zai ','Gua ','Jiong ','Mao ','Zhou ','Mou ','Gou ','Xu ','Mian ','Mi ','Rong ','Yin ','Xie ','Kan ','Jun ','Nong ','Yi ','Mi ','Shi ','Guan ','Meng ','Zhong ','Ju ','Yuan ','Ming ','Kou ','Lam ','Fu ','Xie ','Mi ','Bing ','Dong ','Tai ','Gang ','Feng ','Bing ','Hu ','Chong ','Jue ','Hu ','Kuang ','Ye ','Leng ','Pan ','Fu ','Min ','Dong ','Xian ','Lie ','Xia ','Jian ','Jing ','Shu ','Mei ','Tu ','Qi ','Gu ','Zhun ','Song ','Jing ','Liang ','Qing ','Diao ','Ling ','Dong ','Gan ','Jian ','Yin ','Cou ','Yi ','Li ','Cang ','Ming ','Zhuen ','Cui ','Si ','Duo ','Jin ','Lin ','Lin ','Ning ','Xi ','Du ','Ji ','Fan ','Fan ','Fan ','Feng ','Ju ','Chu ','Tako ','Feng ','Mok ','Ci ','Fu ','Feng ','Ping ','Feng ','Kai ','Huang ','Kai ','Gan ','Deng ','Ping ','Qu ','Xiong ','Kuai ','Tu ','Ao ','Chu ','Ji ','Dang ','Han ','Han ','Zao ',
);
<?php
$UTF8_TO_ASCII[0x76] = array(
'Dao ','Diao ','Dao ','Ren ','Ren ','Chuang ','Fen ','Qie ','Yi ','Ji ','Kan ','Qian ','Cun ','Chu ','Wen ','Ji ','Dan ','Xing ','Hua ','Wan ','Jue ','Li ','Yue ','Lie ','Liu ','Ze ','Gang ','Chuang ','Fu ','Chu ','Qu ','Ju ','Shan ','Min ','Ling ','Zhong ','Pan ','Bie ','Jie ','Jie ','Bao ','Li ','Shan ','Bie ','Chan ','Jing ','Gua ','Gen ','Dao ','Chuang ','Kui ','Ku ','Duo ','Er ','Zhi ','Shua ','Quan ','Cha ','Ci ','Ke ','Jie ','Gui ','Ci ','Gui ','Kai ','Duo ','Ji ','Ti ','Jing ','Lou ','Gen ','Ze ','Yuan ','Cuo ','Xue ','Ke ','La ','Qian ','Cha ','Chuang ','Gua ','Jian ','Cuo ','Li ','Ti ','Fei ','Pou ','Chan ','Qi ','Chuang ','Zi ','Gang ','Wan ','Bo ','Ji ','Duo ','Qing ','Yan ','Zhuo ','Jian ','Ji ','Bo ','Yan ','Ju ','Huo ','Sheng ','Jian ','Duo ','Duan ','Wu ','Gua ','Fu ','Sheng ','Jian ','Ge ','Zha ','Kai ','Chuang ','Juan ','Chan ','Tuan ','Lu ','Li ','Fou ','Shan ','Piao ','Kou ','Jiao ','Gua ','Qiao ','Jue ','Hua ','Zha ','Zhuo ','Lian ','Ju ','Pi ','Liu ','Gui ','Jiao ','Gui ','Jian ','Jian ','Tang ','Huo ','Ji ','Jian ','Yi ','Jian ','Zhi ','Chan ','Cuan ','Mo ','Li ','Zhu ','Li ','Ya ','Quan ','Ban ','Gong ','Jia ','Wu ','Mai ','Lie ','Jin ','Keng ','Xie ','Zhi ','Dong ','Zhu ','Nu ','Jie ','Qu ','Shao ','Yi ','Zhu ','Miao ','Li ','Jing ','Lao ','Lao ','Juan ','Kou ','Yang ','Wa ','Xiao ','Mou ','Kuang ','Jie ','Lie ','He ','Shi ','Ke ','Jing ','Hao ','Bo ','Min ','Chi ','Lang ','Yong ','Yong ','Mian ','Ke ','Xun ','Juan ','Qing ','Lu ','Pou ','Meng ','Lai ','Le ','Kai ','Mian ','Dong ','Xu ','Xu ','Kan ','Wu ','Yi ','Xun ','Weng ','Sheng ','Lao ','Mu ','Lu ','Piao ','Shi ','Ji ','Qin ','Qiang ','Jiao ','Quan ','Yang ','Yi ','Jue ','Fan ','Juan ','Tong ','Ju ','Dan ','Xie ','Mai ','Xun ','Xun ','Lu ','Li ','Che ','Rang ','Quan ','Bao ','Shao ','Yun ','Jiu ','Bao ','Gou ','Wu ',
);
<?php
$UTF8_TO_ASCII[0x77] = array(
'Yun ','Mwun ','Nay ','Gai ','Gai ','Bao ','Cong ','[?] ','Xiong ','Peng ','Ju ','Tao ','Ge ','Pu ','An ','Pao ','Fu ','Gong ','Da ','Jiu ','Qiong ','Bi ','Hua ','Bei ','Nao ','Chi ','Fang ','Jiu ','Yi ','Za ','Jiang ','Kang ','Jiang ','Kuang ','Hu ','Xia ','Qu ','Bian ','Gui ','Qie ','Zang ','Kuang ','Fei ','Hu ','Tou ','Gui ','Gui ','Hui ','Dan ','Gui ','Lian ','Lian ','Suan ','Du ','Jiu ','Qu ','Xi ','Pi ','Qu ','Yi ','Qia ','Yan ','Bian ','Ni ','Qu ','Shi ','Xin ','Qian ','Nian ','Sa ','Zu ','Sheng ','Wu ','Hui ','Ban ','Shi ','Xi ','Wan ','Hua ','Xie ','Wan ','Bei ','Zu ','Zhuo ','Xie ','Dan ','Mai ','Nan ','Dan ','Ji ','Bo ','Shuai ','Bu ','Kuang ','Bian ','Bu ','Zhan ','Qia ','Lu ','You ','Lu ','Xi ','Gua ','Wo ','Xie ','Jie ','Jie ','Wei ','Ang ','Qiong ','Zhi ','Mao ','Yin ','Wei ','Shao ','Ji ','Que ','Luan ','Shi ','Juan ','Xie ','Xu ','Jin ','Que ','Wu ','Ji ','E ','Qing ','Xi ','[?] ','Han ','Zhan ','E ','Ting ','Li ','Zhe ','Han ','Li ','Ya ','Ya ','Yan ','She ','Zhi ','Zha ','Pang ','[?] ','He ','Ya ','Zhi ','Ce ','Pang ','Ti ','Li ','She ','Hou ','Ting ','Zui ','Cuo ','Fei ','Yuan ','Ce ','Yuan ','Xiang ','Yan ','Li ','Jue ','Sha ','Dian ','Chu ','Jiu ','Qin ','Ao ','Gui ','Yan ','Si ','Li ','Chang ','Lan ','Li ','Yan ','Yan ','Yuan ','Si ','Gong ','Lin ','Qiu ','Qu ','Qu ','Uk ','Lei ','Du ','Xian ','Zhuan ','San ','Can ','Can ','Can ','Can ','Ai ','Dai ','You ','Cha ','Ji ','You ','Shuang ','Fan ','Shou ','Guai ','Ba ','Fa ','Ruo ','Shi ','Shu ','Zhuo ','Qu ','Shou ','Bian ','Xu ','Jia ','Pan ','Sou ','Gao ','Wei ','Sou ','Die ','Rui ','Cong ','Kou ','Gu ','Ju ','Ling ','Gua ','Tao ','Kou ','Zhi ','Jiao ','Zhao ','Ba ','Ding ','Ke ','Tai ','Chi ','Shi ','You ','Qiu ','Po ','Xie ','Hao ','Si ','Tan ','Chi ','Le ','Diao ','Ji ','[?] ','Hong ',
);
<?php
$UTF8_TO_ASCII[0x78] = array(
'Mie ','Xu ','Mang ','Chi ','Ge ','Xuan ','Yao ','Zi ','He ','Ji ','Diao ','Cun ','Tong ','Ming ','Hou ','Li ','Tu ','Xiang ','Zha ','Xia ','Ye ','Lu ','A ','Ma ','Ou ','Xue ','Yi ','Jun ','Chou ','Lin ','Tun ','Yin ','Fei ','Bi ','Qin ','Qin ','Jie ','Bu ','Fou ','Ba ','Dun ','Fen ','E ','Han ','Ting ','Hang ','Shun ','Qi ','Hong ','Zhi ','Shen ','Wu ','Wu ','Chao ','Ne ','Xue ','Xi ','Chui ','Dou ','Wen ','Hou ','Ou ','Wu ','Gao ','Ya ','Jun ','Lu ','E ','Ge ','Mei ','Ai ','Qi ','Cheng ','Wu ','Gao ','Fu ','Jiao ','Hong ','Chi ','Sheng ','Ne ','Tun ','Fu ','Yi ','Dai ','Ou ','Li ','Bai ','Yuan ','Kuai ','[?] ','Qiang ','Wu ','E ','Shi ','Quan ','Pen ','Wen ','Ni ','M ','Ling ','Ran ','You ','Di ','Zhou ','Shi ','Zhou ','Tie ','Xi ','Yi ','Qi ','Ping ','Zi ','Gu ','Zi ','Wei ','Xu ','He ','Nao ','Xia ','Pei ','Yi ','Xiao ','Shen ','Hu ','Ming ','Da ','Qu ','Ju ','Gem ','Za ','Tuo ','Duo ','Pou ','Pao ','Bi ','Fu ','Yang ','He ','Zha ','He ','Hai ','Jiu ','Yong ','Fu ','Que ','Zhou ','Wa ','Ka ','Gu ','Ka ','Zuo ','Bu ','Long ','Dong ','Ning ','Tha ','Si ','Xian ','Huo ','Qi ','Er ','E ','Guang ','Zha ','Xi ','Yi ','Lie ','Zi ','Mie ','Mi ','Zhi ','Yao ','Ji ','Zhou ','Ge ','Shuai ','Zan ','Xiao ','Ke ','Hui ','Kua ','Huai ','Tao ','Xian ','E ','Xuan ','Xiu ','Wai ','Yan ','Lao ','Yi ','Ai ','Pin ','Shen ','Tong ','Hong ','Xiong ','Chi ','Wa ','Ha ','Zai ','Yu ','Di ','Pai ','Xiang ','Ai ','Hen ','Kuang ','Ya ','Da ','Xiao ','Bi ','Yue ','[?] ','Hua ','Sasou ','Kuai ','Duo ','[?] ','Ji ','Nong ','Mou ','Yo ','Hao ','Yuan ','Long ','Pou ','Mang ','Ge ','E ','Chi ','Shao ','Li ','Na ','Zu ','He ','Ku ','Xiao ','Xian ','Lao ','Bo ','Zhe ','Zha ','Liang ','Ba ','Mie ','Le ','Sui ','Fou ','Bu ','Han ','Heng ','Geng ','Shuo ','Ge ',
);
<?php
$UTF8_TO_ASCII[0x79] = array(
'You ','Yan ','Gu ','Gu ','Bai ','Han ','Suo ','Chun ','Yi ','Ai ','Jia ','Tu ','Xian ','Huan ','Li ','Xi ','Tang ','Zuo ','Qiu ','Che ','Wu ','Zao ','Ya ','Dou ','Qi ','Di ','Qin ','Ma ','Mal ','Hong ','Dou ','Kes ','Lao ','Liang ','Suo ','Zao ','Huan ','Lang ','Sha ','Ji ','Zuo ','Wo ','Feng ','Yin ','Hu ','Qi ','Shou ','Wei ','Shua ','Chang ','Er ','Li ','Qiang ','An ','Jie ','Yo ','Nian ','Yu ','Tian ','Lai ','Sha ','Xi ','Tuo ','Hu ','Ai ','Zhou ','Nou ','Ken ','Zhuo ','Zhuo ','Shang ','Di ','Heng ','Lan ','A ','Xiao ','Xiang ','Tun ','Wu ','Wen ','Cui ','Sha ','Hu ','Qi ','Qi ','Tao ','Dan ','Dan ','Ye ','Zi ','Bi ','Cui ','Chuo ','He ','Ya ','Qi ','Zhe ','Pei ','Liang ','Xian ','Pi ','Sha ','La ','Ze ','Qing ','Gua ','Pa ','Zhe ','Se ','Zhuan ','Nie ','Guo ','Luo ','Yan ','Di ','Quan ','Tan ','Bo ','Ding ','Lang ','Xiao ','[?] ','Tang ','Chi ','Ti ','An ','Jiu ','Dan ','Ke ','Yong ','Wei ','Nan ','Shan ','Yu ','Zhe ','La ','Jie ','Hou ','Han ','Die ','Zhou ','Chai ','Wai ','Re ','Yu ','Yin ','Zan ','Yao ','Wo ','Mian ','Hu ','Yun ','Chuan ','Hui ','Huan ','Huan ','Xi ','He ','Ji ','Kui ','Zhong ','Wei ','Sha ','Xu ','Huang ','Du ','Nie ','Xuan ','Liang ','Yu ','Sang ','Chi ','Qiao ','Yan ','Dan ','Pen ','Can ','Li ','Yo ','Zha ','Wei ','Miao ','Ying ','Pen ','Phos ','Kui ','Xi ','Yu ','Jie ','Lou ','Ku ','Sao ','Huo ','Ti ','Yao ','He ','A ','Xiu ','Qiang ','Se ','Yong ','Su ','Hong ','Xie ','Yi ','Suo ','Ma ','Cha ','Hai ','Ke ','Ta ','Sang ','Tian ','Ru ','Sou ','Wa ','Ji ','Pang ','Wu ','Xian ','Shi ','Ge ','Zi ','Jie ','Luo ','Weng ','Wa ','Si ','Chi ','Hao ','Suo ','Jia ','Hai ','Suo ','Qin ','Nie ','He ','Cis ','Sai ','Ng ','Ge ','Na ','Dia ','Ai ','[?] ','Tong ','Bi ','Ao ','Ao ','Lian ','Cui ','Zhe ','Mo ','Sou ','Sou ','Tan ',
);
<?php
$UTF8_TO_ASCII[0x7a] = array(
'Di ','Qi ','Jiao ','Chong ','Jiao ','Kai ','Tan ','San ','Cao ','Jia ','Ai ','Xiao ','Piao ','Lou ','Ga ','Gu ','Xiao ','Hu ','Hui ','Guo ','Ou ','Xian ','Ze ','Chang ','Xu ','Po ','De ','Ma ','Ma ','Hu ','Lei ','Du ','Ga ','Tang ','Ye ','Beng ','Ying ','Saai ','Jiao ','Mi ','Xiao ','Hua ','Mai ','Ran ','Zuo ','Peng ','Lao ','Xiao ','Ji ','Zhu ','Chao ','Kui ','Zui ','Xiao ','Si ','Hao ','Fu ','Liao ','Qiao ','Xi ','Xiu ','Tan ','Tan ','Mo ','Xun ','E ','Zun ','Fan ','Chi ','Hui ','Zan ','Chuang ','Cu ','Dan ','Yu ','Tun ','Cheng ','Jiao ','Ye ','Xi ','Qi ','Hao ','Lian ','Xu ','Deng ','Hui ','Yin ','Pu ','Jue ','Qin ','Xun ','Nie ','Lu ','Si ','Yan ','Ying ','Da ','Dan ','Yu ','Zhou ','Jin ','Nong ','Yue ','Hui ','Qi ','E ','Zao ','Yi ','Shi ','Jiao ','Yuan ','Ai ','Yong ','Jue ','Kuai ','Yu ','Pen ','Dao ','Ge ','Xin ','Dun ','Dang ','Sin ','Sai ','Pi ','Pi ','Yin ','Zui ','Ning ','Di ','Lan ','Ta ','Huo ','Ru ','Hao ','Xia ','Ya ','Duo ','Xi ','Chou ','Ji ','Jin ','Hao ','Ti ','Chang ','[?] ','[?] ','Ca ','Ti ','Lu ','Hui ','Bo ','You ','Nie ','Yin ','Hu ','Mo ','Huang ','Zhe ','Li ','Liu ','Haai ','Nang ','Xiao ','Mo ','Yan ','Li ','Lu ','Long ','Fu ','Dan ','Chen ','Pin ','Pi ','Xiang ','Huo ','Mo ','Xi ','Duo ','Ku ','Yan ','Chan ','Ying ','Rang ','Dian ','La ','Ta ','Xiao ','Jiao ','Chuo ','Huan ','Huo ','Zhuan ','Nie ','Xiao ','Ca ','Li ','Chan ','Chai ','Li ','Yi ','Luo ','Nang ','Zan ','Su ','Xi ','So ','Jian ','Za ','Zhu ','Lan ','Nie ','Nang ','[?] ','[?] ','Wei ','Hui ','Yin ','Qiu ','Si ','Nin ','Jian ','Hui ','Xin ','Yin ','Nan ','Tuan ','Tuan ','Dun ','Kang ','Yuan ','Jiong ','Pian ','Yun ','Cong ','Hu ','Hui ','Yuan ','You ','Guo ','Kun ','Cong ','Wei ','Tu ','Wei ','Lun ','Guo ','Qun ','Ri ','Ling ','Gu ','Guo ','Tai ','Guo ','Tu ','You ',
);
<?php
$UTF8_TO_ASCII[0x7b] = array(
'Guo ','Yin ','Hun ','Pu ','Yu ','Han ','Yuan ','Lun ','Quan ','Yu ','Qing ','Guo ','Chuan ','Wei ','Yuan ','Quan ','Ku ','Fu ','Yuan ','Yuan ','E ','Tu ','Tu ','Tu ','Tuan ','Lue ','Hui ','Yi ','Yuan ','Luan ','Luan ','Tu ','Ya ','Tu ','Ting ','Sheng ','Pu ','Lu ','Iri ','Ya ','Zai ','Wei ','Ge ','Yu ','Wu ','Gui ','Pi ','Yi ','Di ','Qian ','Qian ','Zhen ','Zhuo ','Dang ','Qia ','Akutsu ','Yama ','Kuang ','Chang ','Qi ','Nie ','Mo ','Ji ','Jia ','Zhi ','Zhi ','Ban ','Xun ','Tou ','Qin ','Fen ','Jun ','Keng ','Tun ','Fang ','Fen ','Ben ','Tan ','Kan ','Pi ','Zuo ','Keng ','Bi ','Xing ','Di ','Jing ','Ji ','Kuai ','Di ','Jing ','Jian ','Tan ','Li ','Ba ','Wu ','Fen ','Zhui ','Po ','Pan ','Tang ','Kun ','Qu ','Tan ','Zhi ','Tuo ','Gan ','Ping ','Dian ','Gua ','Ni ','Tai ','Pi ','Jiong ','Yang ','Fo ','Ao ','Liu ','Qiu ','Mu ','Ke ','Gou ','Xue ','Ba ','Chi ','Che ','Ling ','Zhu ','Fu ','Hu ','Zhi ','Chui ','La ','Long ','Long ','Lu ','Ao ','Tay ','Pao ','[?] ','Xing ','Dong ','Ji ','Ke ','Lu ','Ci ','Chi ','Lei ','Gai ','Yin ','Hou ','Dui ','Zhao ','Fu ','Guang ','Yao ','Duo ','Duo ','Gui ','Cha ','Yang ','Yin ','Fa ','Gou ','Yuan ','Die ','Xie ','Ken ','Jiong ','Shou ','E ','Ha ','Dian ','Hong ','Wu ','Kua ','[?] ','Tao ','Dang ','Kai ','Gake ','Nao ','An ','Xing ','Xian ','Huan ','Bang ','Pei ','Ba ','Yi ','Yin ','Han ','Xu ','Chui ','Cen ','Geng ','Ai ','Peng ','Fang ','Que ','Yong ','Xun ','Jia ','Di ','Mai ','Lang ','Xuan ','Cheng ','Yan ','Jin ','Zhe ','Lei ','Lie ','Bu ','Cheng ','Gomi ','Bu ','Shi ','Xun ','Guo ','Jiong ','Ye ','Nian ','Di ','Yu ','Bu ','Ya ','Juan ','Sui ','Pi ','Cheng ','Wan ','Ju ','Lun ','Zheng ','Kong ','Chong ','Dong ','Dai ','Tan ','An ','Cai ','Shu ','Beng ','Kan ','Zhi ','Duo ','Yi ','Zhi ','Yi ','Pei ','Ji ','Zhun ','Qi ','Sao ','Ju ','Ni ',
);
<?php
$UTF8_TO_ASCII[0x7c] = array(
'Ku ','Ke ','Tang ','Kun ','Ni ','Jian ','Dui ','Jin ','Gang ','Yu ','E ','Peng ','Gu ','Tu ','Leng ','[?] ','Ya ','Qian ','[?] ','An ','[?] ','Duo ','Nao ','Tu ','Cheng ','Yin ','Hun ','Bi ','Lian ','Guo ','Die ','Zhuan ','Hou ','Bao ','Bao ','Yu ','Di ','Mao ','Jie ','Ruan ','E ','Geng ','Kan ','Zong ','Yu ','Huang ','E ','Yao ','Yan ','Bao ','Ji ','Mei ','Chang ','Du ','Tuo ','Yin ','Feng ','Zhong ','Jie ','Zhen ','Feng ','Gang ','Chuan ','Jian ','Pyeng ','Toride ','Xiang ','Huang ','Leng ','Duan ','[?] ','Xuan ','Ji ','Ji ','Kuai ','Ying ','Ta ','Cheng ','Yong ','Kai ','Su ','Su ','Shi ','Mi ','Ta ','Weng ','Cheng ','Tu ','Tang ','Que ','Zhong ','Li ','Peng ','Bang ','Sai ','Zang ','Dui ','Tian ','Wu ','Cheng ','Xun ','Ge ','Zhen ','Ai ','Gong ','Yan ','Kan ','Tian ','Yuan ','Wen ','Xie ','Liu ','Ama ','Lang ','Chang ','Peng ','Beng ','Chen ','Cu ','Lu ','Ou ','Qian ','Mei ','Mo ','Zhuan ','Shuang ','Shu ','Lou ','Chi ','Man ','Biao ','Jing ','Qi ','Shu ','Di ','Zhang ','Kan ','Yong ','Dian ','Chen ','Zhi ','Xi ','Guo ','Qiang ','Jin ','Di ','Shang ','Mu ','Cui ','Yan ','Ta ','Zeng ','Qi ','Qiang ','Liang ','[?] ','Zhui ','Qiao ','Zeng ','Xu ','Shan ','Shan ','Ba ','Pu ','Kuai ','Dong ','Fan ','Que ','Mo ','Dun ','Dun ','Dun ','Di ','Sheng ','Duo ','Duo ','Tan ','Deng ','Wu ','Fen ','Huang ','Tan ','Da ','Ye ','Sho ','Mama ','Yu ','Qiang ','Ji ','Qiao ','Ken ','Yi ','Pi ','Bi ','Dian ','Jiang ','Ye ','Yong ','Bo ','Tan ','Lan ','Ju ','Huai ','Dang ','Rang ','Qian ','Xun ','Lan ','Xi ','He ','Ai ','Ya ','Dao ','Hao ','Ruan ','Mama ','Lei ','Kuang ','Lu ','Yan ','Tan ','Wei ','Huai ','Long ','Long ','Rui ','Li ','Lin ','Rang ','Ten ','Xun ','Yan ','Lei ','Ba ','[?] ','Shi ','Ren ','[?] ','Zhuang ','Zhuang ','Sheng ','Yi ','Mai ','Ke ','Zhu ','Zhuang ','Hu ','Hu ','Kun ','Yi ','Hu ','Xu ','Kun ','Shou ','Mang ','Zun ',
);
<?php
$UTF8_TO_ASCII[0x7d] = array(
'Shou ','Yi ','Zhi ','Gu ','Chu ','Jiang ','Feng ','Bei ','Cay ','Bian ','Sui ','Qun ','Ling ','Fu ','Zuo ','Xia ','Xiong ','[?] ','Nao ','Xia ','Kui ','Xi ','Wai ','Yuan ','Mao ','Su ','Duo ','Duo ','Ye ','Qing ','Uys ','Gou ','Gou ','Qi ','Meng ','Meng ','Yin ','Huo ','Chen ','Da ','Ze ','Tian ','Tai ','Fu ','Guai ','Yao ','Yang ','Hang ','Gao ','Shi ','Ben ','Tai ','Tou ','Yan ','Bi ','Yi ','Kua ','Jia ','Duo ','Kwu ','Kuang ','Yun ','Jia ','Pa ','En ','Lian ','Huan ','Di ','Yan ','Pao ','Quan ','Qi ','Nai ','Feng ','Xie ','Fen ','Dian ','[?] ','Kui ','Zou ','Huan ','Qi ','Kai ','Zha ','Ben ','Yi ','Jiang ','Tao ','Zang ','Ben ','Xi ','Xiang ','Fei ','Diao ','Xun ','Keng ','Dian ','Ao ','She ','Weng ','Pan ','Ao ','Wu ','Ao ','Jiang ','Lian ','Duo ','Yun ','Jiang ','Shi ','Fen ','Huo ','Bi ','Lian ','Duo ','Nu ','Nu ','Ding ','Nai ','Qian ','Jian ','Ta ','Jiu ','Nan ','Cha ','Hao ','Xian ','Fan ','Ji ','Shuo ','Ru ','Fei ','Wang ','Hong ','Zhuang ','Fu ','Ma ','Dan ','Ren ','Fu ','Jing ','Yan ','Xie ','Wen ','Zhong ','Pa ','Du ','Ji ','Keng ','Zhong ','Yao ','Jin ','Yun ','Miao ','Pei ','Shi ','Yue ','Zhuang ','Niu ','Yan ','Na ','Xin ','Fen ','Bi ','Yu ','Tuo ','Feng ','Yuan ','Fang ','Wu ','Yu ','Gui ','Du ','Ba ','Ni ','Zhou ','Zhuo ','Zhao ','Da ','Nai ','Yuan ','Tou ','Xuan ','Zhi ','E ','Mei ','Mo ','Qi ','Bi ','Shen ','Qie ','E ','He ','Xu ','Fa ','Zheng ','Min ','Ban ','Mu ','Fu ','Ling ','Zi ','Zi ','Shi ','Ran ','Shan ','Yang ','Man ','Jie ','Gu ','Si ','Xing ','Wei ','Zi ','Ju ','Shan ','Pin ','Ren ','Yao ','Tong ','Jiang ','Shu ','Ji ','Gai ','Shang ','Kuo ','Juan ','Jiao ','Gou ','Mu ','Jian ','Jian ','Yi ','Nian ','Zhi ','Ji ','Ji ','Xian ','Heng ','Guang ','Jun ','Kua ','Yan ','Ming ','Lie ','Pei ','Yan ','You ','Yan ','Cha ','Shen ','Yin ','Chi ','Gui ','Quan ','Zi ',
);
<?php
$UTF8_TO_ASCII[0x7e] = array(
'Song ','Wei ','Hong ','Wa ','Lou ','Ya ','Rao ','Jiao ','Luan ','Ping ','Xian ','Shao ','Li ','Cheng ','Xiao ','Mang ','Fu ','Suo ','Wu ','Wei ','Ke ','Lai ','Chuo ','Ding ','Niang ','Xing ','Nan ','Yu ','Nuo ','Pei ','Nei ','Juan ','Shen ','Zhi ','Han ','Di ','Zhuang ','E ','Pin ','Tui ','Han ','Mian ','Wu ','Yan ','Wu ','Xi ','Yan ','Yu ','Si ','Yu ','Wa ','[?] ','Xian ','Ju ','Qu ','Shui ','Qi ','Xian ','Zhui ','Dong ','Chang ','Lu ','Ai ','E ','E ','Lou ','Mian ','Cong ','Pou ','Ju ','Po ','Cai ','Ding ','Wan ','Biao ','Xiao ','Shu ','Qi ','Hui ','Fu ','E ','Wo ','Tan ','Fei ','Wei ','Jie ','Tian ','Ni ','Quan ','Jing ','Hun ','Jing ','Qian ','Dian ','Xing ','Hu ','Wa ','Lai ','Bi ','Yin ','Chou ','Chuo ','Fu ','Jing ','Lun ','Yan ','Lan ','Kun ','Yin ','Ya ','Ju ','Li ','Dian ','Xian ','Hwa ','Hua ','Ying ','Chan ','Shen ','Ting ','Dang ','Yao ','Wu ','Nan ','Ruo ','Jia ','Tou ','Xu ','Yu ','Wei ','Ti ','Rou ','Mei ','Dan ','Ruan ','Qin ','Hui ','Wu ','Qian ','Chun ','Mao ','Fu ','Jie ','Duan ','Xi ','Zhong ','Mei ','Huang ','Mian ','An ','Ying ','Xuan ','Jie ','Wei ','Mei ','Yuan ','Zhen ','Qiu ','Ti ','Xie ','Tuo ','Lian ','Mao ','Ran ','Si ','Pian ','Wei ','Wa ','Jiu ','Hu ','Ao ','[?] ','Bou ','Xu ','Tou ','Gui ','Zou ','Yao ','Pi ','Xi ','Yuan ','Ying ','Rong ','Ru ','Chi ','Liu ','Mei ','Pan ','Ao ','Ma ','Gou ','Kui ','Qin ','Jia ','Sao ','Zhen ','Yuan ','Cha ','Yong ','Ming ','Ying ','Ji ','Su ','Niao ','Xian ','Tao ','Pang ','Lang ','Nao ','Bao ','Ai ','Pi ','Pin ','Yi ','Piao ','Yu ','Lei ','Xuan ','Man ','Yi ','Zhang ','Kang ','Yong ','Ni ','Li ','Di ','Gui ','Yan ','Jin ','Zhuan ','Chang ','Ce ','Han ','Nen ','Lao ','Mo ','Zhe ','Hu ','Hu ','Ao ','Nen ','Qiang ','Ma ','Pie ','Gu ','Wu ','Jiao ','Tuo ','Zhan ','Mao ','Xian ','Xian ','Mo ','Liao ','Lian ','Hua ',
);
<?php
$UTF8_TO_ASCII[0x7f] = array(
'Gui ','Deng ','Zhi ','Xu ','Yi ','Hua ','Xi ','Hui ','Rao ','Xi ','Yan ','Chan ','Jiao ','Mei ','Fan ','Fan ','Xian ','Yi ','Wei ','Jiao ','Fu ','Shi ','Bi ','Shan ','Sui ','Qiang ','Lian ','Huan ','Xin ','Niao ','Dong ','Yi ','Can ','Ai ','Niang ','Neng ','Ma ','Tiao ','Chou ','Jin ','Ci ','Yu ','Pin ','Yong ','Xu ','Nai ','Yan ','Tai ','Ying ','Can ','Niao ','Wo ','Ying ','Mian ','Kaka ','Ma ','Shen ','Xing ','Ni ','Du ','Liu ','Yuan ','Lan ','Yan ','Shuang ','Ling ','Jiao ','Niang ','Lan ','Xian ','Ying ','Shuang ','Shuai ','Quan ','Mi ','Li ','Luan ','Yan ','Zhu ','Lan ','Zi ','Jie ','Jue ','Jue ','Kong ','Yun ','Zi ','Zi ','Cun ','Sun ','Fu ','Bei ','Zi ','Xiao ','Xin ','Meng ','Si ','Tai ','Bao ','Ji ','Gu ','Nu ','Xue ','[?] ','Zhuan ','Hai ','Luan ','Sun ','Huai ','Mie ','Cong ','Qian ','Shu ','Chan ','Ya ','Zi ','Ni ','Fu ','Zi ','Li ','Xue ','Bo ','Ru ','Lai ','Nie ','Nie ','Ying ','Luan ','Mian ','Zhu ','Rong ','Ta ','Gui ','Zhai ','Qiong ','Yu ','Shou ','An ','Tu ','Song ','Wan ','Rou ','Yao ','Hong ','Yi ','Jing ','Zhun ','Mi ','Zhu ','Dang ','Hong ','Zong ','Guan ','Zhou ','Ding ','Wan ','Yi ','Bao ','Shi ','Shi ','Chong ','Shen ','Ke ','Xuan ','Shi ','You ','Huan ','Yi ','Tiao ','Shi ','Xian ','Gong ','Cheng ','Qun ','Gong ','Xiao ','Zai ','Zha ','Bao ','Hai ','Yan ','Xiao ','Jia ','Shen ','Chen ','Rong ','Huang ','Mi ','Kou ','Kuan ','Bin ','Su ','Cai ','Zan ','Ji ','Yuan ','Ji ','Yin ','Mi ','Kou ','Qing ','Que ','Zhen ','Jian ','Fu ','Ning ','Bing ','Huan ','Mei ','Qin ','Han ','Yu ','Shi ','Ning ','Qin ','Ning ','Zhi ','Yu ','Bao ','Kuan ','Ning ','Qin ','Mo ','Cha ','Ju ','Gua ','Qin ','Hu ','Wu ','Liao ','Shi ','Zhu ','Zhai ','Shen ','Wei ','Xie ','Kuan ','Hui ','Liao ','Jun ','Huan ','Yi ','Yi ','Bao ','Qin ','Chong ','Bao ','Feng ','Cun ','Dui ','Si ','Xun ','Dao ','Lu ','Dui ','Shou ',
);
<?php
$UTF8_TO_ASCII[0x80] = array(
'Po ','Feng ','Zhuan ','Fu ','She ','Ke ','Jiang ','Jiang ','Zhuan ','Wei ','Zun ','Xun ','Shu ','Dui ','Dao ','Xiao ','Ji ','Shao ','Er ','Er ','Er ','Ga ','Jian ','Shu ','Chen ','Shang ','Shang ','Mo ','Ga ','Chang ','Liao ','Xian ','Xian ','[?] ','Wang ','Wang ','You ','Liao ','Liao ','Yao ','Mang ','Wang ','Wang ','Wang ','Ga ','Yao ','Duo ','Kui ','Zhong ','Jiu ','Gan ','Gu ','Gan ','Tui ','Gan ','Gan ','Shi ','Yin ','Chi ','Kao ','Ni ','Jin ','Wei ','Niao ','Ju ','Pi ','Ceng ','Xi ','Bi ','Ju ','Jie ','Tian ','Qu ','Ti ','Jie ','Wu ','Diao ','Shi ','Shi ','Ping ','Ji ','Xie ','Chen ','Xi ','Ni ','Zhan ','Xi ','[?] ','Man ','E ','Lou ','Ping ','Ti ','Fei ','Shu ','Xie ','Tu ','Lu ','Lu ','Xi ','Ceng ','Lu ','Ju ','Xie ','Ju ','Jue ','Liao ','Jue ','Shu ','Xi ','Che ','Tun ','Ni ','Shan ','[?] ','Xian ','Li ','Xue ','Nata ','[?] ','Long ','Yi ','Qi ','Ren ','Wu ','Han ','Shen ','Yu ','Chu ','Sui ','Qi ','[?] ','Yue ','Ban ','Yao ','Ang ','Ya ','Wu ','Jie ','E ','Ji ','Qian ','Fen ','Yuan ','Qi ','Cen ','Qian ','Qi ','Cha ','Jie ','Qu ','Gang ','Xian ','Ao ','Lan ','Dao ','Ba ','Zuo ','Zuo ','Yang ','Ju ','Gang ','Ke ','Gou ','Xue ','Bei ','Li ','Tiao ','Ju ','Yan ','Fu ','Xiu ','Jia ','Ling ','Tuo ','Pei ','You ','Dai ','Kuang ','Yue ','Qu ','Hu ','Po ','Min ','An ','Tiao ','Ling ','Chi ','Yuri ','Dong ','Cem ','Kui ','Xiu ','Mao ','Tong ','Xue ','Yi ','Kura ','He ','Ke ','Luo ','E ','Fu ','Xun ','Die ','Lu ','An ','Er ','Gai ','Quan ','Tong ','Yi ','Mu ','Shi ','An ','Wei ','Hu ','Zhi ','Mi ','Li ','Ji ','Tong ','Wei ','You ','Sang ','Xia ','Li ','Yao ','Jiao ','Zheng ','Luan ','Jiao ','E ','E ','Yu ','Ye ','Bu ','Qiao ','Qun ','Feng ','Feng ','Nao ','Li ','You ','Xian ','Hong ','Dao ','Shen ','Cheng ','Tu ','Geng ','Jun ','Hao ','Xia ','Yin ','Yu ',
);
<?php
$UTF8_TO_ASCII[0x81] = array(
'Lang ','Kan ','Lao ','Lai ','Xian ','Que ','Kong ','Chong ','Chong ','Ta ','Lin ','Hua ','Ju ','Lai ','Qi ','Min ','Kun ','Kun ','Zu ','Gu ','Cui ','Ya ','Ya ','Gang ','Lun ','Lun ','Leng ','Jue ','Duo ','Zheng ','Guo ','Yin ','Dong ','Han ','Zheng ','Wei ','Yao ','Pi ','Yan ','Song ','Jie ','Beng ','Zu ','Jue ','Dong ','Zhan ','Gu ','Yin ','[?] ','Ze ','Huang ','Yu ','Wei ','Yang ','Feng ','Qiu ','Dun ','Ti ','Yi ','Zhi ','Shi ','Zai ','Yao ','E ','Zhu ','Kan ','Lu ','Yan ','Mei ','Gan ','Ji ','Ji ','Huan ','Ting ','Sheng ','Mei ','Qian ','Wu ','Yu ','Zong ','Lan ','Jue ','Yan ','Yan ','Wei ','Zong ','Cha ','Sui ','Rong ','Yamashina ','Qin ','Yu ','Kewashii ','Lou ','Tu ','Dui ','Xi ','Weng ','Cang ','Dang ','Hong ','Jie ','Ai ','Liu ','Wu ','Song ','Qiao ','Zi ','Wei ','Beng ','Dian ','Cuo ','Qian ','Yong ','Nie ','Cuo ','Ji ','[?] ','Tao ','Song ','Zong ','Jiang ','Liao ','Kang ','Chan ','Die ','Cen ','Ding ','Tu ','Lou ','Zhang ','Zhan ','Zhan ','Ao ','Cao ','Qu ','Qiang ','Zui ','Zui ','Dao ','Dao ','Xi ','Yu ','Bo ','Long ','Xiang ','Ceng ','Bo ','Qin ','Jiao ','Yan ','Lao ','Zhan ','Lin ','Liao ','Liao ','Jin ','Deng ','Duo ','Zun ','Jiao ','Gui ','Yao ','Qiao ','Yao ','Jue ','Zhan ','Yi ','Xue ','Nao ','Ye ','Ye ','Yi ','E ','Xian ','Ji ','Xie ','Ke ','Xi ','Di ','Ao ','Zui ','[?] ','Ni ','Rong ','Dao ','Ling ','Za ','Yu ','Yue ','Yin ','[?] ','Jie ','Li ','Sui ','Long ','Long ','Dian ','Ying ','Xi ','Ju ','Chan ','Ying ','Kui ','Yan ','Wei ','Nao ','Quan ','Chao ','Cuan ','Luan ','Dian ','Dian ','[?] ','Yan ','Yan ','Yan ','Nao ','Yan ','Chuan ','Gui ','Chuan ','Zhou ','Huang ','Jing ','Xun ','Chao ','Chao ','Lie ','Gong ','Zuo ','Qiao ','Ju ','Gong ','Kek ','Wu ','Pwu ','Pwu ','Chai ','Qiu ','Qiu ','Ji ','Yi ','Si ','Ba ','Zhi ','Zhao ','Xiang ','Yi ','Jin ','Xun ','Juan ','Phas ','Xun ','Jin ','Fu ',
);
<?php
$UTF8_TO_ASCII[0x82] = array(
'Za ','Bi ','Shi ','Bu ','Ding ','Shuai ','Fan ','Nie ','Shi ','Fen ','Pa ','Zhi ','Xi ','Hu ','Dan ','Wei ','Zhang ','Tang ','Dai ','Ma ','Pei ','Pa ','Tie ','Fu ','Lian ','Zhi ','Zhou ','Bo ','Zhi ','Di ','Mo ','Yi ','Yi ','Ping ','Qia ','Juan ','Ru ','Shuai ','Dai ','Zheng ','Shui ','Qiao ','Zhen ','Shi ','Qun ','Xi ','Bang ','Dai ','Gui ','Chou ','Ping ','Zhang ','Sha ','Wan ','Dai ','Wei ','Chang ','Sha ','Qi ','Ze ','Guo ','Mao ','Du ','Hou ','Zheng ','Xu ','Mi ','Wei ','Wo ','Fu ','Yi ','Bang ','Ping ','Tazuna ','Gong ','Pan ','Huang ','Dao ','Mi ','Jia ','Teng ','Hui ','Zhong ','Shan ','Man ','Mu ','Biao ','Guo ','Ze ','Mu ','Bang ','Zhang ','Jiong ','Chan ','Fu ','Zhi ','Hu ','Fan ','Chuang ','Bi ','Hei ','[?] ','Mi ','Qiao ','Chan ','Fen ','Meng ','Bang ','Chou ','Mie ','Chu ','Jie ','Xian ','Lan ','Gan ','Ping ','Nian ','Qian ','Bing ','Bing ','Xing ','Gan ','Yao ','Huan ','You ','You ','Ji ','Yan ','Pi ','Ting ','Ze ','Guang ','Zhuang ','Mo ','Qing ','Bi ','Qin ','Dun ','Chuang ','Gui ','Ya ','Bai ','Jie ','Xu ','Lu ','Wu ','[?] ','Ku ','Ying ','Di ','Pao ','Dian ','Ya ','Miao ','Geng ','Ci ','Fu ','Tong ','Pang ','Fei ','Xiang ','Yi ','Zhi ','Tiao ','Zhi ','Xiu ','Du ','Zuo ','Xiao ','Tu ','Gui ','Ku ','Pang ','Ting ','You ','Bu ','Ding ','Cheng ','Lai ','Bei ','Ji ','An ','Shu ','Kang ','Yong ','Tuo ','Song ','Shu ','Qing ','Yu ','Yu ','Miao ','Sou ','Ce ','Xiang ','Fei ','Jiu ','He ','Hui ','Liu ','Sha ','Lian ','Lang ','Sou ','Jian ','Pou ','Qing ','Jiu ','Jiu ','Qin ','Ao ','Kuo ','Lou ','Yin ','Liao ','Dai ','Lu ','Yi ','Chu ','Chan ','Tu ','Si ','Xin ','Miao ','Chang ','Wu ','Fei ','Guang ','Koc ','Kuai ','Bi ','Qiang ','Xie ','Lin ','Lin ','Liao ','Lu ','[?] ','Ying ','Xian ','Ting ','Yong ','Li ','Ting ','Yin ','Xun ','Yan ','Ting ','Di ','Po ','Jian ','Hui ','Nai ','Hui ','Gong ','Nian ',
);
<?php
$UTF8_TO_ASCII[0x83] = array(
'Kai ','Bian ','Yi ','Qi ','Nong ','Fen ','Ju ','Yan ','Yi ','Zang ','Bi ','Yi ','Yi ','Er ','San ','Shi ','Er ','Shi ','Shi ','Gong ','Diao ','Yin ','Hu ','Fu ','Hong ','Wu ','Tui ','Chi ','Jiang ','Ba ','Shen ','Di ','Zhang ','Jue ','Tao ','Fu ','Di ','Mi ','Xian ','Hu ','Chao ','Nu ','Jing ','Zhen ','Yi ','Mi ','Quan ','Wan ','Shao ','Ruo ','Xuan ','Jing ','Dun ','Zhang ','Jiang ','Qiang ','Peng ','Dan ','Qiang ','Bi ','Bi ','She ','Dan ','Jian ','Gou ','Sei ','Fa ','Bi ','Kou ','Nagi ','Bie ','Xiao ','Dan ','Kuo ','Qiang ','Hong ','Mi ','Kuo ','Wan ','Jue ','Ji ','Ji ','Gui ','Dang ','Lu ','Lu ','Tuan ','Hui ','Zhi ','Hui ','Hui ','Yi ','Yi ','Yi ','Yi ','Huo ','Huo ','Shan ','Xing ','Wen ','Tong ','Yan ','Yan ','Yu ','Chi ','Cai ','Biao ','Diao ','Bin ','Peng ','Yong ','Piao ','Zhang ','Ying ','Chi ','Chi ','Zhuo ','Tuo ','Ji ','Pang ','Zhong ','Yi ','Wang ','Che ','Bi ','Chi ','Ling ','Fu ','Wang ','Zheng ','Cu ','Wang ','Jing ','Dai ','Xi ','Xun ','Hen ','Yang ','Huai ','Lu ','Hou ','Wa ','Cheng ','Zhi ','Xu ','Jing ','Tu ','Cong ','[?] ','Lai ','Cong ','De ','Pai ','Xi ','[?] ','Qi ','Chang ','Zhi ','Cong ','Zhou ','Lai ','Yu ','Xie ','Jie ','Jian ','Chi ','Jia ','Bian ','Huang ','Fu ','Xun ','Wei ','Pang ','Yao ','Wei ','Xi ','Zheng ','Piao ','Chi ','De ','Zheng ','Zheng ','Bie ','De ','Chong ','Che ','Jiao ','Wei ','Jiao ','Hui ','Mei ','Long ','Xiang ','Bao ','Qu ','Xin ','Shu ','Bi ','Yi ','Le ','Ren ','Dao ','Ding ','Gai ','Ji ','Ren ','Ren ','Chan ','Tan ','Te ','Te ','Gan ','Qi ','Shi ','Cun ','Zhi ','Wang ','Mang ','Xi ','Fan ','Ying ','Tian ','Min ','Min ','Zhong ','Chong ','Wu ','Ji ','Wu ','Xi ','Ye ','You ','Wan ','Cong ','Zhong ','Kuai ','Yu ','Bian ','Zhi ','Qi ','Cui ','Chen ','Tai ','Tun ','Qian ','Nian ','Hun ','Xiong ','Niu ','Wang ','Xian ','Xin ','Kang ','Hu ','Kai ','Fen ',
);
<?php
$UTF8_TO_ASCII[0x84] = array(
'Huai ','Tai ','Song ','Wu ','Ou ','Chang ','Chuang ','Ju ','Yi ','Bao ','Chao ','Min ','Pei ','Zuo ','Zen ','Yang ','Kou ','Ban ','Nu ','Nao ','Zheng ','Pa ','Bu ','Tie ','Gu ','Hu ','Ju ','Da ','Lian ','Si ','Chou ','Di ','Dai ','Yi ','Tu ','You ','Fu ','Ji ','Peng ','Xing ','Yuan ','Ni ','Guai ','Fu ','Xi ','Bi ','You ','Qie ','Xuan ','Cong ','Bing ','Huang ','Xu ','Chu ','Pi ','Xi ','Xi ','Tan ','Koraeru ','Zong ','Dui ','[?] ','Ki ','Yi ','Chi ','Ren ','Xun ','Shi ','Xi ','Lao ','Heng ','Kuang ','Mu ','Zhi ','Xie ','Lian ','Tiao ','Huang ','Die ','Hao ','Kong ','Gui ','Heng ','Xi ','Xiao ','Shu ','S ','Kua ','Qiu ','Yang ','Hui ','Hui ','Chi ','Jia ','Yi ','Xiong ','Guai ','Lin ','Hui ','Zi ','Xu ','Chi ','Xiang ','Nu ','Hen ','En ','Ke ','Tong ','Tian ','Gong ','Quan ','Xi ','Qia ','Yue ','Peng ','Ken ','De ','Hui ','E ','Kyuu ','Tong ','Yan ','Kai ','Ce ','Nao ','Yun ','Mang ','Yong ','Yong ','Yuan ','Pi ','Kun ','Qiao ','Yue ','Yu ','Yu ','Jie ','Xi ','Zhe ','Lin ','Ti ','Han ','Hao ','Qie ','Ti ','Bu ','Yi ','Qian ','Hui ','Xi ','Bei ','Man ','Yi ','Heng ','Song ','Quan ','Cheng ','Hui ','Wu ','Wu ','You ','Li ','Liang ','Huan ','Cong ','Yi ','Yue ','Li ','Nin ','Nao ','E ','Que ','Xuan ','Qian ','Wu ','Min ','Cong ','Fei ','Bei ','Duo ','Cui ','Chang ','Men ','Li ','Ji ','Guan ','Guan ','Xing ','Dao ','Qi ','Kong ','Tian ','Lun ','Xi ','Kan ','Kun ','Ni ','Qing ','Chou ','Dun ','Guo ','Chan ','Liang ','Wan ','Yuan ','Jin ','Ji ','Lin ','Yu ','Huo ','He ','Quan ','Tan ','Ti ','Ti ','Nie ','Wang ','Chuo ','Bu ','Hun ','Xi ','Tang ','Xin ','Wei ','Hui ','E ','Rui ','Zong ','Jian ','Yong ','Dian ','Ju ','Can ','Cheng ','De ','Bei ','Qie ','Can ','Dan ','Guan ','Duo ','Nao ','Yun ','Xiang ','Zhui ','Die ','Huang ','Chun ','Qiong ','Re ','Xing ','Ce ','Bian ','Hun ','Zong ','Ti ',
);
<?php
$UTF8_TO_ASCII[0x85] = array(
'Qiao ','Chou ','Bei ','Xuan ','Wei ','Ge ','Qian ','Wei ','Yu ','Yu ','Bi ','Xuan ','Huan ','Min ','Bi ','Yi ','Mian ','Yong ','Kai ','Dang ','Yin ','E ','Chen ','Mou ','Ke ','Ke ','Yu ','Ai ','Qie ','Yan ','Nuo ','Gan ','Yun ','Zong ','Sai ','Leng ','Fen ','[?] ','Kui ','Kui ','Que ','Gong ','Yun ','Su ','Su ','Qi ','Yao ','Song ','Huang ','Ji ','Gu ','Ju ','Chuang ','Ni ','Xie ','Kai ','Zheng ','Yong ','Cao ','Sun ','Shen ','Bo ','Kai ','Yuan ','Xie ','Hun ','Yong ','Yang ','Li ','Sao ','Tao ','Yin ','Ci ','Xu ','Qian ','Tai ','Huang ','Yun ','Shen ','Ming ','[?] ','She ','Cong ','Piao ','Mo ','Mu ','Guo ','Chi ','Can ','Can ','Can ','Cui ','Min ','Te ','Zhang ','Tong ','Ao ','Shuang ','Man ','Guan ','Que ','Zao ','Jiu ','Hui ','Kai ','Lian ','Ou ','Song ','Jin ','Yin ','Lu ','Shang ','Wei ','Tuan ','Man ','Qian ','She ','Yong ','Qing ','Kang ','Di ','Zhi ','Lou ','Juan ','Qi ','Qi ','Yu ','Ping ','Liao ','Cong ','You ','Chong ','Zhi ','Tong ','Cheng ','Qi ','Qu ','Peng ','Bei ','Bie ','Chun ','Jiao ','Zeng ','Chi ','Lian ','Ping ','Kui ','Hui ','Qiao ','Cheng ','Yin ','Yin ','Xi ','Xi ','Dan ','Tan ','Duo ','Dui ','Dui ','Su ','Jue ','Ce ','Xiao ','Fan ','Fen ','Lao ','Lao ','Chong ','Han ','Qi ','Xian ','Min ','Jing ','Liao ','Wu ','Can ','Jue ','Cu ','Xian ','Tan ','Sheng ','Pi ','Yi ','Chu ','Xian ','Nao ','Dan ','Tan ','Jing ','Song ','Han ','Jiao ','Wai ','Huan ','Dong ','Qin ','Qin ','Qu ','Cao ','Ken ','Xie ','Ying ','Ao ','Mao ','Yi ','Lin ','Se ','Jun ','Huai ','Men ','Lan ','Ai ','Lin ','Yan ','Gua ','Xia ','Chi ','Yu ','Yin ','Dai ','Meng ','Ai ','Meng ','Dui ','Qi ','Mo ','Lan ','Men ','Chou ','Zhi ','Nuo ','Nuo ','Yan ','Yang ','Bo ','Zhi ','Kuang ','Kuang ','You ','Fu ','Liu ','Mie ','Cheng ','[?] ','Chan ','Meng ','Lan ','Huai ','Xuan ','Rang ','Chan ','Ji ','Ju ','Huan ','She ','Yi ',
);
<?php
$UTF8_TO_ASCII[0x86] = array(
'Lian ','Nan ','Mi ','Tang ','Jue ','Gang ','Gang ','Gang ','Ge ','Yue ','Wu ','Jian ','Xu ','Shu ','Rong ','Xi ','Cheng ','Wo ','Jie ','Ge ','Jian ','Qiang ','Huo ','Qiang ','Zhan ','Dong ','Qi ','Jia ','Die ','Zei ','Jia ','Ji ','Shi ','Kan ','Ji ','Kui ','Gai ','Deng ','Zhan ','Chuang ','Ge ','Jian ','Jie ','Yu ','Jian ','Yan ','Lu ','Xi ','Zhan ','Xi ','Xi ','Chuo ','Dai ','Qu ','Hu ','Hu ','Hu ','E ','Shi ','Li ','Mao ','Hu ','Li ','Fang ','Suo ','Bian ','Dian ','Jiong ','Shang ','Yi ','Yi ','Shan ','Hu ','Fei ','Yan ','Shou ','T ','Cai ','Zha ','Qiu ','Le ','Bu ','Ba ','Da ','Reng ','Fu ','Hameru ','Zai ','Tuo ','Zhang ','Diao ','Kang ','Yu ','Ku ','Han ','Shen ','Cha ','Yi ','Gu ','Kou ','Wu ','Tuo ','Qian ','Zhi ','Ren ','Kuo ','Men ','Sao ','Yang ','Niu ','Ban ','Che ','Rao ','Xi ','Qian ','Ban ','Jia ','Yu ','Fu ','Ao ','Xi ','Pi ','Zhi ','Zi ','E ','Dun ','Zhao ','Cheng ','Ji ','Yan ','Kuang ','Bian ','Chao ','Ju ','Wen ','Hu ','Yue ','Jue ','Ba ','Qin ','Zhen ','Zheng ','Yun ','Wan ','Nu ','Yi ','Shu ','Zhua ','Pou ','Tou ','Dou ','Kang ','Zhe ','Pou ','Fu ','Pao ','Ba ','Ao ','Ze ','Tuan ','Kou ','Lun ','Qiang ','[?] ','Hu ','Bao ','Bing ','Zhi ','Peng ','Tan ','Pu ','Pi ','Tai ','Yao ','Zhen ','Zha ','Yang ','Bao ','He ','Ni ','Yi ','Di ','Chi ','Pi ','Za ','Mo ','Mo ','Shen ','Ya ','Chou ','Qu ','Min ','Chu ','Jia ','Fu ','Zhan ','Zhu ','Dan ','Chai ','Mu ','Nian ','La ','Fu ','Pao ','Ban ','Pai ','Ling ','Na ','Guai ','Qian ','Ju ','Tuo ','Ba ','Tuo ','Tuo ','Ao ','Ju ','Zhuo ','Pan ','Zhao ','Bai ','Bai ','Di ','Ni ','Ju ','Kuo ','Long ','Jian ','[?] ','Yong ','Lan ','Ning ','Bo ','Ze ','Qian ','Hen ','Gua ','Shi ','Jie ','Zheng ','Nin ','Gong ','Gong ','Quan ','Shuan ','Cun ','Zan ','Kao ','Chi ','Xie ','Ce ','Hui ','Pin ','Zhuai ','Shi ','Na ',
);
<?php
$UTF8_TO_ASCII[0x87] = array(
'Bo ','Chi ','Gua ','Zhi ','Kuo ','Duo ','Duo ','Zhi ','Qie ','An ','Nong ','Zhen ','Ge ','Jiao ','Ku ','Dong ','Ru ','Tiao ','Lie ','Zha ','Lu ','Die ','Wa ','Jue ','Mushiru ','Ju ','Zhi ','Luan ','Ya ','Zhua ','Ta ','Xie ','Nao ','Dang ','Jiao ','Zheng ','Ji ','Hui ','Xun ','Ku ','Ai ','Tuo ','Nuo ','Cuo ','Bo ','Geng ','Ti ','Zhen ','Cheng ','Suo ','Suo ','Keng ','Mei ','Long ','Ju ','Peng ','Jian ','Yi ','Ting ','Shan ','Nuo ','Wan ','Xie ','Cha ','Feng ','Jiao ','Wu ','Jun ','Jiu ','Tong ','Kun ','Huo ','Tu ','Zhuo ','Pou ','Le ','Ba ','Han ','Shao ','Nie ','Juan ','Ze ','Song ','Ye ','Jue ','Bu ','Huan ','Bu ','Zun ','Yi ','Zhai ','Lu ','Sou ','Tuo ','Lao ','Sun ','Bang ','Jian ','Huan ','Dao ','[?] ','Wan ','Qin ','Peng ','She ','Lie ','Min ','Men ','Fu ','Bai ','Ju ','Dao ','Wo ','Ai ','Juan ','Yue ','Zong ','Chen ','Chui ','Jie ','Tu ','Ben ','Na ','Nian ','Nuo ','Zu ','Wo ','Xi ','Xian ','Cheng ','Dian ','Sao ','Lun ','Qing ','Gang ','Duo ','Shou ','Diao ','Pou ','Di ','Zhang ','Gun ','Ji ','Tao ','Qia ','Qi ','Pai ','Shu ','Qian ','Ling ','Yi ','Ya ','Jue ','Zheng ','Liang ','Gua ','Yi ','Huo ','Shan ','Zheng ','Lue ','Cai ','Tan ','Che ','Bing ','Jie ','Ti ','Kong ','Tui ','Yan ','Cuo ','Zou ','Ju ','Tian ','Qian ','Ken ','Bai ','Shou ','Jie ','Lu ','Guo ','Haba ','[?] ','Zhi ','Dan ','Mang ','Xian ','Sao ','Guan ','Peng ','Yuan ','Nuo ','Jian ','Zhen ','Jiu ','Jian ','Yu ','Yan ','Kui ','Nan ','Hong ','Rou ','Pi ','Wei ','Sai ','Zou ','Xuan ','Miao ','Ti ','Nie ','Cha ','Shi ','Zong ','Zhen ','Yi ','Shun ','Heng ','Bian ','Yang ','Huan ','Yan ','Zuan ','An ','Xu ','Ya ','Wo ','Ke ','Chuai ','Ji ','Ti ','La ','La ','Cheng ','Kai ','Jiu ','Jiu ','Tu ','Jie ','Hui ','Geng ','Chong ','Shuo ','She ','Xie ','Yuan ','Qian ','Ye ','Cha ','Zha ','Bei ','Yao ','[?] ','[?] ','Lan ','Wen ','Qin ',
);
<?php
$UTF8_TO_ASCII[0x88] = array(
'Chan ','Ge ','Lou ','Zong ','Geng ','Jiao ','Gou ','Qin ','Yong ','Que ','Chou ','Chi ','Zhan ','Sun ','Sun ','Bo ','Chu ','Rong ','Beng ','Cuo ','Sao ','Ke ','Yao ','Dao ','Zhi ','Nu ','Xie ','Jian ','Sou ','Qiu ','Gao ','Xian ','Shuo ','Sang ','Jin ','Mie ','E ','Chui ','Nuo ','Shan ','Ta ','Jie ','Tang ','Pan ','Ban ','Da ','Li ','Tao ','Hu ','Zhi ','Wa ','Xia ','Qian ','Wen ','Qiang ','Tian ','Zhen ','E ','Xi ','Nuo ','Quan ','Cha ','Zha ','Ge ','Wu ','En ','She ','Kang ','She ','Shu ','Bai ','Yao ','Bin ','Sou ','Tan ','Sa ','Chan ','Suo ','Liao ','Chong ','Chuang ','Guo ','Bing ','Feng ','Shuai ','Di ','Qi ','Sou ','Zhai ','Lian ','Tang ','Chi ','Guan ','Lu ','Luo ','Lou ','Zong ','Gai ','Hu ','Zha ','Chuang ','Tang ','Hua ','Cui ','Nai ','Mo ','Jiang ','Gui ','Ying ','Zhi ','Ao ','Zhi ','Nie ','Man ','Shan ','Kou ','Shu ','Suo ','Tuan ','Jiao ','Mo ','Mo ','Zhe ','Xian ','Keng ','Piao ','Jiang ','Yin ','Gou ','Qian ','Lue ','Ji ','Ying ','Jue ','Pie ','Pie ','Lao ','Dun ','Xian ','Ruan ','Kui ','Zan ','Yi ','Xun ','Cheng ','Cheng ','Sa ','Nao ','Heng ','Si ','Qian ','Huang ','Da ','Zun ','Nian ','Lin ','Zheng ','Hui ','Zhuang ','Jiao ','Ji ','Cao ','Dan ','Dan ','Che ','Bo ','Che ','Jue ','Xiao ','Liao ','Ben ','Fu ','Qiao ','Bo ','Cuo ','Zhuo ','Zhuan ','Tuo ','Pu ','Qin ','Dun ','Nian ','[?] ','Xie ','Lu ','Jiao ','Cuan ','Ta ','Han ','Qiao ','Zhua ','Jian ','Gan ','Yong ','Lei ','Kuo ','Lu ','Shan ','Zhuo ','Ze ','Pu ','Chuo ','Ji ','Dang ','Suo ','Cao ','Qing ','Jing ','Huan ','Jie ','Qin ','Kuai ','Dan ','Xi ','Ge ','Pi ','Bo ','Ao ','Ju ','Ye ','[?] ','Mang ','Sou ','Mi ','Ji ','Tai ','Zhuo ','Dao ','Xing ','Lan ','Ca ','Ju ','Ye ','Ru ','Ye ','Ye ','Ni ','Hu ','Ji ','Bin ','Ning ','Ge ','Zhi ','Jie ','Kuo ','Mo ','Jian ','Xie ','Lie ','Tan ','Bai ','Sou ','Lu ','Lue ','Rao ','Zhi ',
);
<?php
$UTF8_TO_ASCII[0x89] = array(
'Pan ','Yang ','Lei ','Sa ','Shu ','Zan ','Nian ','Xian ','Jun ','Huo ','Li ','La ','Han ','Ying ','Lu ','Long ','Qian ','Qian ','Zan ','Qian ','Lan ','San ','Ying ','Mei ','Rang ','Chan ','[?] ','Cuan ','Xi ','She ','Luo ','Jun ','Mi ','Li ','Zan ','Luan ','Tan ','Zuan ','Li ','Dian ','Wa ','Dang ','Jiao ','Jue ','Lan ','Li ','Nang ','Zhi ','Gui ','Gui ','Qi ','Xin ','Pu ','Sui ','Shou ','Kao ','You ','Gai ','Yi ','Gong ','Gan ','Ban ','Fang ','Zheng ','Bo ','Dian ','Kou ','Min ','Wu ','Gu ','He ','Ce ','Xiao ','Mi ','Chu ','Ge ','Di ','Xu ','Jiao ','Min ','Chen ','Jiu ','Zhen ','Duo ','Yu ','Chi ','Ao ','Bai ','Xu ','Jiao ','Duo ','Lian ','Nie ','Bi ','Chang ','Dian ','Duo ','Yi ','Gan ','San ','Ke ','Yan ','Dun ','Qi ','Dou ','Xiao ','Duo ','Jiao ','Jing ','Yang ','Xia ','Min ','Shu ','Ai ','Qiao ','Ai ','Zheng ','Di ','Zhen ','Fu ','Shu ','Liao ','Qu ','Xiong ','Xi ','Jiao ','Sen ','Jiao ','Zhuo ','Yi ','Lian ','Bi ','Li ','Xiao ','Xiao ','Wen ','Xue ','Qi ','Qi ','Zhai ','Bin ','Jue ','Zhai ','[?] ','Fei ','Ban ','Ban ','Lan ','Yu ','Lan ','Wei ','Dou ','Sheng ','Liao ','Jia ','Hu ','Xie ','Jia ','Yu ','Zhen ','Jiao ','Wo ','Tou ','Chu ','Jin ','Chi ','Yin ','Fu ','Qiang ','Zhan ','Qu ','Zhuo ','Zhan ','Duan ','Zhuo ','Si ','Xin ','Zhuo ','Zhuo ','Qin ','Lin ','Zhuo ','Chu ','Duan ','Zhu ','Fang ','Xie ','Hang ','Yu ','Shi ','Pei ','You ','Mye ','Pang ','Qi ','Zhan ','Mao ','Lu ','Pei ','Pi ','Liu ','Fu ','Fang ','Xuan ','Jing ','Jing ','Ni ','Zu ','Zhao ','Yi ','Liu ','Shao ','Jian ','Es ','Yi ','Qi ','Zhi ','Fan ','Piao ','Fan ','Zhan ','Guai ','Sui ','Yu ','Wu ','Ji ','Ji ','Ji ','Huo ','Ri ','Dan ','Jiu ','Zhi ','Zao ','Xie ','Tiao ','Xun ','Xu ','Xu ','Xu ','Gan ','Han ','Tai ','Di ','Xu ','Chan ','Shi ','Kuang ','Yang ','Shi ','Wang ','Min ','Min ','Tun ','Chun ','Wu ',
);
<?php
$UTF8_TO_ASCII[0x8a] = array(
'Yun ','Bei ','Ang ','Ze ','Ban ','Jie ','Kun ','Sheng ','Hu ','Fang ','Hao ','Gui ','Chang ','Xuan ','Ming ','Hun ','Fen ','Qin ','Hu ','Yi ','Xi ','Xin ','Yan ','Ze ','Fang ','Tan ','Shen ','Ju ','Yang ','Zan ','Bing ','Xing ','Ying ','Xuan ','Pei ','Zhen ','Ling ','Chun ','Hao ','Mei ','Zuo ','Mo ','Bian ','Xu ','Hun ','Zhao ','Zong ','Shi ','Shi ','Yu ','Fei ','Die ','Mao ','Ni ','Chang ','Wen ','Dong ','Ai ','Bing ','Ang ','Zhou ','Long ','Xian ','Kuang ','Tiao ','Chao ','Shi ','Huang ','Huang ','Xuan ','Kui ','Xu ','Jiao ','Jin ','Zhi ','Jin ','Shang ','Tong ','Hong ','Yan ','Gai ','Xiang ','Shai ','Xiao ','Ye ','Yun ','Hui ','Han ','Han ','Jun ','Wan ','Xian ','Kun ','Zhou ','Xi ','Cheng ','Sheng ','Bu ','Zhe ','Zhe ','Wu ','Han ','Hui ','Hao ','Chen ','Wan ','Tian ','Zhuo ','Zui ','Zhou ','Pu ','Jing ','Xi ','Shan ','Yi ','Xi ','Qing ','Qi ','Jing ','Gui ','Zhen ','Yi ','Zhi ','An ','Wan ','Lin ','Liang ','Chang ','Wang ','Xiao ','Zan ','Hi ','Xuan ','Xuan ','Yi ','Xia ','Yun ','Hui ','Fu ','Min ','Kui ','He ','Ying ','Du ','Wei ','Shu ','Qing ','Mao ','Nan ','Jian ','Nuan ','An ','Yang ','Chun ','Yao ','Suo ','Jin ','Ming ','Jiao ','Kai ','Gao ','Weng ','Chang ','Qi ','Hao ','Yan ','Li ','Ai ','Ji ','Gui ','Men ','Zan ','Xie ','Hao ','Mu ','Mo ','Cong ','Ni ','Zhang ','Hui ','Bao ','Han ','Xuan ','Chuan ','Liao ','Xian ','Dan ','Jing ','Pie ','Lin ','Tun ','Xi ','Yi ','Ji ','Huang ','Tai ','Ye ','Ye ','Li ','Tan ','Tong ','Xiao ','Fei ','Qin ','Zhao ','Hao ','Yi ','Xiang ','Xing ','Sen ','Jiao ','Bao ','Jing ','Yian ','Ai ','Ye ','Ru ','Shu ','Meng ','Xun ','Yao ','Pu ','Li ','Chen ','Kuang ','Die ','[?] ','Yan ','Huo ','Lu ','Xi ','Rong ','Long ','Nang ','Luo ','Luan ','Shai ','Tang ','Yan ','Chu ','Yue ','Yue ','Qu ','Yi ','Geng ','Ye ','Hu ','He ','Shu ','Cao ','Cao ','Noboru ','Man ','Ceng ','Ceng ','Ti ',
);
<?php
$UTF8_TO_ASCII[0x8b] = array(
'Zui ','Can ','Xu ','Hui ','Yin ','Qie ','Fen ','Pi ','Yue ','You ','Ruan ','Peng ','Ban ','Fu ','Ling ','Fei ','Qu ','[?] ','Nu ','Tiao ','Shuo ','Zhen ','Lang ','Lang ','Juan ','Ming ','Huang ','Wang ','Tun ','Zhao ','Ji ','Qi ','Ying ','Zong ','Wang ','Tong ','Lang ','[?] ','Meng ','Long ','Mu ','Deng ','Wei ','Mo ','Ben ','Zha ','Zhu ','Zhu ','[?] ','Zhu ','Ren ','Ba ','Po ','Duo ','Duo ','Dao ','Li ','Qiu ','Ji ','Jiu ','Bi ','Xiu ','Ting ','Ci ','Sha ','Eburi ','Za ','Quan ','Qian ','Yu ','Gan ','Wu ','Cha ','Shan ','Xun ','Fan ','Wu ','Zi ','Li ','Xing ','Cai ','Cun ','Ren ','Shao ','Tuo ','Di ','Zhang ','Mang ','Chi ','Yi ','Gu ','Gong ','Du ','Yi ','Qi ','Shu ','Gang ','Tiao ','Moku ','Soma ','Tochi ','Lai ','Sugi ','Mang ','Yang ','Ma ','Miao ','Si ','Yuan ','Hang ','Fei ','Bei ','Jie ','Dong ','Gao ','Yao ','Xian ','Chu ','Qun ','Pa ','Shu ','Hua ','Xin ','Chou ','Zhu ','Chou ','Song ','Ban ','Song ','Ji ','Yue ','Jin ','Gou ','Ji ','Mao ','Pi ','Bi ','Wang ','Ang ','Fang ','Fen ','Yi ','Fu ','Nan ','Xi ','Hu ','Ya ','Dou ','Xun ','Zhen ','Yao ','Lin ','Rui ','E ','Mei ','Zhao ','Guo ','Zhi ','Cong ','Yun ','Waku ','Dou ','Shu ','Zao ','[?] ','Li ','Haze ','Jian ','Cheng ','Matsu ','Qiang ','Feng ','Nan ','Xiao ','Xian ','Ku ','Ping ','Yi ','Xi ','Zhi ','Guai ','Xiao ','Jia ','Jia ','Gou ','Fu ','Mo ','Yi ','Ye ','Ye ','Shi ','Nie ','Bi ','Duo ','Yi ','Ling ','Bing ','Ni ','La ','He ','Pan ','Fan ','Zhong ','Dai ','Ci ','Yang ','Fu ','Bo ','Mou ','Gan ','Qi ','Ran ','Rou ','Mao ','Zhao ','Song ','Zhe ','Xia ','You ','Shen ','Ju ','Tuo ','Zuo ','Nan ','Ning ','Yong ','Di ','Zhi ','Zha ','Cha ','Dan ','Gu ','Pu ','Jiu ','Ao ','Fu ','Jian ','Bo ','Duo ','Ke ','Nai ','Zhu ','Bi ','Liu ','Chai ','Zha ','Si ','Zhu ','Pei ','Shi ','Guai ','Cha ','Yao ','Jue ','Jiu ','Shi ',
);
<?php
$UTF8_TO_ASCII[0x8c] = array(
'Zhi ','Liu ','Mei ','Hoy ','Rong ','Zha ','[?] ','Biao ','Zhan ','Jie ','Long ','Dong ','Lu ','Sayng ','Li ','Lan ','Yong ','Shu ','Xun ','Shuan ','Qi ','Zhen ','Qi ','Li ','Yi ','Xiang ','Zhen ','Li ','Su ','Gua ','Kan ','Bing ','Ren ','Xiao ','Bo ','Ren ','Bing ','Zi ','Chou ','Yi ','Jie ','Xu ','Zhu ','Jian ','Zui ','Er ','Er ','You ','Fa ','Gong ','Kao ','Lao ','Zhan ','Li ','Yin ','Yang ','He ','Gen ','Zhi ','Chi ','Ge ','Zai ','Luan ','Fu ','Jie ','Hang ','Gui ','Tao ','Guang ','Wei ','Kuang ','Ru ','An ','An ','Juan ','Yi ','Zhuo ','Ku ','Zhi ','Qiong ','Tong ','Sang ','Sang ','Huan ','Jie ','Jiu ','Xue ','Duo ','Zhui ','Yu ','Zan ','Kasei ','Ying ','Masu ','[?] ','Zhan ','Ya ','Nao ','Zhen ','Dang ','Qi ','Qiao ','Hua ','Kuai ','Jiang ','Zhuang ','Xun ','Suo ','Sha ','Zhen ','Bei ','Ting ','Gua ','Jing ','Bo ','Ben ','Fu ','Rui ','Tong ','Jue ','Xi ','Lang ','Liu ','Feng ','Qi ','Wen ','Jun ','Gan ','Cu ','Liang ','Qiu ','Ting ','You ','Mei ','Bang ','Long ','Peng ','Zhuang ','Di ','Xuan ','Tu ','Zao ','Ao ','Gu ','Bi ','Di ','Han ','Zi ','Zhi ','Ren ','Bei ','Geng ','Jian ','Huan ','Wan ','Nuo ','Jia ','Tiao ','Ji ','Xiao ','Lu ','Huan ','Shao ','Cen ','Fen ','Song ','Meng ','Wu ','Li ','Li ','Dou ','Cen ','Ying ','Suo ','Ju ','Ti ','Jie ','Kun ','Zhuo ','Shu ','Chan ','Fan ','Wei ','Jing ','Li ','Bing ','Fumoto ','Shikimi ','Tao ','Zhi ','Lai ','Lian ','Jian ','Zhuo ','Ling ','Li ','Qi ','Bing ','Zhun ','Cong ','Qian ','Mian ','Qi ','Qi ','Cai ','Gun ','Chan ','Te ','Fei ','Pai ','Bang ','Pou ','Hun ','Zong ','Cheng ','Zao ','Ji ','Li ','Peng ','Yu ','Yu ','Gu ','Hun ','Dong ','Tang ','Gang ','Wang ','Di ','Xi ','Fan ','Cheng ','Zhan ','Qi ','Yuan ','Yan ','Yu ','Quan ','Yi ','Sen ','Ren ','Chui ','Leng ','Qi ','Zhuo ','Fu ','Ke ','Lai ','Zou ','Zou ','Zhuo ','Guan ','Fen ','Fen ','Chen ','Qiong ','Nie ',
);
<?php
$UTF8_TO_ASCII[0x8d] = array(
'Wan ','Guo ','Lu ','Hao ','Jie ','Yi ','Chou ','Ju ','Ju ','Cheng ','Zuo ','Liang ','Qiang ','Zhi ','Zhui ','Ya ','Ju ','Bei ','Jiao ','Zhuo ','Zi ','Bin ','Peng ','Ding ','Chu ','Chang ','Kunugi ','Momiji ','Jian ','Gui ','Xi ','Du ','Qian ','Kunugi ','Soko ','Shide ','Luo ','Zhi ','Ken ','Myeng ','Tafu ','[?] ','Peng ','Zhan ','[?] ','Tuo ','Sen ','Duo ','Ye ','Fou ','Wei ','Wei ','Duan ','Jia ','Zong ','Jian ','Yi ','Shen ','Xi ','Yan ','Yan ','Chuan ','Zhan ','Chun ','Yu ','He ','Zha ','Wo ','Pian ','Bi ','Yao ','Huo ','Xu ','Ruo ','Yang ','La ','Yan ','Ben ','Hun ','Kui ','Jie ','Kui ','Si ','Feng ','Xie ','Tuo ','Zhi ','Jian ','Mu ','Mao ','Chu ','Hu ','Hu ','Lian ','Leng ','Ting ','Nan ','Yu ','You ','Mei ','Song ','Xuan ','Xuan ','Ying ','Zhen ','Pian ','Ye ','Ji ','Jie ','Ye ','Chu ','Shun ','Yu ','Cou ','Wei ','Mei ','Di ','Ji ','Jie ','Kai ','Qiu ','Ying ','Rou ','Heng ','Lou ','Le ','Hazou ','Katsura ','Pin ','Muro ','Gai ','Tan ','Lan ','Yun ','Yu ','Chen ','Lu ','Ju ','Sakaki ','[?] ','Pi ','Xie ','Jia ','Yi ','Zhan ','Fu ','Nai ','Mi ','Lang ','Rong ','Gu ','Jian ','Ju ','Ta ','Yao ','Zhen ','Bang ','Sha ','Yuan ','Zi ','Ming ','Su ','Jia ','Yao ','Jie ','Huang ','Gan ','Fei ','Zha ','Qian ','Ma ','Sun ','Yuan ','Xie ','Rong ','Shi ','Zhi ','Cui ','Yun ','Ting ','Liu ','Rong ','Tang ','Que ','Zhai ','Si ','Sheng ','Ta ','Ke ','Xi ','Gu ','Qi ','Kao ','Gao ','Sun ','Pan ','Tao ','Ge ','Xun ','Dian ','Nou ','Ji ','Shuo ','Gou ','Chui ','Qiang ','Cha ','Qian ','Huai ','Mei ','Xu ','Gang ','Gao ','Zhuo ','Tuo ','Hashi ','Yang ','Dian ','Jia ','Jian ','Zui ','Kashi ','Ori ','Bin ','Zhu ','[?] ','Xi ','Qi ','Lian ','Hui ','Yong ','Qian ','Guo ','Gai ','Gai ','Tuan ','Hua ','Cu ','Sen ','Cui ','Beng ','You ','Hu ','Jiang ','Hu ','Huan ','Kui ','Yi ','Nie ','Gao ','Kang ','Gui ','Gui ','Cao ','Man ','Jin ',
);
<?php
$UTF8_TO_ASCII[0x8e] = array(
'Di ','Zhuang ','Le ','Lang ','Chen ','Cong ','Li ','Xiu ','Qing ','Shuang ','Fan ','Tong ','Guan ','Ji ','Suo ','Lei ','Lu ','Liang ','Mi ','Lou ','Chao ','Su ','Ke ','Shu ','Tang ','Biao ','Lu ','Jiu ','Shu ','Zha ','Shu ','Zhang ','Men ','Mo ','Niao ','Yang ','Tiao ','Peng ','Zhu ','Sha ','Xi ','Quan ','Heng ','Jian ','Cong ','[?] ','Hokuso ','Qiang ','Tara ','Ying ','Er ','Xin ','Zhi ','Qiao ','Zui ','Cong ','Pu ','Shu ','Hua ','Kui ','Zhen ','Zun ','Yue ','Zhan ','Xi ','Xun ','Dian ','Fa ','Gan ','Mo ','Wu ','Qiao ','Nao ','Lin ','Liu ','Qiao ','Xian ','Run ','Fan ','Zhan ','Tuo ','Lao ','Yun ','Shun ','Tui ','Cheng ','Tang ','Meng ','Ju ','Cheng ','Su ','Jue ','Jue ','Tan ','Hui ','Ji ','Nuo ','Xiang ','Tuo ','Ning ','Rui ','Zhu ','Chuang ','Zeng ','Fen ','Qiong ','Ran ','Heng ','Cen ','Gu ','Liu ','Lao ','Gao ','Chu ','Zusa ','Nude ','Ca ','San ','Ji ','Dou ','Shou ','Lu ','[?] ','[?] ','Yuan ','Ta ','Shu ','Jiang ','Tan ','Lin ','Nong ','Yin ','Xi ','Sui ','Shan ','Zui ','Xuan ','Cheng ','Gan ','Ju ','Zui ','Yi ','Qin ','Pu ','Yan ','Lei ','Feng ','Hui ','Dang ','Ji ','Sui ','Bo ','Bi ','Ding ','Chu ','Zhua ','Kuai ','Ji ','Jie ','Jia ','Qing ','Zhe ','Jian ','Qiang ','Dao ','Yi ','Biao ','Song ','She ','Lin ','Kunugi ','Cha ','Meng ','Yin ','Tao ','Tai ','Mian ','Qi ','Toan ','Bin ','Huo ','Ji ','Qian ','Mi ','Ning ','Yi ','Gao ','Jian ','Yin ','Er ','Qing ','Yan ','Qi ','Mi ','Zhao ','Gui ','Chun ','Ji ','Kui ','Po ','Deng ','Chu ','[?] ','Mian ','You ','Zhi ','Guang ','Qian ','Lei ','Lei ','Sa ','Lu ','Li ','Cuan ','Lu ','Mie ','Hui ','Ou ','Lu ','Jie ','Gao ','Du ','Yuan ','Li ','Fei ','Zhuo ','Sou ','Lian ','Tamo ','Chu ','[?] ','Zhu ','Lu ','Yan ','Li ','Zhu ','Chen ','Jie ','E ','Su ','Huai ','Nie ','Yu ','Long ','Lai ','[?] ','Xian ','Kwi ','Ju ','Xiao ','Ling ','Ying ','Jian ','Yin ','You ','Ying ',
);
<?php
$UTF8_TO_ASCII[0x8f] = array(
'Xiang ','Nong ','Bo ','Chan ','Lan ','Ju ','Shuang ','She ','Wei ','Cong ','Quan ','Qu ','Cang ','[?] ','Yu ','Luo ','Li ','Zan ','Luan ','Dang ','Jue ','Em ','Lan ','Lan ','Zhu ','Lei ','Li ','Ba ','Nang ','Yu ','Ling ','Tsuki ','Qian ','Ci ','Huan ','Xin ','Yu ','Yu ','Qian ','Ou ','Xu ','Chao ','Chu ','Chi ','Kai ','Yi ','Jue ','Xi ','Xu ','Xia ','Yu ','Kuai ','Lang ','Kuan ','Shuo ','Xi ','Ai ','Yi ','Qi ','Hu ','Chi ','Qin ','Kuan ','Kan ','Kuan ','Kan ','Chuan ','Sha ','Gua ','Yin ','Xin ','Xie ','Yu ','Qian ','Xiao ','Yi ','Ge ','Wu ','Tan ','Jin ','Ou ','Hu ','Ti ','Huan ','Xu ','Pen ','Xi ','Xiao ','Xu ','Xi ','Sen ','Lian ','Chu ','Yi ','Kan ','Yu ','Chuo ','Huan ','Zhi ','Zheng ','Ci ','Bu ','Wu ','Qi ','Bu ','Bu ','Wai ','Ju ','Qian ','Chi ','Se ','Chi ','Se ','Zhong ','Sui ','Sui ','Li ','Cuo ','Yu ','Li ','Gui ','Dai ','Dai ','Si ','Jian ','Zhe ','Mo ','Mo ','Yao ','Mo ','Cu ','Yang ','Tian ','Sheng ','Dai ','Shang ','Xu ','Xun ','Shu ','Can ','Jue ','Piao ','Qia ','Qiu ','Su ','Qing ','Yun ','Lian ','Yi ','Fou ','Zhi ','Ye ','Can ','Hun ','Dan ','Ji ','Ye ','Zhen ','Yun ','Wen ','Chou ','Bin ','Ti ','Jin ','Shang ','Yin ','Diao ','Cu ','Hui ','Cuan ','Yi ','Dan ','Du ','Jiang ','Lian ','Bin ','Du ','Tsukusu ','Jian ','Shu ','Ou ','Duan ','Zhu ','Yin ','Qing ','Yi ','Sha ','Que ','Ke ','Yao ','Jun ','Dian ','Hui ','Hui ','Gu ','Que ','Ji ','Yi ','Ou ','Hui ','Duan ','Yi ','Xiao ','Wu ','Guan ','Mu ','Mei ','Mei ','Ai ','Zuo ','Du ','Yu ','Bi ','Bi ','Bi ','Pi ','Pi ','Bi ','Chan ','Mao ','[?] ','[?] ','Pu ','Mushiru ','Jia ','Zhan ','Sai ','Mu ','Tuo ','Xun ','Er ','Rong ','Xian ','Ju ','Mu ','Hao ','Qiu ','Dou ','Mushiru ','Tan ','Pei ','Ju ','Duo ','Cui ','Bi ','San ','[?] ','Mao ','Sui ','Yu ','Yu ','Tuo ','He ','Jian ','Ta ','San ',
);
<?php
$UTF8_TO_ASCII[0x90] = array(
'Lu ','Mu ','Li ','Tong ','Rong ','Chang ','Pu ','Luo ','Zhan ','Sao ','Zhan ','Meng ','Luo ','Qu ','Die ','Shi ','Di ','Min ','Jue ','Mang ','Qi ','Pie ','Nai ','Qi ','Dao ','Xian ','Chuan ','Fen ','Ri ','Nei ','[?] ','Fu ','Shen ','Dong ','Qing ','Qi ','Yin ','Xi ','Hai ','Yang ','An ','Ya ','Ke ','Qing ','Ya ','Dong ','Dan ','Lu ','Qing ','Yang ','Yun ','Yun ','Shui ','San ','Zheng ','Bing ','Yong ','Dang ','Shitamizu ','Le ','Ni ','Tun ','Fan ','Gui ','Ting ','Zhi ','Qiu ','Bin ','Ze ','Mian ','Cuan ','Hui ','Diao ','Yi ','Cha ','Zhuo ','Chuan ','Wan ','Fan ','Dai ','Xi ','Tuo ','Mang ','Qiu ','Qi ','Shan ','Pai ','Han ','Qian ','Wu ','Wu ','Xun ','Si ','Ru ','Gong ','Jiang ','Chi ','Wu ','Tsuchi ','[?] ','Tang ','Zhi ','Chi ','Qian ','Mi ','Yu ','Wang ','Qing ','Jing ','Rui ','Jun ','Hong ','Tai ','Quan ','Ji ','Bian ','Bian ','Gan ','Wen ','Zhong ','Fang ','Xiong ','Jue ','Hang ','Niou ','Qi ','Fen ','Xu ','Xu ','Qin ','Yi ','Wo ','Yun ','Yuan ','Hang ','Yan ','Chen ','Chen ','Dan ','You ','Dun ','Hu ','Huo ','Qie ','Mu ','Rou ','Mei ','Ta ','Mian ','Wu ','Chong ','Tian ','Bi ','Sha ','Zhi ','Pei ','Pan ','Zhui ','Za ','Gou ','Liu ','Mei ','Ze ','Feng ','Ou ','Li ','Lun ','Cang ','Feng ','Wei ','Hu ','Mo ','Mei ','Shu ','Ju ','Zan ','Tuo ','Tuo ','Tuo ','He ','Li ','Mi ','Yi ','Fa ','Fei ','You ','Tian ','Zhi ','Zhao ','Gu ','Zhan ','Yan ','Si ','Kuang ','Jiong ','Ju ','Xie ','Qiu ','Yi ','Jia ','Zhong ','Quan ','Bo ','Hui ','Mi ','Ben ','Zhuo ','Chu ','Le ','You ','Gu ','Hong ','Gan ','Fa ','Mao ','Si ','Hu ','Ping ','Ci ','Fan ','Chi ','Su ','Ning ','Cheng ','Ling ','Pao ','Bo ','Qi ','Si ','Ni ','Ju ','Yue ','Zhu ','Sheng ','Lei ','Xuan ','Xue ','Fu ','Pan ','Min ','Tai ','Yang ','Ji ','Yong ','Guan ','Beng ','Xue ','Long ','Lu ','[?] ','Bo ','Xie ','Po ','Ze ','Jing ','Yin ',
);
<?php
$UTF8_TO_ASCII[0x91] = array(
'Zhou ','Ji ','Yi ','Hui ','Hui ','Zui ','Cheng ','Yin ','Wei ','Hou ','Jian ','Yang ','Lie ','Si ','Ji ','Er ','Xing ','Fu ','Sa ','Suo ','Zhi ','Yin ','Wu ','Xi ','Kao ','Zhu ','Jiang ','Luo ','[?] ','An ','Dong ','Yi ','Mou ','Lei ','Yi ','Mi ','Quan ','Jin ','Mo ','Wei ','Xiao ','Xie ','Hong ','Xu ','Shuo ','Kuang ','Tao ','Qie ','Ju ','Er ','Zhou ','Ru ','Ping ','Xun ','Xiong ','Zhi ','Guang ','Huan ','Ming ','Huo ','Wa ','Qia ','Pai ','Wu ','Qu ','Liu ','Yi ','Jia ','Jing ','Qian ','Jiang ','Jiao ','Cheng ','Shi ','Zhuo ','Ce ','Pal ','Kuai ','Ji ','Liu ','Chan ','Hun ','Hu ','Nong ','Xun ','Jin ','Lie ','Qiu ','Wei ','Zhe ','Jun ','Han ','Bang ','Mang ','Zhuo ','You ','Xi ','Bo ','Dou ','Wan ','Hong ','Yi ','Pu ','Ying ','Lan ','Hao ','Lang ','Han ','Li ','Geng ','Fu ','Wu ','Lian ','Chun ','Feng ','Yi ','Yu ','Tong ','Lao ','Hai ','Jin ','Jia ','Chong ','Weng ','Mei ','Sui ','Cheng ','Pei ','Xian ','Shen ','Tu ','Kun ','Pin ','Nie ','Han ','Jing ','Xiao ','She ','Nian ','Tu ','Yong ','Xiao ','Xian ','Ting ','E ','Su ','Tun ','Juan ','Cen ','Ti ','Li ','Shui ','Si ','Lei ','Shui ','Tao ','Du ','Lao ','Lai ','Lian ','Wei ','Wo ','Yun ','Huan ','Di ','[?] ','Run ','Jian ','Zhang ','Se ','Fu ','Guan ','Xing ','Shou ','Shuan ','Ya ','Chuo ','Zhang ','Ye ','Kong ','Wo ','Han ','Tuo ','Dong ','He ','Wo ','Ju ','Gan ','Liang ','Hun ','Ta ','Zhuo ','Dian ','Qie ','De ','Juan ','Zi ','Xi ','Yao ','Qi ','Gu ','Guo ','Han ','Lin ','Tang ','Zhou ','Peng ','Hao ','Chang ','Shu ','Qi ','Fang ','Chi ','Lu ','Nao ','Ju ','Tao ','Cong ','Lei ','Zhi ','Peng ','Fei ','Song ','Tian ','Pi ','Dan ','Yu ','Ni ','Yu ','Lu ','Gan ','Mi ','Jing ','Ling ','Lun ','Yin ','Cui ','Qu ','Huai ','Yu ','Nian ','Shen ','Piao ','Chun ','Wa ','Yuan ','Lai ','Hun ','Qing ','Yan ','Qian ','Tian ','Miao ','Zhi ','Yin ','Mi ',
);
<?php
$UTF8_TO_ASCII[0x92] = array(
'Ben ','Yuan ','Wen ','Re ','Fei ','Qing ','Yuan ','Ke ','Ji ','She ','Yuan ','Shibui ','Lu ','Zi ','Du ','[?] ','Jian ','Min ','Pi ','Tani ','Yu ','Yuan ','Shen ','Shen ','Rou ','Huan ','Zhu ','Jian ','Nuan ','Yu ','Qiu ','Ting ','Qu ','Du ','Feng ','Zha ','Bo ','Wo ','Wo ','Di ','Wei ','Wen ','Ru ','Xie ','Ce ','Wei ','Ge ','Gang ','Yan ','Hong ','Xuan ','Mi ','Ke ','Mao ','Ying ','Yan ','You ','Hong ','Miao ','Xing ','Mei ','Zai ','Hun ','Nai ','Kui ','Shi ','E ','Pai ','Mei ','Lian ','Qi ','Qi ','Mei ','Tian ','Cou ','Wei ','Can ','Tuan ','Mian ','Hui ','Mo ','Xu ','Ji ','Pen ','Jian ','Jian ','Hu ','Feng ','Xiang ','Yi ','Yin ','Zhan ','Shi ','Jie ','Cheng ','Huang ','Tan ','Yu ','Bi ','Min ','Shi ','Tu ','Sheng ','Yong ','Qu ','Zhong ','Suei ','Jiu ','Jiao ','Qiou ','Yin ','Tang ','Long ','Huo ','Yuan ','Nan ','Ban ','You ','Quan ','Chui ','Liang ','Chan ','Yan ','Chun ','Nie ','Zi ','Wan ','Shi ','Man ','Ying ','Ratsu ','Kui ','[?] ','Jian ','Xu ','Lu ','Gui ','Gai ','[?] ','[?] ','Po ','Jin ','Gui ','Tang ','Yuan ','Suo ','Yuan ','Lian ','Yao ','Meng ','Zhun ','Sheng ','Ke ','Tai ','Da ','Wa ','Liu ','Gou ','Sao ','Ming ','Zha ','Shi ','Yi ','Lun ','Ma ','Pu ','Wei ','Li ','Cai ','Wu ','Xi ','Wen ','Qiang ','Ze ','Shi ','Su ','Yi ','Zhen ','Sou ','Yun ','Xiu ','Yin ','Rong ','Hun ','Su ','Su ','Ni ','Ta ','Shi ','Ru ','Wei ','Pan ','Chu ','Chu ','Pang ','Weng ','Cang ','Mie ','He ','Dian ','Hao ','Huang ','Xi ','Zi ','Di ','Zhi ','Ying ','Fu ','Jie ','Hua ','Ge ','Zi ','Tao ','Teng ','Sui ','Bi ','Jiao ','Hui ','Gun ','Yin ','Gao ','Long ','Zhi ','Yan ','She ','Man ','Ying ','Chun ','Lu ','Lan ','Luan ','[?] ','Bin ','Tan ','Yu ','Sou ','Hu ','Bi ','Biao ','Zhi ','Jiang ','Kou ','Shen ','Shang ','Di ','Mi ','Ao ','Lu ','Hu ','Hu ','You ','Chan ','Fan ','Yong ','Gun ','Man ',
);
<?php
$UTF8_TO_ASCII[0x93] = array(
'Qing ','Yu ','Piao ','Ji ','Ya ','Jiao ','Qi ','Xi ','Ji ','Lu ','Lu ','Long ','Jin ','Guo ','Cong ','Lou ','Zhi ','Gai ','Qiang ','Li ','Yan ','Cao ','Jiao ','Cong ','Qun ','Tuan ','Ou ','Teng ','Ye ','Xi ','Mi ','Tang ','Mo ','Shang ','Han ','Lian ','Lan ','Wa ','Li ','Qian ','Feng ','Xuan ','Yi ','Man ','Zi ','Mang ','Kang ','Lei ','Peng ','Shu ','Zhang ','Zhang ','Chong ','Xu ','Huan ','Kuo ','Jian ','Yan ','Chuang ','Liao ','Cui ','Ti ','Yang ','Jiang ','Cong ','Ying ','Hong ','Xun ','Shu ','Guan ','Ying ','Xiao ','[?] ','[?] ','Xu ','Lian ','Zhi ','Wei ','Pi ','Jue ','Jiao ','Po ','Dang ','Hui ','Jie ','Wu ','Pa ','Ji ','Pan ','Gui ','Xiao ','Qian ','Qian ','Xi ','Lu ','Xi ','Xuan ','Dun ','Huang ','Min ','Run ','Su ','Liao ','Zhen ','Zhong ','Yi ','Di ','Wan ','Dan ','Tan ','Chao ','Xun ','Kui ','Yie ','Shao ','Tu ','Zhu ','San ','Hei ','Bi ','Shan ','Chan ','Chan ','Shu ','Tong ','Pu ','Lin ','Wei ','Se ','Se ','Cheng ','Jiong ','Cheng ','Hua ','Jiao ','Lao ','Che ','Gan ','Cun ','Heng ','Si ','Shu ','Peng ','Han ','Yun ','Liu ','Hong ','Fu ','Hao ','He ','Xian ','Jian ','Shan ','Xi ','Oki ','[?] ','Lan ','[?] ','Yu ','Lin ','Min ','Zao ','Dang ','Wan ','Ze ','Xie ','Yu ','Li ','Shi ','Xue ','Ling ','Man ','Zi ','Yong ','Kuai ','Can ','Lian ','Dian ','Ye ','Ao ','Huan ','Zhen ','Chan ','Man ','Dan ','Dan ','Yi ','Sui ','Pi ','Ju ','Ta ','Qin ','Ji ','Zhuo ','Lian ','Nong ','Guo ','Jin ','Fen ','Se ','Ji ','Sui ','Hui ','Chu ','Ta ','Song ','Ding ','[?] ','Zhu ','Lai ','Bin ','Lian ','Mi ','Shi ','Shu ','Mi ','Ning ','Ying ','Ying ','Meng ','Jin ','Qi ','Pi ','Ji ','Hao ','Ru ','Zui ','Wo ','Tao ','Yin ','Yin ','Dui ','Ci ','Huo ','Jing ','Lan ','Jun ','Ai ','Pu ','Zhuo ','Wei ','Bin ','Gu ','Qian ','Xing ','Hama ','Kuo ','Fei ','[?] ','Boku ','Jian ','Wei ','Luo ','Zan ','Lu ','Li ',
);
<?php
$UTF8_TO_ASCII[0x94] = array(
'You ','Yang ','Lu ','Si ','Jie ','Ying ','Du ','Wang ','Hui ','Xie ','Pan ','Shen ','Biao ','Chan ','Mo ','Liu ','Jian ','Pu ','Se ','Cheng ','Gu ','Bin ','Huo ','Xian ','Lu ','Qin ','Han ','Ying ','Yong ','Li ','Jing ','Xiao ','Ying ','Sui ','Wei ','Xie ','Huai ','Hao ','Zhu ','Long ','Lai ','Dui ','Fan ','Hu ','Lai ','[?] ','[?] ','Ying ','Mi ','Ji ','Lian ','Jian ','Ying ','Fen ','Lin ','Yi ','Jian ','Yue ','Chan ','Dai ','Rang ','Jian ','Lan ','Fan ','Shuang ','Yuan ','Zhuo ','Feng ','She ','Lei ','Lan ','Cong ','Qu ','Yong ','Qian ','Fa ','Guan ','Que ','Yan ','Hao ','Hyeng ','Sa ','Zan ','Luan ','Yan ','Li ','Mi ','Shan ','Tan ','Dang ','Jiao ','Chan ','[?] ','Hao ','Ba ','Zhu ','Lan ','Lan ','Nang ','Wan ','Luan ','Xun ','Xian ','Yan ','Gan ','Yan ','Yu ','Huo ','Si ','Mie ','Guang ','Deng ','Hui ','Xiao ','Xiao ','Hu ','Hong ','Ling ','Zao ','Zhuan ','Jiu ','Zha ','Xie ','Chi ','Zhuo ','Zai ','Zai ','Can ','Yang ','Qi ','Zhong ','Fen ','Niu ','Jiong ','Wen ','Po ','Yi ','Lu ','Chui ','Pi ','Kai ','Pan ','Yan ','Kai ','Pang ','Mu ','Chao ','Liao ','Gui ','Kang ','Tun ','Guang ','Xin ','Zhi ','Guang ','Guang ','Wei ','Qiang ','[?] ','Da ','Xia ','Zheng ','Zhu ','Ke ','Zhao ','Fu ','Ba ','Duo ','Duo ','Ling ','Zhuo ','Xuan ','Ju ','Tan ','Pao ','Jiong ','Pao ','Tai ','Tai ','Bing ','Yang ','Tong ','Han ','Zhu ','Zha ','Dian ','Wei ','Shi ','Lian ','Chi ','Huang ','[?] ','Hu ','Shuo ','Lan ','Jing ','Jiao ','Xu ','Xing ','Quan ','Lie ','Huan ','Yang ','Xiao ','Xiu ','Xian ','Yin ','Wu ','Zhou ','Yao ','Shi ','Wei ','Tong ','Xue ','Zai ','Kai ','Hong ','Luo ','Xia ','Zhu ','Xuan ','Zheng ','Po ','Yan ','Hui ','Guang ','Zhe ','Hui ','Kao ','[?] ','Fan ','Shao ','Ye ','Hui ','[?] ','Tang ','Jin ','Re ','[?] ','Xi ','Fu ','Jiong ','Che ','Pu ','Jing ','Zhuo ','Ting ','Wan ','Hai ','Peng ','Lang ','Shan ','Hu ','Feng ','Chi ','Rong ',
);
<?php
$UTF8_TO_ASCII[0x95] = array(
'Hu ','Xi ','Shu ','He ','Xun ','Ku ','Jue ','Xiao ','Xi ','Yan ','Han ','Zhuang ','Jun ','Di ','Xie ','Ji ','Wu ','[?] ','[?] ','Han ','Yan ','Huan ','Men ','Ju ','Chou ','Bei ','Fen ','Lin ','Kun ','Hun ','Tun ','Xi ','Cui ','Wu ','Hong ','Ju ','Fu ','Wo ','Jiao ','Cong ','Feng ','Ping ','Qiong ','Ruo ','Xi ','Qiong ','Xin ','Zhuo ','Yan ','Yan ','Yi ','Jue ','Yu ','Gang ','Ran ','Pi ','Gu ','[?] ','Sheng ','Chang ','Shao ','[?] ','[?] ','[?] ','[?] ','Chen ','He ','Kui ','Zhong ','Duan ','Xia ','Hui ','Feng ','Lian ','Xuan ','Xing ','Huang ','Jiao ','Jian ','Bi ','Ying ','Zhu ','Wei ','Tuan ','Tian ','Xi ','Nuan ','Nuan ','Chan ','Yan ','Jiong ','Jiong ','Yu ','Mei ','Sha ','Wei ','Ye ','Xin ','Qiong ','Rou ','Mei ','Huan ','Xu ','Zhao ','Wei ','Fan ','Qiu ','Sui ','Yang ','Lie ','Zhu ','Jie ','Gao ','Gua ','Bao ','Hu ','Yun ','Xia ','[?] ','[?] ','Bian ','Gou ','Tui ','Tang ','Chao ','Shan ','N ','Bo ','Huang ','Xie ','Xi ','Wu ','Xi ','Yun ','He ','He ','Xi ','Yun ','Xiong ','Nai ','Shan ','Qiong ','Yao ','Xun ','Mi ','Lian ','Ying ','Wen ','Rong ','Oozutsu ','[?] ','Qiang ','Liu ','Xi ','Bi ','Biao ','Zong ','Lu ','Jian ','Shou ','Yi ','Lou ','Feng ','Sui ','Yi ','Tong ','Jue ','Zong ','Yun ','Hu ','Yi ','Zhi ','Ao ','Wei ','Liao ','Han ','Ou ','Re ','Jiong ','Man ','[?] ','Shang ','Cuan ','Zeng ','Jian ','Xi ','Xi ','Xi ','Yi ','Xiao ','Chi ','Huang ','Chan ','Ye ','Qian ','Ran ','Yan ','Xian ','Qiao ','Zun ','Deng ','Dun ','Shen ','Jiao ','Fen ','Si ','Liao ','Yu ','Lin ','Tong ','Shao ','Fen ','Fan ','Yan ','Xun ','Lan ','Mei ','Tang ','Yi ','Jing ','Men ','[?] ','[?] ','Ying ','Yu ','Yi ','Xue ','Lan ','Tai ','Zao ','Can ','Sui ','Xi ','Que ','Cong ','Lian ','Hui ','Zhu ','Xie ','Ling ','Wei ','Yi ','Xie ','Zhao ','Hui ','Tatsu ','Nung ','Lan ','Ru ','Xian ','Kao ','Xun ','Jin ','Chou ','Chou ','Yao ',
);
<?php
$UTF8_TO_ASCII[0x96] = array(
'He ','Lan ','Biao ','Rong ','Li ','Mo ','Bao ','Ruo ','Lu ','La ','Ao ','Xun ','Kuang ','Shuo ','[?] ','Li ','Lu ','Jue ','Liao ','Yan ','Xi ','Xie ','Long ','Ye ','[?] ','Rang ','Yue ','Lan ','Cong ','Jue ','Tong ','Guan ','[?] ','Che ','Mi ','Tang ','Lan ','Zhu ','[?] ','Ling ','Cuan ','Yu ','Zhua ','Tsumekanmuri ','Pa ','Zheng ','Pao ','Cheng ','Yuan ','Ai ','Wei ','[?] ','Jue ','Jue ','Fu ','Ye ','Ba ','Die ','Ye ','Yao ','Zu ','Shuang ','Er ','Qiang ','Chuang ','Ge ','Zang ','Die ','Qiang ','Yong ','Qiang ','Pian ','Ban ','Pan ','Shao ','Jian ','Pai ','Du ','Chuang ','Tou ','Zha ','Bian ','Die ','Bang ','Bo ','Chuang ','You ','[?] ','Du ','Ya ','Cheng ','Niu ','Ushihen ','Pin ','Jiu ','Mou ','Tuo ','Mu ','Lao ','Ren ','Mang ','Fang ','Mao ','Mu ','Gang ','Wu ','Yan ','Ge ','Bei ','Si ','Jian ','Gu ','You ','Ge ','Sheng ','Mu ','Di ','Qian ','Quan ','Quan ','Zi ','Te ','Xi ','Mang ','Keng ','Qian ','Wu ','Gu ','Xi ','Li ','Li ','Pou ','Ji ','Gang ','Zhi ','Ben ','Quan ','Run ','Du ','Ju ','Jia ','Jian ','Feng ','Pian ','Ke ','Ju ','Kao ','Chu ','Xi ','Bei ','Luo ','Jie ','Ma ','San ','Wei ','Li ','Dun ','Tong ','[?] ','Jiang ','Ikenie ','Li ','Du ','Lie ','Pi ','Piao ','Bao ','Xi ','Chou ','Wei ','Kui ','Chou ','Quan ','Fan ','Ba ','Fan ','Qiu ','Ji ','Cai ','Chuo ','An ','Jie ','Zhuang ','Guang ','Ma ','You ','Kang ','Bo ','Hou ','Ya ','Yin ','Huan ','Zhuang ','Yun ','Kuang ','Niu ','Di ','Qing ','Zhong ','Mu ','Bei ','Pi ','Ju ','Ni ','Sheng ','Pao ','Xia ','Tuo ','Hu ','Ling ','Fei ','Pi ','Ni ','Ao ','You ','Gou ','Yue ','Ju ','Dan ','Po ','Gu ','Xian ','Ning ','Huan ','Hen ','Jiao ','He ','Zhao ','Ji ','Xun ','Shan ','Ta ','Rong ','Shou ','Tong ','Lao ','Du ','Xia ','Shi ','Hua ','Zheng ','Yu ','Sun ','Yu ','Bi ','Mang ','Xi ','Juan ','Li ','Xia ','Yin ','Suan ','Lang ','Bei ','Zhi ','Yan ',
);
<?php
$UTF8_TO_ASCII[0x97] = array(
'Sha ','Li ','Han ','Xian ','Jing ','Pai ','Fei ','Yao ','Ba ','Qi ','Ni ','Biao ','Yin ','Lai ','Xi ','Jian ','Qiang ','Kun ','Yan ','Guo ','Zong ','Mi ','Chang ','Yi ','Zhi ','Zheng ','Ya ','Meng ','Cai ','Cu ','She ','Kari ','Cen ','Luo ','Hu ','Zong ','Ji ','Wei ','Feng ','Wo ','Yuan ','Xing ','Zhu ','Mao ','Wei ','Yuan ','Xian ','Tuan ','Ya ','Nao ','Xie ','Jia ','Hou ','Bian ','You ','You ','Mei ','Zha ','Yao ','Sun ','Bo ','Ming ','Hua ','Yuan ','Sou ','Ma ','Yuan ','Dai ','Yu ','Shi ','Hao ','[?] ','Yi ','Zhen ','Chuang ','Hao ','Man ','Jing ','Jiang ','Mu ','Zhang ','Chan ','Ao ','Ao ','Hao ','Cui ','Fen ','Jue ','Bi ','Bi ','Huang ','Pu ','Lin ','Yu ','Tong ','Yao ','Liao ','Shuo ','Xiao ','Swu ','Ton ','Xi ','Ge ','Juan ','Du ','Hui ','Kuai ','Xian ','Xie ','Ta ','Xian ','Xun ','Ning ','Pin ','Huo ','Nou ','Meng ','Lie ','Nao ','Guang ','Shou ','Lu ','Ta ','Xian ','Mi ','Rang ','Huan ','Nao ','Luo ','Xian ','Qi ','Jue ','Xuan ','Miao ','Zi ','Lu ','Lu ','Yu ','Su ','Wang ','Qiu ','Ga ','Ding ','Le ','Ba ','Ji ','Hong ','Di ','Quan ','Gan ','Jiu ','Yu ','Ji ','Yu ','Yang ','Ma ','Gong ','Wu ','Fu ','Wen ','Jie ','Ya ','Fen ','Bian ','Beng ','Yue ','Jue ','Yun ','Jue ','Wan ','Jian ','Mei ','Dan ','Pi ','Wei ','Huan ','Xian ','Qiang ','Ling ','Dai ','Yi ','An ','Ping ','Dian ','Fu ','Xuan ','Xi ','Bo ','Ci ','Gou ','Jia ','Shao ','Po ','Ci ','Ke ','Ran ','Sheng ','Shen ','Yi ','Zu ','Jia ','Min ','Shan ','Liu ','Bi ','Zhen ','Zhen ','Jue ','Fa ','Long ','Jin ','Jiao ','Jian ','Li ','Guang ','Xian ','Zhou ','Gong ','Yan ','Xiu ','Yang ','Xu ','Luo ','Su ','Zhu ','Qin ','Ken ','Xun ','Bao ','Er ','Xiang ','Yao ','Xia ','Heng ','Gui ','Chong ','Xu ','Ban ','Pei ','[?] ','Dang ','Ei ','Hun ','Wen ','E ','Cheng ','Ti ','Wu ','Wu ','Cheng ','Jun ','Mei ','Bei ','Ting ','Xian ','Chuo ',
);
<?php
$UTF8_TO_ASCII[0x98] = array(
'Han ','Xuan ','Yan ','Qiu ','Quan ','Lang ','Li ','Xiu ','Fu ','Liu ','Ye ','Xi ','Ling ','Li ','Jin ','Lian ','Suo ','Chiisai ','[?] ','Wan ','Dian ','Pin ','Zhan ','Cui ','Min ','Yu ','Ju ','Chen ','Lai ','Wen ','Sheng ','Wei ','Dian ','Chu ','Zhuo ','Pei ','Cheng ','Hu ','Qi ','E ','Kun ','Chang ','Qi ','Beng ','Wan ','Lu ','Cong ','Guan ','Yan ','Diao ','Bei ','Lin ','Qin ','Pi ','Pa ','Que ','Zhuo ','Qin ','Fa ','[?] ','Qiong ','Du ','Jie ','Hun ','Yu ','Mao ','Mei ','Chun ','Xuan ','Ti ','Xing ','Dai ','Rou ','Min ','Zhen ','Wei ','Ruan ','Huan ','Jie ','Chuan ','Jian ','Zhuan ','Yang ','Lian ','Quan ','Xia ','Duan ','Yuan ','Ye ','Nao ','Hu ','Ying ','Yu ','Huang ','Rui ','Se ','Liu ','Shi ','Rong ','Suo ','Yao ','Wen ','Wu ','Jin ','Jin ','Ying ','Ma ','Tao ','Liu ','Tang ','Li ','Lang ','Gui ','Zhen ','Qiang ','Cuo ','Jue ','Zhao ','Yao ','Ai ','Bin ','Tu ','Chang ','Kun ','Zhuan ','Cong ','Jin ','Yi ','Cui ','Cong ','Qi ','Li ','Ying ','Suo ','Qiu ','Xuan ','Ao ','Lian ','Man ','Zhang ','Yin ','[?] ','Ying ','Zhi ','Lu ','Wu ','Deng ','Xiou ','Zeng ','Xun ','Qu ','Dang ','Lin ','Liao ','Qiong ','Su ','Huang ','Gui ','Pu ','Jing ','Fan ','Jin ','Liu ','Ji ','[?] ','Jing ','Ai ','Bi ','Can ','Qu ','Zao ','Dang ','Jiao ','Gun ','Tan ','Hui ','Huan ','Se ','Sui ','Tian ','[?] ','Yu ','Jin ','Lu ','Bin ','Shou ','Wen ','Zui ','Lan ','Xi ','Ji ','Xuan ','Ruan ','Huo ','Gai ','Lei ','Du ','Li ','Zhi ','Rou ','Li ','Zan ','Qiong ','Zhe ','Gui ','Sui ','La ','Long ','Lu ','Li ','Zan ','Lan ','Ying ','Mi ','Xiang ','Xi ','Guan ','Dao ','Zan ','Huan ','Gua ','Bo ','Die ','Bao ','Hu ','Zhi ','Piao ','Ban ','Rang ','Li ','Wa ','Dekaguramu ','Jiang ','Qian ','Fan ','Pen ','Fang ','Dan ','Weng ','Ou ','Deshiguramu ','Miriguramu ','Thon ','Hu ','Ling ','Yi ','Ping ','Ci ','Hekutogura ','Juan ','Chang ','Chi ','Sarake ','Dang ','Meng ','Pou ',
);
<?php
$UTF8_TO_ASCII[0x99] = array(
'Zhui ','Ping ','Bian ','Zhou ','Zhen ','Senchigura ','Ci ','Ying ','Qi ','Xian ','Lou ','Di ','Ou ','Meng ','Zhuan ','Peng ','Lin ','Zeng ','Wu ','Pi ','Dan ','Weng ','Ying ','Yan ','Gan ','Dai ','Shen ','Tian ','Tian ','Han ','Chang ','Sheng ','Qing ','Sheng ','Chan ','Chan ','Rui ','Sheng ','Su ','Sen ','Yong ','Shuai ','Lu ','Fu ','Yong ','Beng ','Feng ','Ning ','Tian ','You ','Jia ','Shen ','Zha ','Dian ','Fu ','Nan ','Dian ','Ping ','Ting ','Hua ','Ting ','Quan ','Zi ','Meng ','Bi ','Qi ','Liu ','Xun ','Liu ','Chang ','Mu ','Yun ','Fan ','Fu ','Geng ','Tian ','Jie ','Jie ','Quan ','Wei ','Fu ','Tian ','Mu ','Tap ','Pan ','Jiang ','Wa ','Da ','Nan ','Liu ','Ben ','Zhen ','Chu ','Mu ','Mu ','Ce ','Cen ','Gai ','Bi ','Da ','Zhi ','Lue ','Qi ','Lue ','Pan ','Kesa ','Fan ','Hua ','Yu ','Yu ','Mu ','Jun ','Yi ','Liu ','Yu ','Die ','Chou ','Hua ','Dang ','Chuo ','Ji ','Wan ','Jiang ','Sheng ','Chang ','Tuan ','Lei ','Ji ','Cha ','Liu ','Tatamu ','Tuan ','Lin ','Jiang ','Jiang ','Chou ','Bo ','Die ','Die ','Pi ','Nie ','Dan ','Shu ','Shu ','Zhi ','Yi ','Chuang ','Nai ','Ding ','Bi ','Jie ','Liao ','Gong ','Ge ','Jiu ','Zhou ','Xia ','Shan ','Xu ','Nue ','Li ','Yang ','Chen ','You ','Ba ','Jie ','Jue ','Zhi ','Xia ','Cui ','Bi ','Yi ','Li ','Zong ','Chuang ','Feng ','Zhu ','Pao ','Pi ','Gan ','Ke ','Ci ','Xie ','Qi ','Dan ','Zhen ','Fa ','Zhi ','Teng ','Ju ','Ji ','Fei ','Qu ','Dian ','Jia ','Xian ','Cha ','Bing ','Ni ','Zheng ','Yong ','Jing ','Quan ','Chong ','Tong ','Yi ','Kai ','Wei ','Hui ','Duo ','Yang ','Chi ','Zhi ','Hen ','Ya ','Mei ','Dou ','Jing ','Xiao ','Tong ','Tu ','Mang ','Pi ','Xiao ','Suan ','Pu ','Li ','Zhi ','Cuo ','Duo ','Wu ','Sha ','Lao ','Shou ','Huan ','Xian ','Yi ','Peng ','Zhang ','Guan ','Tan ','Fei ','Ma ','Lin ','Chi ','Ji ','Dian ','An ','Chi ','Bi ','Bei ','Min ','Gu ','Dui ','E ','Wei ',
);
<?php
$UTF8_TO_ASCII[0x9a] = array(
'Yu ','Cui ','Ya ','Zhu ','Cu ','Dan ','Shen ','Zhung ','Ji ','Yu ','Hou ','Feng ','La ','Yang ','Shen ','Tu ','Yu ','Gua ','Wen ','Huan ','Ku ','Jia ','Yin ','Yi ','Lu ','Sao ','Jue ','Chi ','Xi ','Guan ','Yi ','Wen ','Ji ','Chuang ','Ban ','Lei ','Liu ','Chai ','Shou ','Nue ','Dian ','Da ','Pie ','Tan ','Zhang ','Biao ','Shen ','Cu ','Luo ','Yi ','Zong ','Chou ','Zhang ','Zhai ','Sou ','Suo ','Que ','Diao ','Lou ','Lu ','Mo ','Jin ','Yin ','Ying ','Huang ','Fu ','Liao ','Long ','Qiao ','Liu ','Lao ','Xian ','Fei ','Dan ','Yin ','He ','Yan ','Ban ','Xian ','Guan ','Guai ','Nong ','Yu ','Wei ','Yi ','Yong ','Pi ','Lei ','Li ','Shu ','Dan ','Lin ','Dian ','Lin ','Lai ','Pie ','Ji ','Chi ','Yang ','Xian ','Jie ','Zheng ','[?] ','Li ','Huo ','Lai ','Shaku ','Dian ','Xian ','Ying ','Yin ','Qu ','Yong ','Tan ','Dian ','Luo ','Luan ','Luan ','Bo ','[?] ','Gui ','Po ','Fa ','Deng ','Fa ','Bai ','Bai ','Qie ','Bi ','Zao ','Zao ','Mao ','De ','Pa ','Jie ','Huang ','Gui ','Ci ','Ling ','Gao ','Mo ','Ji ','Jiao ','Peng ','Gao ','Ai ','E ','Hao ','Han ','Bi ','Wan ','Chou ','Qian ','Xi ','Ai ','Jiong ','Hao ','Huang ','Hao ','Ze ','Cui ','Hao ','Xiao ','Ye ','Po ','Hao ','Jiao ','Ai ','Xing ','Huang ','Li ','Piao ','He ','Jiao ','Pi ','Gan ','Pao ','Zhou ','Jun ','Qiu ','Cun ','Que ','Zha ','Gu ','Jun ','Jun ','Zhou ','Zha ','Gu ','Zhan ','Du ','Min ','Qi ','Ying ','Yu ','Bei ','Zhao ','Zhong ','Pen ','He ','Ying ','He ','Yi ','Bo ','Wan ','He ','Ang ','Zhan ','Yan ','Jian ','He ','Yu ','Kui ','Fan ','Gai ','Dao ','Pan ','Fu ','Qiu ','Sheng ','Dao ','Lu ','Zhan ','Meng ','Li ','Jin ','Xu ','Jian ','Pan ','Guan ','An ','Lu ','Shu ','Zhou ','Dang ','An ','Gu ','Li ','Mu ','Cheng ','Gan ','Xu ','Mang ','Mang ','Zhi ','Qi ','Ruan ','Tian ','Xiang ','Dun ','Xin ','Xi ','Pan ','Feng ','Dun ','Min ',
);
<?php
$UTF8_TO_ASCII[0x9b] = array(
'Ming ','Sheng ','Shi ','Yun ','Mian ','Pan ','Fang ','Miao ','Dan ','Mei ','Mao ','Kan ','Xian ','Ou ','Shi ','Yang ','Zheng ','Yao ','Shen ','Huo ','Da ','Zhen ','Kuang ','Ju ','Shen ','Chi ','Sheng ','Mei ','Mo ','Zhu ','Zhen ','Zhen ','Mian ','Di ','Yuan ','Die ','Yi ','Zi ','Zi ','Chao ','Zha ','Xuan ','Bing ','Mi ','Long ','Sui ','Dong ','Mi ','Die ','Yi ','Er ','Ming ','Xuan ','Chi ','Kuang ','Juan ','Mou ','Zhen ','Tiao ','Yang ','Yan ','Mo ','Zhong ','Mai ','Zhao ','Zheng ','Mei ','Jun ','Shao ','Han ','Huan ','Di ','Cheng ','Cuo ','Juan ','E ','Wan ','Xian ','Xi ','Kun ','Lai ','Jian ','Shan ','Tian ','Hun ','Wan ','Ling ','Shi ','Qiong ','Lie ','Yai ','Jing ','Zheng ','Li ','Lai ','Sui ','Juan ','Shui ','Sui ','Du ','Bi ','Bi ','Mu ','Hun ','Ni ','Lu ','Yi ','Jie ','Cai ','Zhou ','Yu ','Hun ','Ma ','Xia ','Xing ','Xi ','Gun ','Cai ','Chun ','Jian ','Mei ','Du ','Hou ','Xuan ','Ti ','Kui ','Gao ','Rui ','Mou ','Xu ','Fa ','Wen ','Miao ','Chou ','Kui ','Mi ','Weng ','Kou ','Dang ','Chen ','Ke ','Sou ','Xia ','Qiong ','Mao ','Ming ','Man ','Shui ','Ze ','Zhang ','Yi ','Diao ','Ou ','Mo ','Shun ','Cong ','Lou ','Chi ','Man ','Piao ','Cheng ','Ji ','Meng ','[?] ','Run ','Pie ','Xi ','Qiao ','Pu ','Zhu ','Deng ','Shen ','Shun ','Liao ','Che ','Xian ','Kan ','Ye ','Xu ','Tong ','Mou ','Lin ','Kui ','Xian ','Ye ','Ai ','Hui ','Zhan ','Jian ','Gu ','Zhao ','Qu ','Wei ','Chou ','Sao ','Ning ','Xun ','Yao ','Huo ','Meng ','Mian ','Bin ','Mian ','Li ','Kuang ','Jue ','Xuan ','Mian ','Huo ','Lu ','Meng ','Long ','Guan ','Man ','Xi ','Chu ','Tang ','Kan ','Zhu ','Mao ','Jin ','Lin ','Yu ','Shuo ','Ce ','Jue ','Shi ','Yi ','Shen ','Zhi ','Hou ','Shen ','Ying ','Ju ','Zhou ','Jiao ','Cuo ','Duan ','Ai ','Jiao ','Zeng ','Huo ','Bai ','Shi ','Ding ','Qi ','Ji ','Zi ','Gan ','Wu ','Tuo ','Ku ','Qiang ','Xi ','Fan ','Kuang ',
);
<?php
$UTF8_TO_ASCII[0x9c] = array(
'Dang ','Ma ','Sha ','Dan ','Jue ','Li ','Fu ','Min ','Nuo ','Huo ','Kang ','Zhi ','Qi ','Kan ','Jie ','Fen ','E ','Ya ','Pi ','Zhe ','Yan ','Sui ','Zhuan ','Che ','Dun ','Pan ','Yan ','[?] ','Feng ','Fa ','Mo ','Zha ','Qu ','Yu ','Luo ','Tuo ','Tuo ','Di ','Zhai ','Zhen ','Ai ','Fei ','Mu ','Zhu ','Li ','Bian ','Nu ','Ping ','Peng ','Ling ','Pao ','Le ','Po ','Bo ','Po ','Shen ','Za ','Nuo ','Li ','Long ','Tong ','[?] ','Li ','Aragane ','Chu ','Keng ','Quan ','Zhu ','Kuang ','Huo ','E ','Nao ','Jia ','Lu ','Wei ','Ai ','Luo ','Ken ','Xing ','Yan ','Tong ','Peng ','Xi ','[?] ','Hong ','Shuo ','Xia ','Qiao ','[?] ','Wei ','Qiao ','[?] ','Keng ','Xiao ','Que ','Chan ','Lang ','Hong ','Yu ','Xiao ','Xia ','Mang ','Long ','Iong ','Che ','Che ','E ','Liu ','Ying ','Mang ','Que ','Yan ','Sha ','Kun ','Yu ','[?] ','Kaki ','Lu ','Chen ','Jian ','Nue ','Song ','Zhuo ','Keng ','Peng ','Yan ','Zhui ','Kong ','Ceng ','Qi ','Zong ','Qing ','Lin ','Jun ','Bo ','Ding ','Min ','Diao ','Jian ','He ','Lu ','Ai ','Sui ','Que ','Ling ','Bei ','Yin ','Dui ','Wu ','Qi ','Lun ','Wan ','Dian ','Gang ','Pei ','Qi ','Chen ','Ruan ','Yan ','Die ','Ding ','Du ','Tuo ','Jie ','Ying ','Bian ','Ke ','Bi ','Wei ','Shuo ','Zhen ','Duan ','Xia ','Dang ','Ti ','Nao ','Peng ','Jian ','Di ','Tan ','Cha ','Seki ','Qi ','[?] ','Feng ','Xuan ','Que ','Que ','Ma ','Gong ','Nian ','Su ','E ','Ci ','Liu ','Si ','Tang ','Bang ','Hua ','Pi ','Wei ','Sang ','Lei ','Cuo ','Zhen ','Xia ','Qi ','Lian ','Pan ','Wei ','Yun ','Dui ','Zhe ','Ke ','La ','[?] ','Qing ','Gun ','Zhuan ','Chan ','Qi ','Ao ','Peng ','Lu ','Lu ','Kan ','Qiang ','Chen ','Yin ','Lei ','Biao ','Qi ','Mo ','Qi ','Cui ','Zong ','Qing ','Chuo ','[?] ','Ji ','Shan ','Lao ','Qu ','Zeng ','Deng ','Jian ','Xi ','Lin ','Ding ','Dian ','Huang ','Pan ','Za ','Qiao ','Di ','Li ',
);
<?php
$UTF8_TO_ASCII[0x9d] = array(
'Tani ','Jiao ','[?] ','Zhang ','Qiao ','Dun ','Xian ','Yu ','Zhui ','He ','Huo ','Zhai ','Lei ','Ke ','Chu ','Ji ','Que ','Dang ','Yi ','Jiang ','Pi ','Pi ','Yu ','Pin ','Qi ','Ai ','Kai ','Jian ','Yu ','Ruan ','Meng ','Pao ','Ci ','[?] ','[?] ','Mie ','Ca ','Xian ','Kuang ','Lei ','Lei ','Zhi ','Li ','Li ','Fan ','Que ','Pao ','Ying ','Li ','Long ','Long ','Mo ','Bo ','Shuang ','Guan ','Lan ','Zan ','Yan ','Shi ','Shi ','Li ','Reng ','She ','Yue ','Si ','Qi ','Ta ','Ma ','Xie ','Xian ','Xian ','Zhi ','Qi ','Zhi ','Beng ','Dui ','Zhong ','[?] ','Yi ','Shi ','You ','Zhi ','Tiao ','Fu ','Fu ','Mi ','Zu ','Zhi ','Suan ','Mei ','Zuo ','Qu ','Hu ','Zhu ','Shen ','Sui ','Ci ','Chai ','Mi ','Lu ','Yu ','Xiang ','Wu ','Tiao ','Piao ','Zhu ','Gui ','Xia ','Zhi ','Ji ','Gao ','Zhen ','Gao ','Shui ','Jin ','Chen ','Gai ','Kun ','Di ','Dao ','Huo ','Tao ','Qi ','Gu ','Guan ','Zui ','Ling ','Lu ','Bing ','Jin ','Dao ','Zhi ','Lu ','Shan ','Bei ','Zhe ','Hui ','You ','Xi ','Yin ','Zi ','Huo ','Zhen ','Fu ','Yuan ','Wu ','Xian ','Yang ','Ti ','Yi ','Mei ','Si ','Di ','[?] ','Zhuo ','Zhen ','Yong ','Ji ','Gao ','Tang ','Si ','Ma ','Ta ','[?] ','Xuan ','Qi ','Yu ','Xi ','Ji ','Si ','Chan ','Tan ','Kuai ','Sui ','Li ','Nong ','Ni ','Dao ','Li ','Rang ','Yue ','Ti ','Zan ','Lei ','Rou ','Yu ','Yu ','Chi ','Xie ','Qin ','He ','Tu ','Xiu ','Si ','Ren ','Tu ','Zi ','Cha ','Gan ','Yi ','Xian ','Bing ','Nian ','Qiu ','Qiu ','Chong ','Fen ','Hao ','Yun ','Ke ','Miao ','Zhi ','Geng ','Bi ','Zhi ','Yu ','Mi ','Ku ','Ban ','Pi ','Ni ','Li ','You ','Zu ','Pi ','Ba ','Ling ','Mo ','Cheng ','Nian ','Qin ','Yang ','Zuo ','Zhi ','Zhi ','Shu ','Ju ','Zi ','Huo ','Ji ','Cheng ','Tong ','Zhi ','Huo ','He ','Yin ','Zi ','Zhi ','Jie ','Ren ','Du ','Yi ','Zhu ','Hui ','Nong ','Fu ',
);
<?php
$UTF8_TO_ASCII[0x9e] = array(
'Xi ','Kao ','Lang ','Fu ','Ze ','Shui ','Lu ','Kun ','Gan ','Geng ','Ti ','Cheng ','Tu ','Shao ','Shui ','Ya ','Lun ','Lu ','Gu ','Zuo ','Ren ','Zhun ','Bang ','Bai ','Ji ','Zhi ','Zhi ','Kun ','Leng ','Peng ','Ke ','Bing ','Chou ','Zu ','Yu ','Su ','Lue ','[?] ','Yi ','Xi ','Bian ','Ji ','Fu ','Bi ','Nuo ','Jie ','Zhong ','Zong ','Xu ','Cheng ','Dao ','Wen ','Lian ','Zi ','Yu ','Ji ','Xu ','Zhen ','Zhi ','Dao ','Jia ','Ji ','Gao ','Gao ','Gu ','Rong ','Sui ','You ','Ji ','Kang ','Mu ','Shan ','Men ','Zhi ','Ji ','Lu ','Su ','Ji ','Ying ','Wen ','Qiu ','Se ','[?] ','Yi ','Huang ','Qie ','Ji ','Sui ','Xiao ','Pu ','Jiao ','Zhuo ','Tong ','Sai ','Lu ','Sui ','Nong ','Se ','Hui ','Rang ','Nuo ','Yu ','Bin ','Ji ','Tui ','Wen ','Cheng ','Huo ','Gong ','Lu ','Biao ','[?] ','Rang ','Zhuo ','Li ','Zan ','Xue ','Wa ','Jiu ','Qiong ','Xi ','Qiong ','Kong ','Yu ','Sen ','Jing ','Yao ','Chuan ','Zhun ','Tu ','Lao ','Qie ','Zhai ','Yao ','Bian ','Bao ','Yao ','Bing ','Wa ','Zhu ','Jiao ','Qiao ','Diao ','Wu ','Gui ','Yao ','Zhi ','Chuang ','Yao ','Tiao ','Jiao ','Chuang ','Jiong ','Xiao ','Cheng ','Kou ','Cuan ','Wo ','Dan ','Ku ','Ke ','Zhui ','Xu ','Su ','Guan ','Kui ','Dou ','[?] ','Yin ','Wo ','Wa ','Ya ','Yu ','Ju ','Qiong ','Yao ','Yao ','Tiao ','Chao ','Yu ','Tian ','Diao ','Ju ','Liao ','Xi ','Wu ','Kui ','Chuang ','Zhao ','[?] ','Kuan ','Long ','Cheng ','Cui ','Piao ','Zao ','Cuan ','Qiao ','Qiong ','Dou ','Zao ','Long ','Qie ','Li ','Chu ','Shi ','Fou ','Qian ','Chu ','Hong ','Qi ','Qian ','Gong ','Shi ','Shu ','Miao ','Ju ','Zhan ','Zhu ','Ling ','Long ','Bing ','Jing ','Jing ','Zhang ','Yi ','Si ','Jun ','Hong ','Tong ','Song ','Jing ','Diao ','Yi ','Shu ','Jing ','Qu ','Jie ','Ping ','Duan ','Shao ','Zhuan ','Ceng ','Deng ','Cui ','Huai ','Jing ','Kan ','Jing ','Zhu ','Zhu ','Le ','Peng ','Yu ','Chi ','Gan ',
);
<?php
$UTF8_TO_ASCII[0x9f] = array(
'Mang ','Zhu ','Utsubo ','Du ','Ji ','Xiao ','Ba ','Suan ','Ji ','Zhen ','Zhao ','Sun ','Ya ','Zhui ','Yuan ','Hu ','Gang ','Xiao ','Cen ','Pi ','Bi ','Jian ','Yi ','Dong ','Shan ','Sheng ','Xia ','Di ','Zhu ','Na ','Chi ','Gu ','Li ','Qie ','Min ','Bao ','Tiao ','Si ','Fu ','Ce ','Ben ','Pei ','Da ','Zi ','Di ','Ling ','Ze ','Nu ','Fu ','Gou ','Fan ','Jia ','Ge ','Fan ','Shi ','Mao ','Po ','Sey ','Jian ','Qiong ','Long ','Souke ','Bian ','Luo ','Gui ','Qu ','Chi ','Yin ','Yao ','Xian ','Bi ','Qiong ','Gua ','Deng ','Jiao ','Jin ','Quan ','Sun ','Ru ','Fa ','Kuang ','Zhu ','Tong ','Ji ','Da ','Xing ','Ce ','Zhong ','Kou ','Lai ','Bi ','Shai ','Dang ','Zheng ','Ce ','Fu ','Yun ','Tu ','Pa ','Li ','Lang ','Ju ','Guan ','Jian ','Han ','Tong ','Xia ','Zhi ','Cheng ','Suan ','Shi ','Zhu ','Zuo ','Xiao ','Shao ','Ting ','Ce ','Yan ','Gao ','Kuai ','Gan ','Chou ','Kago ','Gang ','Yun ','O ','Qian ','Xiao ','Jian ','Pu ','Lai ','Zou ','Bi ','Bi ','Bi ','Ge ','Chi ','Guai ','Yu ','Jian ','Zhao ','Gu ','Chi ','Zheng ','Jing ','Sha ','Zhou ','Lu ','Bo ','Ji ','Lin ','Suan ','Jun ','Fu ','Zha ','Gu ','Kong ','Qian ','Quan ','Jun ','Chui ','Guan ','Yuan ','Ce ','Ju ','Bo ','Ze ','Qie ','Tuo ','Luo ','Dan ','Xiao ','Ruo ','Jian ','Xuan ','Bian ','Sun ','Xiang ','Xian ','Ping ','Zhen ','Sheng ','Hu ','Shi ','Zhu ','Yue ','Chun ','Lu ','Wu ','Dong ','Xiao ','Ji ','Jie ','Huang ','Xing ','Mei ','Fan ','Chui ','Zhuan ','Pian ','Feng ','Zhu ','Hong ','Qie ','Hou ','Qiu ','Miao ','Qian ','[?] ','Kui ','Sik ','Lou ','Yun ','He ','Tang ','Yue ','Chou ','Gao ','Fei ','Ruo ','Zheng ','Gou ','Nie ','Qian ','Xiao ','Cuan ','Gong ','Pang ','Du ','Li ','Bi ','Zhuo ','Chu ','Shai ','Chi ','Zhu ','Qiang ','Long ','Lan ','Jian ','Bu ','Li ','Hui ','Bi ','Di ','Cong ','Yan ','Peng ','Sen ','Zhuan ','Pai ','Piao ','Dou ','Yu ','Mie ','Zhuan ',
);
<?php
$UTF8_TO_ASCII[0xa0] = array(
'Ze ','Xi ','Guo ','Yi ','Hu ','Chan ','Kou ','Cu ','Ping ','Chou ','Ji ','Gui ','Su ','Lou ','Zha ','Lu ','Nian ','Suo ','Cuan ','Sasara ','Suo ','Le ','Duan ','Yana ','Xiao ','Bo ','Mi ','Si ','Dang ','Liao ','Dan ','Dian ','Fu ','Jian ','Min ','Kui ','Dai ','Qiao ','Deng ','Huang ','Sun ','Lao ','Zan ','Xiao ','Du ','Shi ','Zan ','[?] ','Pai ','Hata ','Pai ','Gan ','Ju ','Du ','Lu ','Yan ','Bo ','Dang ','Sai ','Ke ','Long ','Qian ','Lian ','Bo ','Zhou ','Lai ','[?] ','Lan ','Kui ','Yu ','Yue ','Hao ','Zhen ','Tai ','Ti ','Mi ','Chou ','Ji ','[?] ','Hata ','Teng ','Zhuan ','Zhou ','Fan ','Sou ','Zhou ','Kuji ','Zhuo ','Teng ','Lu ','Lu ','Jian ','Tuo ','Ying ','Yu ','Lai ','Long ','Shinshi ','Lian ','Lan ','Qian ','Yue ','Zhong ','Qu ','Lian ','Bian ','Duan ','Zuan ','Li ','Si ','Luo ','Ying ','Yue ','Zhuo ','Xu ','Mi ','Di ','Fan ','Shen ','Zhe ','Shen ','Nu ','Xie ','Lei ','Xian ','Zi ','Ni ','Cun ','[?] ','Qian ','Kume ','Bi ','Ban ','Wu ','Sha ','Kang ','Rou ','Fen ','Bi ','Cui ','[?] ','Li ','Chi ','Nukamiso ','Ro ','Ba ','Li ','Gan ','Ju ','Po ','Mo ','Cu ','Nian ','Zhou ','Li ','Su ','Tiao ','Li ','Qi ','Su ','Hong ','Tong ','Zi ','Ce ','Yue ','Zhou ','Lin ','Zhuang ','Bai ','[?] ','Fen ','Ji ','[?] ','Sukumo ','Liang ','Xian ','Fu ','Liang ','Can ','Geng ','Li ','Yue ','Lu ','Ju ','Qi ','Cui ','Bai ','Zhang ','Lin ','Zong ','Jing ','Guo ','Kouji ','San ','San ','Tang ','Bian ','Rou ','Mian ','Hou ','Xu ','Zong ','Hu ','Jian ','Zan ','Ci ','Li ','Xie ','Fu ','Ni ','Bei ','Gu ','Xiu ','Gao ','Tang ','Qiu ','Sukumo ','Cao ','Zhuang ','Tang ','Mi ','San ','Fen ','Zao ','Kang ','Jiang ','Mo ','San ','San ','Nuo ','Xi ','Liang ','Jiang ','Kuai ','Bo ','Huan ','[?] ','Zong ','Xian ','Nuo ','Tuan ','Nie ','Li ','Zuo ','Di ','Nie ','Tiao ','Lan ','Mi ','Jiao ','Jiu ','Xi ','Gong ','Zheng ','Jiu ','You ',
);
<?php
$UTF8_TO_ASCII[0xa1] = array(
'Ji ','Cha ','Zhou ','Xun ','Yue ','Hong ','Yu ','He ','Wan ','Ren ','Wen ','Wen ','Qiu ','Na ','Zi ','Tou ','Niu ','Fou ','Jie ','Shu ','Chun ','Pi ','Yin ','Sha ','Hong ','Zhi ','Ji ','Fen ','Yun ','Ren ','Dan ','Jin ','Su ','Fang ','Suo ','Cui ','Jiu ','Zha ','Kinu ','Jin ','Fu ','Zhi ','Ci ','Zi ','Chou ','Hong ','Zha ','Lei ','Xi ','Fu ','Xie ','Shen ','Bei ','Zhu ','Qu ','Ling ','Zhu ','Shao ','Gan ','Yang ','Fu ','Tuo ','Zhen ','Dai ','Zhuo ','Shi ','Zhong ','Xian ','Zu ','Jiong ','Ban ','Ju ','Mo ','Shu ','Zui ','Wata ','Jing ','Ren ','Heng ','Xie ','Jie ','Zhu ','Chou ','Gua ','Bai ','Jue ','Kuang ','Hu ','Ci ','Geng ','Geng ','Tao ','Xie ','Ku ','Jiao ','Quan ','Gai ','Luo ','Xuan ','Bing ','Xian ','Fu ','Gei ','Tong ','Rong ','Tiao ','Yin ','Lei ','Xie ','Quan ','Xu ','Lun ','Die ','Tong ','Si ','Jiang ','Xiang ','Hui ','Jue ','Zhi ','Jian ','Juan ','Chi ','Mian ','Zhen ','Lu ','Cheng ','Qiu ','Shu ','Bang ','Tong ','Xiao ','Wan ','Qin ','Geng ','Xiu ','Ti ','Xiu ','Xie ','Hong ','Xi ','Fu ','Ting ','Sui ','Dui ','Kun ','Fu ','Jing ','Hu ','Zhi ','Yan ','Jiong ','Feng ','Ji ','Sok ','Kase ','Zong ','Lin ','Duo ','Li ','Lu ','Liang ','Chou ','Quan ','Shao ','Qi ','Qi ','Zhun ','Qi ','Wan ','Qian ','Xian ','Shou ','Wei ','Qi ','Tao ','Wan ','Gang ','Wang ','Beng ','Zhui ','Cai ','Guo ','Cui ','Lun ','Liu ','Qi ','Zhan ','Bei ','Chuo ','Ling ','Mian ','Qi ','Qie ','Tan ','Zong ','Gun ','Zou ','Yi ','Zi ','Xing ','Liang ','Jin ','Fei ','Rui ','Min ','Yu ','Zong ','Fan ','Lu ','Xu ','Yingl ','Zhang ','Kasuri ','Xu ','Xiang ','Jian ','Ke ','Xian ','Ruan ','Mian ','Qi ','Duan ','Zhong ','Di ','Min ','Miao ','Yuan ','Xie ','Bao ','Si ','Qiu ','Bian ','Huan ','Geng ','Cong ','Mian ','Wei ','Fu ','Wei ','Yu ','Gou ','Miao ','Xie ','Lian ','Zong ','Bian ','Yun ','Yin ','Ti ','Gua ','Zhi ','Yun ','Cheng ','Chan ','Dai ',
);
<?php
$UTF8_TO_ASCII[0xa2] = array(
'Xia ','Yuan ','Zong ','Xu ','Nawa ','Odoshi ','Geng ','Sen ','Ying ','Jin ','Yi ','Zhui ','Ni ','Bang ','Gu ','Pan ','Zhou ','Jian ','Cuo ','Quan ','Shuang ','Yun ','Xia ','Shuai ','Xi ','Rong ','Tao ','Fu ','Yun ','Zhen ','Gao ','Ru ','Hu ','Zai ','Teng ','Xian ','Su ','Zhen ','Zong ','Tao ','Horo ','Cai ','Bi ','Feng ','Cu ','Li ','Suo ','Yin ','Xi ','Zong ','Lei ','Zhuan ','Qian ','Man ','Zhi ','Lu ','Mo ','Piao ','Lian ','Mi ','Xuan ','Zong ','Ji ','Shan ','Sui ','Fan ','Shuai ','Beng ','Yi ','Sao ','Mou ','Zhou ','Qiang ','Hun ','Sem ','Xi ','Jung ','Xiu ','Ran ','Xuan ','Hui ','Qiao ','Zeng ','Zuo ','Zhi ','Shan ','San ','Lin ','Yu ','Fan ','Liao ','Chuo ','Zun ','Jian ','Rao ','Chan ','Rui ','Xiu ','Hui ','Hua ','Zuan ','Xi ','Qiang ','Un ','Da ','Sheng ','Hui ','Xi ','Se ','Jian ','Jiang ','Huan ','Zao ','Cong ','Jie ','Jiao ','Bo ','Chan ','Yi ','Nao ','Sui ','Yi ','Shai ','Xu ','Ji ','Bin ','Qian ','Lan ','Pu ','Xun ','Zuan ','Qi ','Peng ','Li ','Mo ','Lei ','Xie ','Zuan ','Kuang ','You ','Xu ','Lei ','Xian ','Chan ','Kou ','Lu ','Chan ','Ying ','Cai ','Xiang ','Xian ','Zui ','Zuan ','Luo ','Xi ','Dao ','Lan ','Lei ','Lian ','Si ','Jiu ','Yu ','Hong ','Zhou ','Xian ','He ','Yue ','Ji ','Wan ','Kuang ','Ji ','Ren ','Wei ','Yun ','Hong ','Chun ','Pi ','Sha ','Gang ','Na ','Ren ','Zong ','Lun ','Fen ','Zhi ','Wen ','Fang ','Zhu ','Yin ','Niu ','Shu ','Xian ','Gan ','Xie ','Fu ','Lian ','Zu ','Shen ','Xi ','Zhi ','Zhong ','Zhou ','Ban ','Fu ','Zhuo ','Shao ','Yi ','Jing ','Dai ','Bang ','Rong ','Jie ','Ku ','Rao ','Die ','Heng ','Hui ','Gei ','Xuan ','Jiang ','Luo ','Jue ','Jiao ','Tong ','Geng ','Xiao ','Juan ','Xiu ','Xi ','Sui ','Tao ','Ji ','Ti ','Ji ','Xu ','Ling ','[?] ','Xu ','Qi ','Fei ','Chuo ','Zhang ','Gun ','Sheng ','Wei ','Mian ','Shou ','Beng ','Chou ','Tao ','Liu ','Quan ','Zong ','Zhan ','Wan ','Lu ',
);
<?php
$UTF8_TO_ASCII[0xa3] = array(
'Zhui ','Zi ','Ke ','Xiang ','Jian ','Mian ','Lan ','Ti ','Miao ','Qi ','Yun ','Hui ','Si ','Duo ','Duan ','Bian ','Xian ','Gou ','Zhui ','Huan ','Di ','Lu ','Bian ','Min ','Yuan ','Jin ','Fu ','Ru ','Zhen ','Feng ','Shuai ','Gao ','Chan ','Li ','Yi ','Jian ','Bin ','Piao ','Man ','Lei ','Ying ','Suo ','Mou ','Sao ','Xie ','Liao ','Shan ','Zeng ','Jiang ','Qian ','Zao ','Huan ','Jiao ','Zuan ','Fou ','Xie ','Gang ','Fou ','Que ','Fou ','Kaakeru ','Bo ','Ping ','Hou ','[?] ','Gang ','Ying ','Ying ','Qing ','Xia ','Guan ','Zun ','Tan ','Chang ','Qi ','Weng ','Ying ','Lei ','Tan ','Lu ','Guan ','Wang ','Wang ','Gang ','Wang ','Han ','[?] ','Luo ','Fu ','Mi ','Fa ','Gu ','Zhu ','Ju ','Mao ','Gu ','Min ','Gang ','Ba ','Gua ','Ti ','Juan ','Fu ','Lin ','Yan ','Zhao ','Zui ','Gua ','Zhuo ','Yu ','Zhi ','An ','Fa ','Nan ','Shu ','Si ','Pi ','Ma ','Liu ','Ba ','Fa ','Li ','Chao ','Wei ','Bi ','Ji ','Zeng ','Tong ','Liu ','Ji ','Juan ','Mi ','Zhao ','Luo ','Pi ','Ji ','Ji ','Luan ','Yang ','Mie ','Qiang ','Ta ','Mei ','Yang ','You ','You ','Fen ','Ba ','Gao ','Yang ','Gu ','Qiang ','Zang ','Gao ','Ling ','Yi ','Zhu ','Di ','Xiu ','Qian ','Yi ','Xian ','Rong ','Qun ','Qun ','Qian ','Huan ','Zui ','Xian ','Yi ','Yashinau ','Qiang ','Xian ','Yu ','Geng ','Jie ','Tang ','Yuan ','Xi ','Fan ','Shan ','Fen ','Shan ','Lian ','Lei ','Geng ','Nou ','Qiang ','Chan ','Yu ','Gong ','Yi ','Chong ','Weng ','Fen ','Hong ','Chi ','Chi ','Cui ','Fu ','Xia ','Pen ','Yi ','La ','Yi ','Pi ','Ling ','Liu ','Zhi ','Qu ','Xi ','Xie ','Xiang ','Xi ','Xi ','Qi ','Qiao ','Hui ','Hui ','Xiao ','Se ','Hong ','Jiang ','Di ','Cui ','Fei ','Tao ','Sha ','Chi ','Zhu ','Jian ','Xuan ','Shi ','Pian ','Zong ','Wan ','Hui ','Hou ','He ','He ','Han ','Ao ','Piao ','Yi ','Lian ','Qu ','[?] ','Lin ','Pen ','Qiao ','Ao ','Fan ','Yi ','Hui ','Xuan ','Dao ',
);
<?php
$UTF8_TO_ASCII[0xa4] = array(
'Yao ','Lao ','[?] ','Kao ','Mao ','Zhe ','Qi ','Gou ','Gou ','Gou ','Die ','Die ','Er ','Shua ','Ruan ','Er ','Nai ','Zhuan ','Lei ','Ting ','Zi ','Geng ','Chao ','Hao ','Yun ','Pa ','Pi ','Chi ','Si ','Chu ','Jia ','Ju ','He ','Chu ','Lao ','Lun ','Ji ','Tang ','Ou ','Lou ','Nou ','Gou ','Pang ','Ze ','Lou ','Ji ','Lao ','Huo ','You ','Mo ','Huai ','Er ','Zhe ','Ting ','Ye ','Da ','Song ','Qin ','Yun ','Chi ','Dan ','Dan ','Hong ','Geng ','Zhi ','[?] ','Nie ','Dan ','Zhen ','Che ','Ling ','Zheng ','You ','Wa ','Liao ','Long ','Zhi ','Ning ','Tiao ','Er ','Ya ','Die ','Gua ','[?] ','Lian ','Hao ','Sheng ','Lie ','Pin ','Jing ','Ju ','Bi ','Di ','Guo ','Wen ','Xu ','Ping ','Cong ','Shikato ','[?] ','Ting ','Yu ','Cong ','Kui ','Tsuraneru ','Kui ','Cong ','Lian ','Weng ','Kui ','Lian ','Lian ','Cong ','Ao ','Sheng ','Song ','Ting ','Kui ','Nie ','Zhi ','Dan ','Ning ','Qie ','Ji ','Ting ','Ting ','Long ','Yu ','Yu ','Zhao ','Si ','Su ','Yi ','Su ','Si ','Zhao ','Zhao ','Rou ','Yi ','Le ','Ji ','Qiu ','Ken ','Cao ','Ge ','Di ','Huan ','Huang ','Yi ','Ren ','Xiao ','Ru ','Zhou ','Yuan ','Du ','Gang ','Rong ','Gan ','Cha ','Wo ','Chang ','Gu ','Zhi ','Han ','Fu ','Fei ','Fen ','Pei ','Pang ','Jian ','Fang ','Zhun ','You ','Na ','Hang ','Ken ','Ran ','Gong ','Yu ','Wen ','Yao ','Jin ','Pi ','Qian ','Xi ','Xi ','Fei ','Ken ','Jing ','Tai ','Shen ','Zhong ','Zhang ','Xie ','Shen ','Wei ','Zhou ','Die ','Dan ','Fei ','Ba ','Bo ','Qu ','Tian ','Bei ','Gua ','Tai ','Zi ','Ku ','Zhi ','Ni ','Ping ','Zi ','Fu ','Pang ','Zhen ','Xian ','Zuo ','Pei ','Jia ','Sheng ','Zhi ','Bao ','Mu ','Qu ','Hu ','Ke ','Yi ','Yin ','Xu ','Yang ','Long ','Dong ','Ka ','Lu ','Jing ','Nu ','Yan ','Pang ','Kua ','Yi ','Guang ','Gai ','Ge ','Dong ','Zhi ','Xiao ','Xiong ','Xiong ','Er ','E ','Xing ','Pian ','Neng ','Zi ','Gui ',
);
<?php
$UTF8_TO_ASCII[0xac] = array(
'Cheng ','Tiao ','Zhi ','Cui ','Mei ','Xie ','Cui ','Xie ','Mo ','Mai ','Ji ','Obiyaakasu ','[?] ','Kuai ','Sa ','Zang ','Qi ','Nao ','Mi ','Nong ','Luan ','Wan ','Bo ','Wen ','Guan ','Qiu ','Jiao ','Jing ','Rou ','Heng ','Cuo ','Lie ','Shan ','Ting ','Mei ','Chun ','Shen ','Xie ','De ','Zui ','Cu ','Xiu ','Xin ','Tuo ','Pao ','Cheng ','Nei ','Fu ','Dou ','Tuo ','Niao ','Noy ','Pi ','Gu ','Gua ','Li ','Lian ','Zhang ','Cui ','Jie ','Liang ','Zhou ','Pi ','Biao ','Lun ','Pian ','Guo ','Kui ','Chui ','Dan ','Tian ','Nei ','Jing ','Jie ','La ','Yi ','An ','Ren ','Shen ','Chuo ','Fu ','Fu ','Ju ','Fei ','Qiang ','Wan ','Dong ','Pi ','Guo ','Zong ','Ding ','Wu ','Mei ','Ruan ','Zhuan ','Zhi ','Cou ','Gua ','Ou ','Di ','An ','Xing ','Nao ','Yu ','Chuan ','Nan ','Yun ','Zhong ','Rou ','E ','Sai ','Tu ','Yao ','Jian ','Wei ','Jiao ','Yu ','Jia ','Duan ','Bi ','Chang ','Fu ','Xian ','Ni ','Mian ','Wa ','Teng ','Tui ','Bang ','Qian ','Lu ','Wa ','Sou ','Tang ','Su ','Zhui ','Ge ','Yi ','Bo ','Liao ','Ji ','Pi ','Xie ','Gao ','Lu ','Bin ','Ou ','Chang ','Lu ','Guo ','Pang ','Chuai ','Piao ','Jiang ','Fu ','Tang ','Mo ','Xi ','Zhuan ','Lu ','Jiao ','Ying ','Lu ','Zhi ','Tara ','Chun ','Lian ','Tong ','Peng ','Ni ','Zha ','Liao ','Cui ','Gui ','Xiao ','Teng ','Fan ','Zhi ','Jiao ','Shan ','Wu ','Cui ','Run ','Xiang ','Sui ','Fen ','Ying ','Tan ','Zhua ','Dan ','Kuai ','Nong ','Tun ','Lian ','Bi ','Yong ','Jue ','Chu ','Yi ','Juan ','La ','Lian ','Sao ','Tun ','Gu ','Qi ','Cui ','Bin ','Xun ','Ru ','Huo ','Zang ','Xian ','Biao ','Xing ','Kuan ','La ','Yan ','Lu ','Huo ','Zang ','Luo ','Qu ','Zang ','Luan ','Ni ','Zang ','Chen ','Qian ','Wo ','Guang ','Zang ','Lin ','Guang ','Zi ','Jiao ','Nie ','Chou ','Ji ','Gao ','Chou ','Mian ','Nie ','Zhi ','Zhi ','Ge ','Jian ','Die ','Zhi ','Xiu ','Tai ','Zhen ','Jiu ','Xian ','Yu ','Cha ',
);
<?php
$UTF8_TO_ASCII[0xad] = array(
'Yao ','Yu ','Chong ','Xi ','Xi ','Jiu ','Yu ','Yu ','Xing ','Ju ','Jiu ','Xin ','She ','She ','Yadoru ','Jiu ','Shi ','Tan ','Shu ','Shi ','Tian ','Dan ','Pu ','Pu ','Guan ','Hua ','Tan ','Chuan ','Shun ','Xia ','Wu ','Zhou ','Dao ','Gang ','Shan ','Yi ','[?] ','Pa ','Tai ','Fan ','Ban ','Chuan ','Hang ','Fang ','Ban ','Que ','Hesaki ','Zhong ','Jian ','Cang ','Ling ','Zhu ','Ze ','Duo ','Bo ','Xian ','Ge ','Chuan ','Jia ','Lu ','Hong ','Pang ','Xi ','[?] ','Fu ','Zao ','Feng ','Li ','Shao ','Yu ','Lang ','Ting ','[?] ','Wei ','Bo ','Meng ','Nian ','Ju ','Huang ','Shou ','Zong ','Bian ','Mao ','Die ','[?] ','Bang ','Cha ','Yi ','Sao ','Cang ','Cao ','Lou ','Dai ','Sori ','Yao ','Tong ','Yofune ','Dang ','Tan ','Lu ','Yi ','Jie ','Jian ','Huo ','Meng ','Qi ','Lu ','Lu ','Chan ','Shuang ','Gen ','Liang ','Jian ','Jian ','Se ','Yan ','Fu ','Ping ','Yan ','Yan ','Cao ','Cao ','Yi ','Le ','Ting ','Qiu ','Ai ','Nai ','Tiao ','Jiao ','Jie ','Peng ','Wan ','Yi ','Chai ','Mian ','Mie ','Gan ','Qian ','Yu ','Yu ','Shuo ','Qiong ','Tu ','Xia ','Qi ','Mang ','Zi ','Hui ','Sui ','Zhi ','Xiang ','Bi ','Fu ','Tun ','Wei ','Wu ','Zhi ','Qi ','Shan ','Wen ','Qian ','Ren ','Fou ','Kou ','Jie ','Lu ','Xu ','Ji ','Qin ','Qi ','Yuan ','Fen ','Ba ','Rui ','Xin ','Ji ','Hua ','Hua ','Fang ','Wu ','Jue ','Gou ','Zhi ','Yun ','Qin ','Ao ','Chu ','Mao ','Ya ','Fei ','Reng ','Hang ','Cong ','Yin ','You ','Bian ','Yi ','Susa ','Wei ','Li ','Pi ','E ','Xian ','Chang ','Cang ','Meng ','Su ','Yi ','Yuan ','Ran ','Ling ','Tai ','Tiao ','Di ','Miao ','Qiong ','Li ','Yong ','Ke ','Mu ','Pei ','Bao ','Gou ','Min ','Yi ','Yi ','Ju ','Pi ','Ruo ','Ku ','Zhu ','Ni ','Bo ','Bing ','Shan ','Qiu ','Yao ','Xian ','Ben ','Hong ','Ying ','Zha ','Dong ','Ju ','Die ','Nie ','Gan ','Hu ','Ping ','Mei ','Fu ','Sheng ','Gu ','Bi ','Wei ',
);
<?php
$UTF8_TO_ASCII[0xae] = array(
'Fu ','Zhuo ','Mao ','Fan ','Qie ','Mao ','Mao ','Ba ','Zi ','Mo ','Zi ','Di ','Chi ','Ji ','Jing ','Long ','[?] ','Niao ','[?] ','Xue ','Ying ','Qiong ','Ge ','Ming ','Li ','Rong ','Yin ','Gen ','Qian ','Chai ','Chen ','Yu ','Xiu ','Zi ','Lie ','Wu ','Ji ','Kui ','Ce ','Chong ','Ci ','Gou ','Guang ','Mang ','Chi ','Jiao ','Jiao ','Fu ','Yu ','Zhu ','Zi ','Jiang ','Hui ','Yin ','Cha ','Fa ','Rong ','Ru ','Chong ','Mang ','Tong ','Zhong ','[?] ','Zhu ','Xun ','Huan ','Kua ','Quan ','Gai ','Da ','Jing ','Xing ','Quan ','Cao ','Jing ','Er ','An ','Shou ','Chi ','Ren ','Jian ','Ti ','Huang ','Ping ','Li ','Jin ','Lao ','Shu ','Zhuang ','Da ','Jia ','Rao ','Bi ','Ze ','Qiao ','Hui ','Qi ','Dang ','[?] ','Rong ','Hun ','Ying ','Luo ','Ying ','Xun ','Jin ','Sun ','Yin ','Mai ','Hong ','Zhou ','Yao ','Du ','Wei ','Chu ','Dou ','Fu ','Ren ','Yin ','He ','Bi ','Bu ','Yun ','Di ','Tu ','Sui ','Sui ','Cheng ','Chen ','Wu ','Bie ','Xi ','Geng ','Li ','Fu ','Zhu ','Mo ','Li ','Zhuang ','Ji ','Duo ','Qiu ','Sha ','Suo ','Chen ','Feng ','Ju ','Mei ','Meng ','Xing ','Jing ','Che ','Xin ','Jun ','Yan ','Ting ','Diao ','Cuo ','Wan ','Han ','You ','Cuo ','Jia ','Wang ','You ','Niu ','Shao ','Xian ','Lang ','Fu ','E ','Mo ','Wen ','Jie ','Nan ','Mu ','Kan ','Lai ','Lian ','Shi ','Wo ','Usagi ','Lian ','Huo ','You ','Ying ','Ying ','Nuc ','Chun ','Mang ','Mang ','Ci ','Wan ','Jing ','Di ','Qu ','Dong ','Jian ','Zou ','Gu ','La ','Lu ','Ju ','Wei ','Jun ','Nie ','Kun ','He ','Pu ','Zi ','Gao ','Guo ','Fu ','Lun ','Chang ','Chou ','Song ','Chui ','Zhan ','Men ','Cai ','Ba ','Li ','Tu ','Bo ','Han ','Bao ','Qin ','Juan ','Xi ','Qin ','Di ','Jie ','Pu ','Dang ','Jin ','Zhao ','Tai ','Geng ','Hua ','Gu ','Ling ','Fei ','Jin ','An ','Wang ','Beng ','Zhou ','Yan ','Ju ','Jian ','Lin ','Tan ','Shu ','Tian ','Dao ',
);
<?php
$UTF8_TO_ASCII[0xaf] = array(
'Hu ','Qi ','He ','Cui ','Tao ','Chun ','Bei ','Chang ','Huan ','Fei ','Lai ','Qi ','Meng ','Ping ','Wei ','Dan ','Sha ','Huan ','Yan ','Yi ','Tiao ','Qi ','Wan ','Ce ','Nai ','Kutabireru ','Tuo ','Jiu ','Tie ','Luo ','[?] ','[?] ','Meng ','[?] ','Yaji ','[?] ','Ying ','Ying ','Ying ','Xiao ','Sa ','Qiu ','Ke ','Xiang ','Wan ','Yu ','Yu ','Fu ','Lian ','Xuan ','Yuan ','Nan ','Ze ','Wo ','Chun ','Xiao ','Yu ','Pian ','Mao ','An ','E ','Luo ','Ying ','Huo ','Gua ','Jiang ','Mian ','Zuo ','Zuo ','Ju ','Bao ','Rou ','Xi ','Xie ','An ','Qu ','Jian ','Fu ','Lu ','Jing ','Pen ','Feng ','Hong ','Hong ','Hou ','Yan ','Tu ','Zhu ','Zi ','Xiang ','Shen ','Ge ','Jie ','Jing ','Mi ','Huang ','Shen ','Pu ','Gai ','Dong ','Zhou ','Qian ','Wei ','Bo ','Wei ','Pa ','Ji ','Hu ','Zang ','Jia ','Duan ','Yao ','Jun ','Cong ','Quan ','Wei ','Xian ','Kui ','Ting ','Hun ','Xi ','Shi ','Qi ','Lan ','Zong ','Yao ','Yuan ','Mei ','Yun ','Shu ','Di ','Zhuan ','Guan ','Sukumo ','Xue ','Chan ','Kai ','Kui ','[?] ','Jiang ','Lou ','Wei ','Pai ','[?] ','Sou ','Yin ','Shi ','Chun ','Shi ','Yun ','Zhen ','Lang ','Nu ','Meng ','He ','Que ','Suan ','Yuan ','Li ','Ju ','Xi ','Pang ','Chu ','Xu ','Tu ','Liu ','Wo ','Zhen ','Qian ','Zu ','Po ','Cuo ','Yuan ','Chu ','Yu ','Kuai ','Pan ','Pu ','Pu ','Na ','Shuo ','Xi ','Fen ','Yun ','Zheng ','Jian ','Ji ','Ruo ','Cang ','En ','Mi ','Hao ','Sun ','Zhen ','Ming ','Sou ','Xu ','Liu ','Xi ','Gu ','Lang ','Rong ','Weng ','Gai ','Cuo ','Shi ','Tang ','Luo ','Ru ','Suo ','Xian ','Bei ','Yao ','Gui ','Bi ','Zong ','Gun ','Za ','Xiu ','Ce ','Hai ','Lan ','[?] ','Ji ','Li ','Can ','Lang ','Yu ','[?] ','Ying ','Mo ','Diao ','Tiao ','Mao ','Tong ','Zhu ','Peng ','An ','Lian ','Cong ','Xi ','Ping ','Qiu ','Jin ','Chun ','Jie ','Wei ','Tui ','Cao ','Yu ','Yi ','Ji ','Liao ','Bi ','Lu ','Su ',
);
<?php
$UTF8_TO_ASCII[0xb0] = array(
'Bu ','Zhang ','Luo ','Jiang ','Man ','Yan ','Ling ','Ji ','Piao ','Gun ','Han ','Di ','Su ','Lu ','She ','Shang ','Di ','Mie ','Xun ','Man ','Bo ','Di ','Cuo ','Zhe ','Sen ','Xuan ','Wei ','Hu ','Ao ','Mi ','Lou ','Cu ','Zhong ','Cai ','Po ','Jiang ','Mi ','Cong ','Niao ','Hui ','Jun ','Yin ','Jian ','Yan ','Shu ','Yin ','Kui ','Chen ','Hu ','Sha ','Kou ','Qian ','Ma ','Zang ','Sonoko ','Qiang ','Dou ','Lian ','Lin ','Kou ','Ai ','Bi ','Li ','Wei ','Ji ','Xun ','Sheng ','Fan ','Meng ','Ou ','Chan ','Dian ','Xun ','Jiao ','Rui ','Rui ','Lei ','Yu ','Qiao ','Chu ','Hua ','Jian ','Mai ','Yun ','Bao ','You ','Qu ','Lu ','Rao ','Hui ','E ','Teng ','Fei ','Jue ','Zui ','Fa ','Ru ','Fen ','Kui ','Shun ','Rui ','Ya ','Xu ','Fu ','Jue ','Dang ','Wu ','Tong ','Si ','Xiao ','Xi ','Long ','Yun ','[?] ','Qi ','Jian ','Yun ','Sun ','Ling ','Yu ','Xia ','Yong ','Ji ','Hong ','Si ','Nong ','Lei ','Xuan ','Yun ','Yu ','Xi ','Hao ','Bo ','Hao ','Ai ','Wei ','Hui ','Wei ','Ji ','Ci ','Xiang ','Luan ','Mie ','Yi ','Leng ','Jiang ','Can ','Shen ','Qiang ','Lian ','Ke ','Yuan ','Da ','Ti ','Tang ','Xie ','Bi ','Zhan ','Sun ','Lian ','Fan ','Ding ','Jie ','Gu ','Xie ','Shu ','Jian ','Kao ','Hong ','Sa ','Xin ','Xun ','Yao ','Hie ','Sou ','Shu ','Xun ','Dui ','Pin ','Wei ','Neng ','Chou ','Mai ','Ru ','Piao ','Tai ','Qi ','Zao ','Chen ','Zhen ','Er ','Ni ','Ying ','Gao ','Cong ','Xiao ','Qi ','Fa ','Jian ','Xu ','Kui ','Jie ','Bian ','Diao ','Mi ','Lan ','Jin ','Cang ','Miao ','Qiong ','Qie ','Xian ','[?] ','Ou ','Xian ','Su ','Lu ','Yi ','Xu ','Xie ','Li ','Yi ','La ','Lei ','Xiao ','Di ','Zhi ','Bei ','Teng ','Yao ','Mo ','Huan ','Piao ','Fan ','Sou ','Tan ','Tui ','Qiong ','Qiao ','Wei ','Liu ','Hui ','[?] ','Gao ','Yun ','[?] ','Li ','Shu ','Chu ','Ai ','Lin ','Zao ','Xuan ','Chen ','Lai ','Huo ',
);
<?php
$UTF8_TO_ASCII[0xb1] = array(
'Tuo ','Wu ','Rui ','Rui ','Qi ','Heng ','Lu ','Su ','Tui ','Mang ','Yun ','Pin ','Yu ','Xun ','Ji ','Jiong ','Xian ','Mo ','Hagi ','Su ','Jiong ','[?] ','Nie ','Bo ','Rang ','Yi ','Xian ','Yu ','Ju ','Lian ','Lian ','Yin ','Qiang ','Ying ','Long ','Tong ','Wei ','Yue ','Ling ','Qu ','Yao ','Fan ','Mi ','Lan ','Kui ','Lan ','Ji ','Dang ','Katsura ','Lei ','Lei ','Hua ','Feng ','Zhi ','Wei ','Kui ','Zhan ','Huai ','Li ','Ji ','Mi ','Lei ','Huai ','Luo ','Ji ','Kui ','Lu ','Jian ','San ','[?] ','Lei ','Quan ','Xiao ','Yi ','Luan ','Men ','Bie ','Hu ','Hu ','Lu ','Nue ','Lu ','Si ','Xiao ','Qian ','Chu ','Hu ','Xu ','Cuo ','Fu ','Xu ','Xu ','Lu ','Hu ','Yu ','Hao ','Jiao ','Ju ','Guo ','Bao ','Yan ','Zhan ','Zhan ','Kui ','Ban ','Xi ','Shu ','Chong ','Qiu ','Diao ','Ji ','Qiu ','Cheng ','Shi ','[?] ','Di ','Zhe ','She ','Yu ','Gan ','Zi ','Hong ','Hui ','Meng ','Ge ','Sui ','Xia ','Chai ','Shi ','Yi ','Ma ','Xiang ','Fang ','E ','Pa ','Chi ','Qian ','Wen ','Wen ','Rui ','Bang ','Bi ','Yue ','Yue ','Jun ','Qi ','Ran ','Yin ','Qi ','Tian ','Yuan ','Jue ','Hui ','Qin ','Qi ','Zhong ','Ya ','Ci ','Mu ','Wang ','Fen ','Fen ','Hang ','Gong ','Zao ','Fu ','Ran ','Jie ','Fu ','Chi ','Dou ','Piao ','Xian ','Ni ','Te ','Qiu ','You ','Zha ','Ping ','Chi ','You ','He ','Han ','Ju ','Li ','Fu ','Ran ','Zha ','Gou ','Pi ','Bo ','Xian ','Zhu ','Diao ','Bie ','Bing ','Gu ','Ran ','Qu ','She ','Tie ','Ling ','Gu ','Dan ','Gu ','Ying ','Li ','Cheng ','Qu ','Mou ','Ge ','Ci ','Hui ','Hui ','Mang ','Fu ','Yang ','Wa ','Lie ','Zhu ','Yi ','Xian ','Kuo ','Jiao ','Li ','Yi ','Ping ','Ji ','Ha ','She ','Yi ','Wang ','Mo ','Qiong ','Qie ','Gui ','Gong ','Zhi ','Man ','Ebi ','Zhi ','Jia ','Rao ','Si ','Qi ','Xing ','Lie ','Qiu ','Shao ','Yong ','Jia ','Shui ','Che ','Bai ','E ','Han ',
);
<?php
$UTF8_TO_ASCII[0xb2] = array(
'Shu ','Xuan ','Feng ','Shen ','Zhen ','Fu ','Xian ','Zhe ','Wu ','Fu ','Li ','Lang ','Bi ','Chu ','Yuan ','You ','Jie ','Dan ','Yan ','Ting ','Dian ','Shui ','Hui ','Gua ','Zhi ','Song ','Fei ','Ju ','Mi ','Qi ','Qi ','Yu ','Jun ','Zha ','Meng ','Qiang ','Si ','Xi ','Lun ','Li ','Die ','Tiao ','Tao ','Kun ','Gan ','Han ','Yu ','Bang ','Fei ','Pi ','Wei ','Dun ','Yi ','Yuan ','Su ','Quan ','Qian ','Rui ','Ni ','Qing ','Wei ','Liang ','Guo ','Wan ','Dong ','E ','Ban ','Di ','Wang ','Can ','Yang ','Ying ','Guo ','Chan ','[?] ','La ','Ke ','Ji ','He ','Ting ','Mai ','Xu ','Mian ','Yu ','Jie ','Shi ','Xuan ','Huang ','Yan ','Bian ','Rou ','Wei ','Fu ','Yuan ','Mei ','Wei ','Fu ','Ruan ','Xie ','You ','Qiu ','Mao ','Xia ','Ying ','Shi ','Chong ','Tang ','Zhu ','Zong ','Ti ','Fu ','Yuan ','Hui ','Meng ','La ','Du ','Hu ','Qiu ','Die ','Li ','Gua ','Yun ','Ju ','Nan ','Lou ','Qun ','Rong ','Ying ','Jiang ','[?] ','Lang ','Pang ','Si ','Xi ','Ci ','Xi ','Yuan ','Weng ','Lian ','Sou ','Ban ','Rong ','Rong ','Ji ','Wu ','Qiu ','Han ','Qin ','Yi ','Bi ','Hua ','Tang ','Yi ','Du ','Nai ','He ','Hu ','Hui ','Ma ','Ming ','Yi ','Wen ','Ying ','Teng ','Yu ','Cang ','So ','Ebi ','Man ','[?] ','Shang ','Zhe ','Cao ','Chi ','Di ','Ao ','Lu ','Wei ','Zhi ','Tang ','Chen ','Piao ','Qu ','Pi ','Yu ','Jian ','Luo ','Lou ','Qin ','Zhong ','Yin ','Jiang ','Shuai ','Wen ','Jiao ','Wan ','Zhi ','Zhe ','Ma ','Ma ','Guo ','Liu ','Mao ','Xi ','Cong ','Li ','Man ','Xiao ','Kamakiri ','Zhang ','Mang ','Xiang ','Mo ','Zui ','Si ','Qiu ','Te ','Zhi ','Peng ','Peng ','Jiao ','Qu ','Bie ','Liao ','Pan ','Gui ','Xi ','Ji ','Zhuan ','Huang ','Fei ','Lao ','Jue ','Jue ','Hui ','Yin ','Chan ','Jiao ','Shan ','Rao ','Xiao ','Mou ','Chong ','Xun ','Si ','[?] ','Cheng ','Dang ','Li ','Xie ','Shan ','Yi ','Jing ','Da ','Chan ','Qi ',
);
<?php
$UTF8_TO_ASCII[0xb3] = array(
'Ci ','Xiang ','She ','Luo ','Qin ','Ying ','Chai ','Li ','Ze ','Xuan ','Lian ','Zhu ','Ze ','Xie ','Mang ','Xie ','Qi ','Rong ','Jian ','Meng ','Hao ','Ruan ','Huo ','Zhuo ','Jie ','Bin ','He ','Mie ','Fan ','Lei ','Jie ','La ','Mi ','Li ','Chun ','Li ','Qiu ','Nie ','Lu ','Du ','Xiao ','Zhu ','Long ','Li ','Long ','Feng ','Ye ','Beng ','Shang ','Gu ','Juan ','Ying ','[?] ','Xi ','Can ','Qu ','Quan ','Du ','Can ','Man ','Jue ','Jie ','Zhu ','Zha ','Xie ','Huang ','Niu ','Pei ','Nu ','Xin ','Zhong ','Mo ','Er ','Ke ','Mie ','Xi ','Xing ','Yan ','Kan ','Yuan ','[?] ','Ling ','Xuan ','Shu ','Xian ','Tong ','Long ','Jie ','Xian ','Ya ','Hu ','Wei ','Dao ','Chong ','Wei ','Dao ','Zhun ','Heng ','Qu ','Yi ','Yi ','Bu ','Gan ','Yu ','Biao ','Cha ','Yi ','Shan ','Chen ','Fu ','Gun ','Fen ','Shuai ','Jie ','Na ','Zhong ','Dan ','Ri ','Zhong ','Zhong ','Xie ','Qi ','Xie ','Ran ','Zhi ','Ren ','Qin ','Jin ','Jun ','Yuan ','Mei ','Chai ','Ao ','Niao ','Hui ','Ran ','Jia ','Tuo ','Ling ','Dai ','Bao ','Pao ','Yao ','Zuo ','Bi ','Shao ','Tan ','Ju ','He ','Shu ','Xiu ','Zhen ','Yi ','Pa ','Bo ','Di ','Wa ','Fu ','Gun ','Zhi ','Zhi ','Ran ','Pan ','Yi ','Mao ','Tuo ','Na ','Kou ','Xian ','Chan ','Qu ','Bei ','Gun ','Xi ','Ne ','Bo ','Horo ','Fu ','Yi ','Chi ','Ku ','Ren ','Jiang ','Jia ','Cun ','Mo ','Jie ','Er ','Luo ','Ru ','Zhu ','Gui ','Yin ','Cai ','Lie ','Kamishimo ','Yuki ','Zhuang ','Dang ','[?] ','Kun ','Ken ','Niao ','Shu ','Jia ','Kun ','Cheng ','Li ','Juan ','Shen ','Pou ','Ge ','Yi ','Yu ','Zhen ','Liu ','Qiu ','Qun ','Ji ','Yi ','Bu ','Zhuang ','Shui ','Sha ','Qun ','Li ','Lian ','Lian ','Ku ','Jian ','Fou ','Chan ','Bi ','Gun ','Tao ','Yuan ','Ling ','Chi ','Chang ','Chou ','Duo ','Biao ','Liang ','Chang ','Pei ','Pei ','Fei ','Yuan ','Luo ','Guo ','Yan ','Du ','Xi ','Zhi ','Ju ','Qi ',
);
<?php
$UTF8_TO_ASCII[0xb4] = array(
'Ji ','Zhi ','Gua ','Ken ','Che ','Ti ','Ti ','Fu ','Chong ','Xie ','Bian ','Die ','Kun ','Duan ','Xiu ','Xiu ','He ','Yuan ','Bao ','Bao ','Fu ','Yu ','Tuan ','Yan ','Hui ','Bei ','Chu ','Lu ','Ena ','Hitoe ','Yun ','Da ','Gou ','Da ','Huai ','Rong ','Yuan ','Ru ','Nai ','Jiong ','Suo ','Ban ','Tun ','Chi ','Sang ','Niao ','Ying ','Jie ','Qian ','Huai ','Ku ','Lian ','Bao ','Li ','Zhe ','Shi ','Lu ','Yi ','Die ','Xie ','Xian ','Wei ','Biao ','Cao ','Ji ','Jiang ','Sen ','Bao ','Xiang ','Chihaya ','Pu ','Jian ','Zhuan ','Jian ','Zui ','Ji ','Dan ','Za ','Fan ','Bo ','Xiang ','Xin ','Bie ','Rao ','Man ','Lan ','Ao ','Duo ','Gui ','Cao ','Sui ','Nong ','Chan ','Lian ','Bi ','Jin ','Dang ','Shu ','Tan ','Bi ','Lan ','Pu ','Ru ','Zhi ','[?] ','Shu ','Wa ','Shi ','Bai ','Xie ','Bo ','Chen ','Lai ','Long ','Xi ','Xian ','Lan ','Zhe ','Dai ','Tasuki ','Zan ','Shi ','Jian ','Pan ','Yi ','Ran ','Ya ','Xi ','Xi ','Yao ','Feng ','Tan ','[?] ','Biao ','Fu ','Ba ','He ','Ji ','Ji ','Jian ','Guan ','Bian ','Yan ','Gui ','Jue ','Pian ','Mao ','Mi ','Mi ','Mie ','Shi ','Si ','Zhan ','Luo ','Jue ','Mi ','Tiao ','Lian ','Yao ','Zhi ','Jun ','Xi ','Shan ','Wei ','Xi ','Tian ','Yu ','Lan ','E ','Du ','Qin ','Pang ','Ji ','Ming ','Ying ','Gou ','Qu ','Zhan ','Jin ','Guan ','Deng ','Jian ','Luo ','Qu ','Jian ','Wei ','Jue ','Qu ','Luo ','Lan ','Shen ','Di ','Guan ','Jian ','Guan ','Yan ','Gui ','Mi ','Shi ','Zhan ','Lan ','Jue ','Ji ','Xi ','Di ','Tian ','Yu ','Gou ','Jin ','Qu ','Jiao ','Jiu ','Jin ','Cu ','Jue ','Zhi ','Chao ','Ji ','Gu ','Dan ','Zui ','Di ','Shang ','Hua ','Quan ','Ge ','Chi ','Jie ','Gui ','Gong ','Hong ','Jie ','Hun ','Qiu ','Xing ','Su ','Ni ','Ji ','Lu ','Zhi ','Zha ','Bi ','Xing ','Hu ','Shang ','Gong ','Zhi ','Xue ','Chu ','Xi ','Yi ','Lu ','Jue ','Xi ','Yan ','Xi ',
);
<?php
$UTF8_TO_ASCII[0xb5] = array(
'Yan ','Yan ','Ding ','Fu ','Qiu ','Qiu ','Jiao ','Hong ','Ji ','Fan ','Xun ','Diao ','Hong ','Cha ','Tao ','Xu ','Jie ','Yi ','Ren ','Xun ','Yin ','Shan ','Qi ','Tuo ','Ji ','Xun ','Yin ','E ','Fen ','Ya ','Yao ','Song ','Shen ','Yin ','Xin ','Jue ','Xiao ','Ne ','Chen ','You ','Zhi ','Xiong ','Fang ','Xin ','Chao ','She ','Xian ','Sha ','Tun ','Xu ','Yi ','Yi ','Su ','Chi ','He ','Shen ','He ','Xu ','Zhen ','Zhu ','Zheng ','Gou ','Zi ','Zi ','Zhan ','Gu ','Fu ','Quan ','Die ','Ling ','Di ','Yang ','Li ','Nao ','Pan ','Zhou ','Gan ','Yi ','Ju ','Ao ','Zha ','Tuo ','Yi ','Qu ','Zhao ','Ping ','Bi ','Xiong ','Qu ','Ba ','Da ','Zu ','Tao ','Zhu ','Ci ','Zhe ','Yong ','Xu ','Xun ','Yi ','Huang ','He ','Shi ','Cha ','Jiao ','Shi ','Hen ','Cha ','Gou ','Gui ','Quan ','Hui ','Jie ','Hua ','Gai ','Xiang ','Wei ','Shen ','Chou ','Tong ','Mi ','Zhan ','Ming ','E ','Hui ','Yan ','Xiong ','Gua ','Er ','Beng ','Tiao ','Chi ','Lei ','Zhu ','Kuang ','Kua ','Wu ','Yu ','Teng ','Ji ','Zhi ','Ren ','Su ','Lang ','E ','Kuang ','E ','Shi ','Ting ','Dan ','Bo ','Chan ','You ','Heng ','Qiao ','Qin ','Shua ','An ','Yu ','Xiao ','Cheng ','Jie ','Xian ','Wu ','Wu ','Gao ','Song ','Pu ','Hui ','Jing ','Shuo ','Zhen ','Shuo ','Du ','Yasashi ','Chang ','Shui ','Jie ','Ke ','Qu ','Cong ','Xiao ','Sui ','Wang ','Xuan ','Fei ','Chi ','Ta ','Yi ','Na ','Yin ','Diao ','Pi ','Chuo ','Chan ','Chen ','Zhun ','Ji ','Qi ','Tan ','Zhui ','Wei ','Ju ','Qing ','Jian ','Zheng ','Ze ','Zou ','Qian ','Zhuo ','Liang ','Jian ','Zhu ','Hao ','Lun ','Shen ','Biao ','Huai ','Pian ','Yu ','Die ','Xu ','Pian ','Shi ','Xuan ','Shi ','Hun ','Hua ','E ','Zhong ','Di ','Xie ','Fu ','Pu ','Ting ','Jian ','Qi ','Yu ','Zi ','Chuan ','Xi ','Hui ','Yin ','An ','Xian ','Nan ','Chen ','Feng ','Zhu ','Yang ','Yan ','Heng ','Xuan ','Ge ','Nuo ','Qi ',
);
<?php
$UTF8_TO_ASCII[0xb6] = array(
'Mou ','Ye ','Wei ','[?] ','Teng ','Zou ','Shan ','Jian ','Bo ','Ku ','Huang ','Huo ','Ge ','Ying ','Mi ','Xiao ','Mi ','Xi ','Qiang ','Chen ','Nue ','Ti ','Su ','Bang ','Chi ','Qian ','Shi ','Jiang ','Yuan ','Xie ','Xue ','Tao ','Yao ','Yao ','[?] ','Yu ','Biao ','Cong ','Qing ','Li ','Mo ','Mo ','Shang ','Zhe ','Miu ','Jian ','Ze ','Jie ','Lian ','Lou ','Can ','Ou ','Guan ','Xi ','Zhuo ','Ao ','Ao ','Jin ','Zhe ','Yi ','Hu ','Jiang ','Man ','Chao ','Han ','Hua ','Chan ','Xu ','Zeng ','Se ','Xi ','She ','Dui ','Zheng ','Nao ','Lan ','E ','Ying ','Jue ','Ji ','Zun ','Jiao ','Bo ','Hui ','Zhuan ','Mu ','Zen ','Zha ','Shi ','Qiao ','Tan ','Zen ','Pu ','Sheng ','Xuan ','Zao ','Tan ','Dang ','Sui ','Qian ','Ji ','Jiao ','Jing ','Lian ','Nou ','Yi ','Ai ','Zhan ','Pi ','Hui ','Hua ','Yi ','Yi ','Shan ','Rang ','Nou ','Qian ','Zhui ','Ta ','Hu ','Zhou ','Hao ','Ye ','Ying ','Jian ','Yu ','Jian ','Hui ','Du ','Zhe ','Xuan ','Zan ','Lei ','Shen ','Wei ','Chan ','Li ','Yi ','Bian ','Zhe ','Yan ','E ','Chou ','Wei ','Chou ','Yao ','Chan ','Rang ','Yin ','Lan ','Chen ','Huo ','Zhe ','Huan ','Zan ','Yi ','Dang ','Zhan ','Yan ','Du ','Yan ','Ji ','Ding ','Fu ','Ren ','Ji ','Jie ','Hong ','Tao ','Rang ','Shan ','Qi ','Tuo ','Xun ','Yi ','Xun ','Ji ','Ren ','Jiang ','Hui ','Ou ','Ju ','Ya ','Ne ','Xu ','E ','Lun ','Xiong ','Song ','Feng ','She ','Fang ','Jue ','Zheng ','Gu ','He ','Ping ','Zu ','Shi ','Xiong ','Zha ','Su ','Zhen ','Di ','Zou ','Ci ','Qu ','Zhao ','Bi ','Yi ','Yi ','Kuang ','Lei ','Shi ','Gua ','Shi ','Jie ','Hui ','Cheng ','Zhu ','Shen ','Hua ','Dan ','Gou ','Quan ','Gui ','Xun ','Yi ','Zheng ','Gai ','Xiang ','Cha ','Hun ','Xu ','Zhou ','Jie ','Wu ','Yu ','Qiao ','Wu ','Gao ','You ','Hui ','Kuang ','Shuo ','Song ','Ai ','Qing ','Zhu ','Zou ','Nuo ','Du ','Zhuo ','Fei ','Ke ','Wei ',
);
<?php
$UTF8_TO_ASCII[0xb7] = array(
'Yu ','Shui ','Shen ','Diao ','Chan ','Liang ','Zhun ','Sui ','Tan ','Shen ','Yi ','Mou ','Chen ','Die ','Huang ','Jian ','Xie ','Nue ','Ye ','Wei ','E ','Yu ','Xuan ','Chan ','Zi ','An ','Yan ','Di ','Mi ','Pian ','Xu ','Mo ','Dang ','Su ','Xie ','Yao ','Bang ','Shi ','Qian ','Mi ','Jin ','Man ','Zhe ','Jian ','Miu ','Tan ','Zen ','Qiao ','Lan ','Pu ','Jue ','Yan ','Qian ','Zhan ','Chen ','Gu ','Qian ','Hong ','Xia ','Jue ','Hong ','Han ','Hong ','Xi ','Xi ','Huo ','Liao ','Han ','Du ','Long ','Dou ','Jiang ','Qi ','Shi ','Li ','Deng ','Wan ','Bi ','Shu ','Xian ','Feng ','Zhi ','Zhi ','Yan ','Yan ','Shi ','Chu ','Hui ','Tun ','Yi ','Tun ','Yi ','Jian ','Ba ','Hou ','E ','Cu ','Xiang ','Huan ','Jian ','Ken ','Gai ','Qu ','Fu ','Xi ','Bin ','Hao ','Yu ','Zhu ','Jia ','[?] ','Xi ','Bo ','Wen ','Huan ','Bin ','Di ','Zong ','Fen ','Yi ','Zhi ','Bao ','Chai ','Han ','Pi ','Na ','Pi ','Gou ','Na ','You ','Diao ','Mo ','Si ','Xiu ','Huan ','Kun ','He ','He ','Mo ','Han ','Mao ','Li ','Ni ','Bi ','Yu ','Jia ','Tuan ','Mao ','Pi ','Xi ','E ','Ju ','Mo ','Chu ','Tan ','Huan ','Jue ','Bei ','Zhen ','Yuan ','Fu ','Cai ','Gong ','Te ','Yi ','Hang ','Wan ','Pin ','Huo ','Fan ','Tan ','Guan ','Ze ','Zhi ','Er ','Zhu ','Shi ','Bi ','Zi ','Er ','Gui ','Pian ','Bian ','Mai ','Dai ','Sheng ','Kuang ','Fei ','Tie ','Yi ','Chi ','Mao ','He ','Bi ','Lu ','Ren ','Hui ','Gai ','Pian ','Zi ','Jia ','Xu ','Zei ','Jiao ','Gai ','Zang ','Jian ','Ying ','Xun ','Zhen ','She ','Bin ','Bin ','Qiu ','She ','Chuan ','Zang ','Zhou ','Lai ','Zan ','Si ','Chen ','Shang ','Tian ','Pei ','Geng ','Xian ','Mai ','Jian ','Sui ','Fu ','Tan ','Cong ','Cong ','Zhi ','Ji ','Zhang ','Du ','Jin ','Xiong ','Shun ','Yun ','Bao ','Zai ','Lai ','Feng ','Cang ','Ji ','Sheng ','Ai ','Zhuan ','Fu ','Gou ','Sai ','Ze ','Liao ',
);
<?php
$UTF8_TO_ASCII[0xb8] = array(
'Wei ','Bai ','Chen ','Zhuan ','Zhi ','Zhui ','Biao ','Yun ','Zeng ','Tan ','Zan ','Yan ','[?] ','Shan ','Wan ','Ying ','Jin ','Gan ','Xian ','Zang ','Bi ','Du ','Shu ','Yan ','[?] ','Xuan ','Long ','Gan ','Zang ','Bei ','Zhen ','Fu ','Yuan ','Gong ','Cai ','Ze ','Xian ','Bai ','Zhang ','Huo ','Zhi ','Fan ','Tan ','Pin ','Bian ','Gou ','Zhu ','Guan ','Er ','Jian ','Bi ','Shi ','Tie ','Gui ','Kuang ','Dai ','Mao ','Fei ','He ','Yi ','Zei ','Zhi ','Jia ','Hui ','Zi ','Ren ','Lu ','Zang ','Zi ','Gai ','Jin ','Qiu ','Zhen ','Lai ','She ','Fu ','Du ','Ji ','Shu ','Shang ','Si ','Bi ','Zhou ','Geng ','Pei ','Tan ','Lai ','Feng ','Zhui ','Fu ','Zhuan ','Sai ','Ze ','Yan ','Zan ','Yun ','Zeng ','Shan ','Ying ','Gan ','Chi ','Xi ','She ','Nan ','Xiong ','Xi ','Cheng ','He ','Cheng ','Zhe ','Xia ','Tang ','Zou ','Zou ','Li ','Jiu ','Fu ','Zhao ','Gan ','Qi ','Shan ','Qiong ','Qin ','Xian ','Ci ','Jue ','Qin ','Chi ','Ci ','Chen ','Chen ','Die ','Ju ','Chao ','Di ','Se ','Zhan ','Zhu ','Yue ','Qu ','Jie ','Chi ','Chu ','Gua ','Xue ','Ci ','Tiao ','Duo ','Lie ','Gan ','Suo ','Cu ','Xi ','Zhao ','Su ','Yin ','Ju ','Jian ','Que ','Tang ','Chuo ','Cui ','Lu ','Qu ','Dang ','Qiu ','Zi ','Ti ','Qu ','Chi ','Huang ','Qiao ','Qiao ','Yao ','Zao ','Ti ','[?] ','Zan ','Zan ','Zu ','Pa ','Bao ','Ku ','Ke ','Dun ','Jue ','Fu ','Chen ','Jian ','Fang ','Zhi ','Sa ','Yue ','Pa ','Qi ','Yue ','Qiang ','Tuo ','Tai ','Yi ','Nian ','Ling ','Mei ','Ba ','Die ','Ku ','Tuo ','Jia ','Ci ','Pao ','Qia ','Zhu ','Ju ','Die ','Zhi ','Fu ','Pan ','Ju ','Shan ','Bo ','Ni ','Ju ','Li ','Gen ','Yi ','Ji ','Dai ','Xian ','Jiao ','Duo ','Zhu ','Zhuan ','Kua ','Zhuai ','Gui ','Qiong ','Kui ','Xiang ','Chi ','Lu ','Beng ','Zhi ','Jia ','Tiao ','Cai ','Jian ','Ta ','Qiao ','Bi ','Xian ','Duo ','Ji ','Ju ','Ji ','Shu ','Tu ',
);
<?php
$UTF8_TO_ASCII[0xb9] = array(
'Chu ','Jing ','Nie ','Xiao ','Bo ','Chi ','Qun ','Mou ','Shu ','Lang ','Yong ','Jiao ','Chou ','Qiao ','[?] ','Ta ','Jian ','Qi ','Wo ','Wei ','Zhuo ','Jie ','Ji ','Nie ','Ju ','Ju ','Lun ','Lu ','Leng ','Huai ','Ju ','Chi ','Wan ','Quan ','Ti ','Bo ','Zu ','Qie ','Ji ','Cu ','Zong ','Cai ','Zong ','Peng ','Zhi ','Zheng ','Dian ','Zhi ','Yu ','Duo ','Dun ','Chun ','Yong ','Zhong ','Di ','Zhe ','Chen ','Chuai ','Jian ','Gua ','Tang ','Ju ','Fu ','Zu ','Die ','Pian ','Rou ','Nuo ','Ti ','Cha ','Tui ','Jian ','Dao ','Cuo ','Xi ','Ta ','Qiang ','Zhan ','Dian ','Ti ','Ji ','Nie ','Man ','Liu ','Zhan ','Bi ','Chong ','Lu ','Liao ','Cu ','Tang ','Dai ','Suo ','Xi ','Kui ','Ji ','Zhi ','Qiang ','Di ','Man ','Zong ','Lian ','Beng ','Zao ','Nian ','Bie ','Tui ','Ju ','Deng ','Ceng ','Xian ','Fan ','Chu ','Zhong ','Dun ','Bo ','Cu ','Zu ','Jue ','Jue ','Lin ','Ta ','Qiao ','Qiao ','Pu ','Liao ','Dun ','Cuan ','Kuang ','Zao ','Ta ','Bi ','Bi ','Zhu ','Ju ','Chu ','Qiao ','Dun ','Chou ','Ji ','Wu ','Yue ','Nian ','Lin ','Lie ','Zhi ','Li ','Zhi ','Chan ','Chu ','Duan ','Wei ','Long ','Lin ','Xian ','Wei ','Zuan ','Lan ','Xie ','Rang ','Xie ','Nie ','Ta ','Qu ','Jie ','Cuan ','Zuan ','Xi ','Kui ','Jue ','Lin ','Shen ','Gong ','Dan ','Segare ','Qu ','Ti ','Duo ','Duo ','Gong ','Lang ','Nerau ','Luo ','Ai ','Ji ','Ju ','Tang ','Utsuke ','[?] ','Yan ','Shitsuke ','Kang ','Qu ','Lou ','Lao ','Tuo ','Zhi ','Yagate ','Ti ','Dao ','Yagate ','Yu ','Che ','Ya ','Gui ','Jun ','Wei ','Yue ','Xin ','Di ','Xuan ','Fan ','Ren ','Shan ','Qiang ','Shu ','Tun ','Chen ','Dai ','E ','Na ','Qi ','Mao ','Ruan ','Ren ','Fan ','Zhuan ','Hong ','Hu ','Qu ','Huang ','Di ','Ling ','Dai ','Ao ','Zhen ','Fan ','Kuang ','Ang ','Peng ','Bei ','Gu ','Ku ','Pao ','Zhu ','Rong ','E ','Ba ','Zhou ','Zhi ','Yao ','Ke ','Yi ','Qing ','Shi ','Ping ',
);
<?php
$UTF8_TO_ASCII[0xba] = array(
'Er ','Qiong ','Ju ','Jiao ','Guang ','Lu ','Kai ','Quan ','Zhou ','Zai ','Zhi ','She ','Liang ','Yu ','Shao ','You ','Huan ','Yun ','Zhe ','Wan ','Fu ','Qing ','Zhou ','Ni ','Ling ','Zhe ','Zhan ','Liang ','Zi ','Hui ','Wang ','Chuo ','Guo ','Kan ','Yi ','Peng ','Qian ','Gun ','Nian ','Pian ','Guan ','Bei ','Lun ','Pai ','Liang ','Ruan ','Rou ','Ji ','Yang ','Xian ','Chuan ','Cou ','Qun ','Ge ','You ','Hong ','Shu ','Fu ','Zi ','Fu ','Wen ','Ben ','Zhan ','Yu ','Wen ','Tao ','Gu ','Zhen ','Xia ','Yuan ','Lu ','Jiu ','Chao ','Zhuan ','Wei ','Hun ','Sori ','Che ','Jiao ','Zhan ','Pu ','Lao ','Fen ','Fan ','Lin ','Ge ','Se ','Kan ','Huan ','Yi ','Ji ','Dui ','Er ','Yu ','Xian ','Hong ','Lei ','Pei ','Li ','Li ','Lu ','Lin ','Che ','Ya ','Gui ','Xuan ','Di ','Ren ','Zhuan ','E ','Lun ','Ruan ','Hong ','Ku ','Ke ','Lu ','Zhou ','Zhi ','Yi ','Hu ','Zhen ','Li ','Yao ','Qing ','Shi ','Zai ','Zhi ','Jiao ','Zhou ','Quan ','Lu ','Jiao ','Zhe ','Fu ','Liang ','Nian ','Bei ','Hui ','Gun ','Wang ','Liang ','Chuo ','Zi ','Cou ','Fu ','Ji ','Wen ','Shu ','Pei ','Yuan ','Xia ','Zhan ','Lu ','Che ','Lin ','Xin ','Gu ','Ci ','Ci ','Pi ','Zui ','Bian ','La ','La ','Ci ','Xue ','Ban ','Bian ','Bian ','Bian ','[?] ','Bian ','Ban ','Ci ','Bian ','Bian ','Chen ','Ru ','Nong ','Nong ','Zhen ','Chuo ','Chuo ','Suberu ','Reng ','Bian ','Bian ','Sip ','Ip ','Liao ','Da ','Chan ','Gan ','Qian ','Yu ','Yu ','Qi ','Xun ','Yi ','Guo ','Mai ','Qi ','Za ','Wang ','Jia ','Zhun ','Ying ','Ti ','Yun ','Jin ','Hang ','Ya ','Fan ','Wu ','Da ','E ','Huan ','Zhe ','Totemo ','Jin ','Yuan ','Wei ','Lian ','Chi ','Che ','Ni ','Tiao ','Zhi ','Yi ','Jiong ','Jia ','Chen ','Dai ','Er ','Di ','Po ','Wang ','Die ','Ze ','Tao ','Shu ','Tuo ','Kep ','Jing ','Hui ','Tong ','You ','Mi ','Beng ','Ji ','Nai ','Yi ','Jie ','Zhui ','Lie ','Xun ',
);
<?php
$UTF8_TO_ASCII[0xbb] = array(
'Tui ','Song ','Gua ','Tao ','Pang ','Hou ','Ni ','Dun ','Jiong ','Xuan ','Xun ','Bu ','You ','Xiao ','Qiu ','Tou ','Zhu ','Qiu ','Di ','Di ','Tu ','Jing ','Ti ','Dou ','Yi ','Zhe ','Tong ','Guang ','Wu ','Shi ','Cheng ','Su ','Zao ','Qun ','Feng ','Lian ','Suo ','Hui ','Li ','Sako ','Lai ','Ben ','Cuo ','Jue ','Beng ','Huan ','Dai ','Lu ','You ','Zhou ','Jin ','Yu ','Chuo ','Kui ','Wei ','Ti ','Yi ','Da ','Yuan ','Luo ','Bi ','Nuo ','Yu ','Dang ','Sui ','Dun ','Sui ','Yan ','Chuan ','Chi ','Ti ','Yu ','Shi ','Zhen ','You ','Yun ','E ','Bian ','Guo ','E ','Xia ','Huang ','Qiu ','Dao ','Da ','Wei ','Appare ','Yi ','Gou ','Yao ','Chu ','Liu ','Xun ','Ta ','Di ','Chi ','Yuan ','Su ','Ta ','Qian ','[?] ','Yao ','Guan ','Zhang ','Ao ','Shi ','Ce ','Chi ','Su ','Zao ','Zhe ','Dun ','Di ','Lou ','Chi ','Cuo ','Lin ','Zun ','Rao ','Qian ','Xuan ','Yu ','Yi ','Wu ','Liao ','Ju ','Shi ','Bi ','Yao ','Mai ','Xie ','Sui ','Huan ','Zhan ','Teng ','Er ','Miao ','Bian ','Bian ','La ','Li ','Yuan ','Yao ','Luo ','Li ','Yi ','Ting ','Deng ','Qi ','Yong ','Shan ','Han ','Yu ','Mang ','Ru ','Qiong ','[?] ','Kuang ','Fu ','Kang ','Bin ','Fang ','Xing ','Na ','Xin ','Shen ','Bang ','Yuan ','Cun ','Huo ','Xie ','Bang ','Wu ','Ju ','You ','Han ','Tai ','Qiu ','Bi ','Pei ','Bing ','Shao ','Bei ','Wa ','Di ','Zou ','Ye ','Lin ','Kuang ','Gui ','Zhu ','Shi ','Ku ','Yu ','Gai ','Ge ','Xi ','Zhi ','Ji ','Xun ','Hou ','Xing ','Jiao ','Xi ','Gui ','Nuo ','Lang ','Jia ','Kuai ','Zheng ','Otoko ','Yun ','Yan ','Cheng ','Dou ','Chi ','Lu ','Fu ','Wu ','Fu ','Gao ','Hao ','Lang ','Jia ','Geng ','Jun ','Ying ','Bo ','Xi ','Bei ','Li ','Yun ','Bu ','Xiao ','Qi ','Pi ','Qing ','Guo ','Zhou ','Tan ','Zou ','Ping ','Lai ','Ni ','Chen ','You ','Bu ','Xiang ','Dan ','Ju ','Yong ','Qiao ','Yi ','Du ','Yan ','Mei ',
);
<?php
$UTF8_TO_ASCII[0xbc] = array(
'Ruo ','Bei ','E ','Yu ','Juan ','Yu ','Yun ','Hou ','Kui ','Xiang ','Xiang ','Sou ','Tang ','Ming ','Xi ','Ru ','Chu ','Zi ','Zou ','Ju ','Wu ','Xiang ','Yun ','Hao ','Yong ','Bi ','Mo ','Chao ','Fu ','Liao ','Yin ','Zhuan ','Hu ','Qiao ','Yan ','Zhang ','Fan ','Qiao ','Xu ','Deng ','Bi ','Xin ','Bi ','Ceng ','Wei ','Zheng ','Mao ','Shan ','Lin ','Po ','Dan ','Meng ','Ye ','Cao ','Kuai ','Feng ','Meng ','Zou ','Kuang ','Lian ','Zan ','Chan ','You ','Qi ','Yan ','Chan ','Zan ','Ling ','Huan ','Xi ','Feng ','Zan ','Li ','You ','Ding ','Qiu ','Zhuo ','Pei ','Zhou ','Yi ','Hang ','Yu ','Jiu ','Yan ','Zui ','Mao ','Dan ','Xu ','Tou ','Zhen ','Fen ','Sakenomoto ','[?] ','Yun ','Tai ','Tian ','Qia ','Tuo ','Zuo ','Han ','Gu ','Su ','Po ','Chou ','Zai ','Ming ','Luo ','Chuo ','Chou ','You ','Tong ','Zhi ','Xian ','Jiang ','Cheng ','Yin ','Tu ','Xiao ','Mei ','Ku ','Suan ','Lei ','Pu ','Zui ','Hai ','Yan ','Xi ','Niang ','Wei ','Lu ','Lan ','Yan ','Tao ','Pei ','Zhan ','Chun ','Tan ','Zui ','Chuo ','Cu ','Kun ','Ti ','Mian ','Du ','Hu ','Xu ','Xing ','Tan ','Jiu ','Chun ','Yun ','Po ','Ke ','Sou ','Mi ','Quan ','Chou ','Cuo ','Yun ','Yong ','Ang ','Zha ','Hai ','Tang ','Jiang ','Piao ','Shan ','Yu ','Li ','Zao ','Lao ','Yi ','Jiang ','Pu ','Jiao ','Xi ','Tan ','Po ','Nong ','Yi ','Li ','Ju ','Jiao ','Yi ','Niang ','Ru ','Xun ','Chou ','Yan ','Ling ','Mi ','Mi ','Niang ','Xin ','Jiao ','Xi ','Mi ','Yan ','Bian ','Cai ','Shi ','You ','Shi ','Shi ','Li ','Zhong ','Ye ','Liang ','Li ','Jin ','Jin ','Qiu ','Yi ','Diao ','Dao ','Zhao ','Ding ','Po ','Qiu ','He ','Fu ','Zhen ','Zhi ','Ba ','Luan ','Fu ','Nai ','Diao ','Shan ','Qiao ','Kou ','Chuan ','Zi ','Fan ','Yu ','Hua ','Han ','Gong ','Qi ','Mang ','Ri ','Di ','Si ','Xi ','Yi ','Chai ','Shi ','Tu ','Xi ','Nu ','Qian ','Ishiyumi ','Jian ','Pi ','Ye ','Yin ',
);
<?php
$UTF8_TO_ASCII[0xbd] = array(
'Ba ','Fang ','Chen ','Xing ','Tou ','Yue ','Yan ','Fu ','Pi ','Na ','Xin ','E ','Jue ','Dun ','Gou ','Yin ','Qian ','Ban ','Ji ','Ren ','Chao ','Niu ','Fen ','Yun ','Ji ','Qin ','Pi ','Guo ','Hong ','Yin ','Jun ','Shi ','Yi ','Zhong ','Nie ','Gai ','Ri ','Huo ','Tai ','Kang ','Habaki ','Irori ','Ngaak ','[?] ','Duo ','Zi ','Ni ','Tu ','Shi ','Min ','Gu ','E ','Ling ','Bing ','Yi ','Gu ','Ba ','Pi ','Yu ','Si ','Zuo ','Bu ','You ','Dian ','Jia ','Zhen ','Shi ','Shi ','Tie ','Ju ','Zhan ','Shi ','She ','Xuan ','Zhao ','Bao ','He ','Bi ','Sheng ','Chu ','Shi ','Bo ','Zhu ','Chi ','Za ','Po ','Tong ','Qian ','Fu ','Zhai ','Liu ','Qian ','Fu ','Li ','Yue ','Pi ','Yang ','Ban ','Bo ','Jie ','Gou ','Shu ','Zheng ','Mu ','Ni ','Nie ','Di ','Jia ','Mu ','Dan ','Shen ','Yi ','Si ','Kuang ','Ka ','Bei ','Jian ','Tong ','Xing ','Hong ','Jiao ','Chi ','Er ','Ge ','Bing ','Shi ','Mou ','Jia ','Yin ','Jun ','Zhou ','Chong ','Shang ','Tong ','Mo ','Lei ','Ji ','Yu ','Xu ','Ren ','Zun ','Zhi ','Qiong ','Shan ','Chi ','Xian ','Xing ','Quan ','Pi ','Tie ','Zhu ','Hou ','Ming ','Kua ','Yao ','Xian ','Xian ','Xiu ','Jun ','Cha ','Lao ','Ji ','Pi ','Ru ','Mi ','Yi ','Yin ','Guang ','An ','Diou ','You ','Se ','Kao ','Qian ','Luan ','Kasugai ','Ai ','Diao ','Han ','Rui ','Shi ','Keng ','Qiu ','Xiao ','Zhe ','Xiu ','Zang ','Ti ','Cuo ','Gua ','Gong ','Zhong ','Dou ','Lu ','Mei ','Lang ','Wan ','Xin ','Yun ','Bei ','Wu ','Su ','Yu ','Chan ','Ting ','Bo ','Han ','Jia ','Hong ','Cuan ','Feng ','Chan ','Wan ','Zhi ','Si ','Xuan ','Wu ','Wu ','Tiao ','Gong ','Zhuo ','Lue ','Xing ','Qian ','Shen ','Han ','Lue ','Xie ','Chu ','Zheng ','Ju ','Xian ','Tie ','Mang ','Pu ','Li ','Pan ','Rui ','Cheng ','Gao ','Li ','Te ','Pyeng ','Zhu ','[?] ','Tu ','Liu ','Zui ','Ju ','Chang ','Yuan ','Jian ','Gang ','Diao ','Tao ','Chang ',
);
<?php
$UTF8_TO_ASCII[0xbe] = array(
'Lun ','Kua ','Ling ','Bei ','Lu ','Li ','Qiang ','Pou ','Juan ','Min ','Zui ','Peng ','An ','Pi ','Xian ','Ya ','Zhui ','Lei ','A ','Kong ','Ta ','Kun ','Du ','Wei ','Chui ','Zi ','Zheng ','Ben ','Nie ','Cong ','Qun ','Tan ','Ding ','Qi ','Qian ','Zhuo ','Qi ','Yu ','Jin ','Guan ','Mao ','Chang ','Tian ','Xi ','Lian ','Tao ','Gu ','Cuo ','Shu ','Zhen ','Lu ','Meng ','Lu ','Hua ','Biao ','Ga ','Lai ','Ken ','Kazari ','Bu ','Nai ','Wan ','Zan ','[?] ','De ','Xian ','[?] ','Huo ','Liang ','[?] ','Men ','Kai ','Ying ','Di ','Lian ','Guo ','Xian ','Du ','Tu ','Wei ','Cong ','Fu ','Rou ','Ji ','E ','Rou ','Chen ','Ti ','Zha ','Hong ','Yang ','Duan ','Xia ','Yu ','Keng ','Xing ','Huang ','Wei ','Fu ','Zhao ','Cha ','Qie ','She ','Hong ','Kui ','Tian ','Mou ','Qiao ','Qiao ','Hou ','Tou ','Cong ','Huan ','Ye ','Min ','Jian ','Duan ','Jian ','Song ','Kui ','Hu ','Xuan ','Duo ','Jie ','Zhen ','Bian ','Zhong ','Zi ','Xiu ','Ye ','Mei ','Pai ','Ai ','Jie ','[?] ','Mei ','Chuo ','Ta ','Bang ','Xia ','Lian ','Suo ','Xi ','Liu ','Zu ','Ye ','Nou ','Weng ','Rong ','Tang ','Suo ','Qiang ','Ge ','Shuo ','Chui ','Bo ','Pan ','Sa ','Bi ','Sang ','Gang ','Zi ','Wu ','Ying ','Huang ','Tiao ','Liu ','Kai ','Sun ','Sha ','Sou ','Wan ','Hao ','Zhen ','Zhen ','Luo ','Yi ','Yuan ','Tang ','Nie ','Xi ','Jia ','Ge ','Ma ','Juan ','Kasugai ','Habaki ','Suo ','[?] ','[?] ','[?] ','Na ','Lu ','Suo ','Ou ','Zu ','Tuan ','Xiu ','Guan ','Xuan ','Lian ','Shou ','Ao ','Man ','Mo ','Luo ','Bi ','Wei ','Liu ','Di ','Qiao ','Cong ','Yi ','Lu ','Ao ','Keng ','Qiang ','Cui ','Qi ','Chang ','Tang ','Man ','Yong ','Chan ','Feng ','Jing ','Biao ','Shu ','Lou ','Xiu ','Cong ','Long ','Zan ','Jian ','Cao ','Li ','Xia ','Xi ','Kang ','[?] ','Beng ','[?] ','[?] ','Zheng ','Lu ','Hua ','Ji ','Pu ','Hui ','Qiang ','Po ','Lin ','Suo ','Xiu ','San ','Cheng ',
);
<?php
$UTF8_TO_ASCII[0xbf] = array(
'Kui ','Si ','Liu ','Nao ','Heng ','Pie ','Sui ','Fan ','Qiao ','Quan ','Yang ','Tang ','Xiang ','Jue ','Jiao ','Zun ','Liao ','Jie ','Lao ','Dui ','Tan ','Zan ','Ji ','Jian ','Zhong ','Deng ','Ya ','Ying ','Dui ','Jue ','Nou ','Ti ','Pu ','Tie ','[?] ','[?] ','Ding ','Shan ','Kai ','Jian ','Fei ','Sui ','Lu ','Juan ','Hui ','Yu ','Lian ','Zhuo ','Qiao ','Qian ','Zhuo ','Lei ','Bi ','Tie ','Huan ','Ye ','Duo ','Guo ','Dang ','Ju ','Fen ','Da ','Bei ','Yi ','Ai ','Zong ','Xun ','Diao ','Zhu ','Heng ','Zhui ','Ji ','Nie ','Ta ','Huo ','Qing ','Bin ','Ying ','Kui ','Ning ','Xu ','Jian ','Jian ','Yari ','Cha ','Zhi ','Mie ','Li ','Lei ','Ji ','Zuan ','Kuang ','Shang ','Peng ','La ','Du ','Shuo ','Chuo ','Lu ','Biao ','Bao ','Lu ','[?] ','[?] ','Long ','E ','Lu ','Xin ','Jian ','Lan ','Bo ','Jian ','Yao ','Chan ','Xiang ','Jian ','Xi ','Guan ','Cang ','Nie ','Lei ','Cuan ','Qu ','Pan ','Luo ','Zuan ','Luan ','Zao ','Nie ','Jue ','Tang ','Shu ','Lan ','Jin ','Qiu ','Yi ','Zhen ','Ding ','Zhao ','Po ','Diao ','Tu ','Qian ','Chuan ','Shan ','Ji ','Fan ','Diao ','Men ','Nu ','Xi ','Chai ','Xing ','Gai ','Bu ','Tai ','Ju ','Dun ','Chao ','Zhong ','Na ','Bei ','Gang ','Ban ','Qian ','Yao ','Qin ','Jun ','Wu ','Gou ','Kang ','Fang ','Huo ','Tou ','Niu ','Ba ','Yu ','Qian ','Zheng ','Qian ','Gu ','Bo ','E ','Po ','Bu ','Ba ','Yue ','Zuan ','Mu ','Dan ','Jia ','Dian ','You ','Tie ','Bo ','Ling ','Shuo ','Qian ','Liu ','Bao ','Shi ','Xuan ','She ','Bi ','Ni ','Pi ','Duo ','Xing ','Kao ','Lao ','Er ','Mang ','Ya ','You ','Cheng ','Jia ','Ye ','Nao ','Zhi ','Dang ','Tong ','Lu ','Diao ','Yin ','Kai ','Zha ','Zhu ','Xian ','Ting ','Diu ','Xian ','Hua ','Quan ','Sha ','Jia ','Yao ','Ge ','Ming ','Zheng ','Se ','Jiao ','Yi ','Chan ','Chong ','Tang ','An ','Yin ','Ru ','Zhu ','Lao ','Pu ','Wu ','Lai ','Te ','Lian ','Keng ',
);
<?php
$UTF8_TO_ASCII[0xc0] = array(
'Xiao ','Suo ','Li ','Zheng ','Chu ','Guo ','Gao ','Tie ','Xiu ','Cuo ','Lue ','Feng ','Xin ','Liu ','Kai ','Jian ','Rui ','Ti ','Lang ','Qian ','Ju ','A ','Qiang ','Duo ','Tian ','Cuo ','Mao ','Ben ','Qi ','De ','Kua ','Kun ','Chang ','Xi ','Gu ','Luo ','Chui ','Zhui ','Jin ','Zhi ','Xian ','Juan ','Huo ','Pou ','Tan ','Ding ','Jian ','Ju ','Meng ','Zi ','Qie ','Ying ','Kai ','Qiang ','Song ','E ','Cha ','Qiao ','Zhong ','Duan ','Sou ','Huang ','Huan ','Ai ','Du ','Mei ','Lou ','Zi ','Fei ','Mei ','Mo ','Zhen ','Bo ','Ge ','Nie ','Tang ','Juan ','Nie ','Na ','Liu ','Hao ','Bang ','Yi ','Jia ','Bin ','Rong ','Biao ','Tang ','Man ','Luo ','Beng ','Yong ','Jing ','Di ','Zu ','Xuan ','Liu ','Tan ','Jue ','Liao ','Pu ','Lu ','Dui ','Lan ','Pu ','Cuan ','Qiang ','Deng ','Huo ','Lei ','Huan ','Zhuo ','Lian ','Yi ','Cha ','Biao ','La ','Chan ','Xiang ','Chang ','Chang ','Jiu ','Ao ','Die ','Qu ','Liao ','Mi ','Chang ','Men ','Ma ','Shuan ','Shan ','Huo ','Men ','Yan ','Bi ','Han ','Bi ','San ','Kai ','Kang ','Beng ','Hong ','Run ','San ','Xian ','Xian ','Jian ','Min ','Xia ','Yuru ','Dou ','Zha ','Nao ','Jian ','Peng ','Xia ','Ling ','Bian ','Bi ','Run ','He ','Guan ','Ge ','Ge ','Fa ','Chu ','Hong ','Gui ','Min ','Se ','Kun ','Lang ','Lu ','Ting ','Sha ','Ju ','Yue ','Yue ','Chan ','Qu ','Lin ','Chang ','Shai ','Kun ','Yan ','Min ','Yan ','E ','Hun ','Yu ','Wen ','Xiang ','Bao ','Xiang ','Qu ','Yao ','Wen ','Ban ','An ','Wei ','Yin ','Kuo ','Que ','Lan ','Du ','[?] ','Phwung ','Tian ','Nie ','Ta ','Kai ','He ','Que ','Chuang ','Guan ','Dou ','Qi ','Kui ','Tang ','Guan ','Piao ','Kan ','Xi ','Hui ','Chan ','Pi ','Dang ','Huan ','Ta ','Wen ','[?] ','Men ','Shuan ','Shan ','Yan ','Han ','Bi ','Wen ','Chuang ','Run ','Wei ','Xian ','Hong ','Jian ','Min ','Kang ','Men ','Zha ','Nao ','Gui ','Wen ','Ta ','Min ','Lu ','Kai ',
);
<?php
$UTF8_TO_ASCII[0xc1] = array(
'Fa ','Ge ','He ','Kun ','Jiu ','Yue ','Lang ','Du ','Yu ','Yan ','Chang ','Xi ','Wen ','Hun ','Yan ','E ','Chan ','Lan ','Qu ','Hui ','Kuo ','Que ','Ge ','Tian ','Ta ','Que ','Kan ','Huan ','Fu ','Fu ','Le ','Dui ','Xin ','Qian ','Wu ','Yi ','Tuo ','Yin ','Yang ','Dou ','E ','Sheng ','Ban ','Pei ','Keng ','Yun ','Ruan ','Zhi ','Pi ','Jing ','Fang ','Yang ','Yin ','Zhen ','Jie ','Cheng ','E ','Qu ','Di ','Zu ','Zuo ','Dian ','Ling ','A ','Tuo ','Tuo ','Po ','Bing ','Fu ','Ji ','Lu ','Long ','Chen ','Xing ','Duo ','Lou ','Mo ','Jiang ','Shu ','Duo ','Xian ','Er ','Gui ','Yu ','Gai ','Shan ','Xun ','Qiao ','Xing ','Chun ','Fu ','Bi ','Xia ','Shan ','Sheng ','Zhi ','Pu ','Dou ','Yuan ','Zhen ','Chu ','Xian ','Tou ','Nie ','Yun ','Xian ','Pei ','Pei ','Zou ','Yi ','Dui ','Lun ','Yin ','Ju ','Chui ','Chen ','Pi ','Ling ','Tao ','Xian ','Lu ','Sheng ','Xian ','Yin ','Zhu ','Yang ','Reng ','Shan ','Chong ','Yan ','Yin ','Yu ','Ti ','Yu ','Long ','Wei ','Wei ','Nie ','Dui ','Sui ','An ','Huang ','Jie ','Sui ','Yin ','Gai ','Yan ','Hui ','Ge ','Yun ','Wu ','Wei ','Ai ','Xi ','Tang ','Ji ','Zhang ','Dao ','Ao ','Xi ','Yin ','[?] ','Rao ','Lin ','Tui ','Deng ','Pi ','Sui ','Sui ','Yu ','Xian ','Fen ','Ni ','Er ','Ji ','Dao ','Xi ','Yin ','E ','Hui ','Long ','Xi ','Li ','Li ','Li ','Zhui ','He ','Zhi ','Zhun ','Jun ','Nan ','Yi ','Que ','Yan ','Qian ','Ya ','Xiong ','Ya ','Ji ','Gu ','Huan ','Zhi ','Gou ','Jun ','Ci ','Yong ','Ju ','Chu ','Hu ','Za ','Luo ','Yu ','Chou ','Diao ','Sui ','Han ','Huo ','Shuang ','Guan ','Chu ','Za ','Yong ','Ji ','Xi ','Chou ','Liu ','Li ','Nan ','Xue ','Za ','Ji ','Ji ','Yu ','Yu ','Xue ','Na ','Fou ','Se ','Mu ','Wen ','Fen ','Pang ','Yun ','Li ','Li ','Ang ','Ling ','Lei ','An ','Bao ','Meng ','Dian ','Dang ','Xing ','Wu ','Zhao ',
);
<?php
$UTF8_TO_ASCII[0xc2] = array(
'Xu ','Ji ','Mu ','Chen ','Xiao ','Zha ','Ting ','Zhen ','Pei ','Mei ','Ling ','Qi ','Chou ','Huo ','Sha ','Fei ','Weng ','Zhan ','Yin ','Ni ','Chou ','Tun ','Lin ','[?] ','Dong ','Ying ','Wu ','Ling ','Shuang ','Ling ','Xia ','Hong ','Yin ','Mo ','Mai ','Yun ','Liu ','Meng ','Bin ','Wu ','Wei ','Huo ','Yin ','Xi ','Yi ','Ai ','Dan ','Deng ','Xian ','Yu ','Lu ','Long ','Dai ','Ji ','Pang ','Yang ','Ba ','Pi ','Wei ','[?] ','Xi ','Ji ','Mai ','Meng ','Meng ','Lei ','Li ','Huo ','Ai ','Fei ','Dai ','Long ','Ling ','Ai ','Feng ','Li ','Bao ','[?] ','He ','He ','Bing ','Qing ','Qing ','Jing ','Tian ','Zhen ','Jing ','Cheng ','Qing ','Jing ','Jing ','Dian ','Jing ','Tian ','Fei ','Fei ','Kao ','Mi ','Mian ','Mian ','Pao ','Ye ','Tian ','Hui ','Ye ','Ge ','Ding ','Cha ','Jian ','Ren ','Di ','Du ','Wu ','Ren ','Qin ','Jin ','Xue ','Niu ','Ba ','Yin ','Sa ','Na ','Mo ','Zu ','Da ','Ban ','Yi ','Yao ','Tao ','Tuo ','Jia ','Hong ','Pao ','Yang ','Tomo ','Yin ','Jia ','Tao ','Ji ','Xie ','An ','An ','Hen ','Gong ','Kohaze ','Da ','Qiao ','Ting ','Wan ','Ying ','Sui ','Tiao ','Qiao ','Xuan ','Kong ','Beng ','Ta ','Zhang ','Bing ','Kuo ','Ju ','La ','Xie ','Rou ','Bang ','Yi ','Qiu ','Qiu ','He ','Xiao ','Mu ','Ju ','Jian ','Bian ','Di ','Jian ','On ','Tao ','Gou ','Ta ','Bei ','Xie ','Pan ','Ge ','Bi ','Kuo ','Tang ','Lou ','Gui ','Qiao ','Xue ','Ji ','Jian ','Jiang ','Chan ','Da ','Huo ','Xian ','Qian ','Du ','Wa ','Jian ','Lan ','Wei ','Ren ','Fu ','Mei ','Juan ','Ge ','Wei ','Qiao ','Han ','Chang ','[?] ','Rou ','Xun ','She ','Wei ','Ge ','Bei ','Tao ','Gou ','Yun ','[?] ','Bi ','Wei ','Hui ','Du ','Wa ','Du ','Wei ','Ren ','Fu ','Han ','Wei ','Yun ','Tao ','Jiu ','Jiu ','Xian ','Xie ','Xian ','Ji ','Yin ','Za ','Yun ','Shao ','Le ','Peng ','Heng ','Ying ','Yun ','Peng ','Yin ','Yin ','Xiang ',
);
<?php
$UTF8_TO_ASCII[0xc3] = array(
'Hu ','Ye ','Ding ','Qing ','Pan ','Xiang ','Shun ','Han ','Xu ','Yi ','Xu ','Gu ','Song ','Kui ','Qi ','Hang ','Yu ','Wan ','Ban ','Dun ','Di ','Dan ','Pan ','Po ','Ling ','Ce ','Jing ','Lei ','He ','Qiao ','E ','E ','Wei ','Jie ','Gua ','Shen ','Yi ','Shen ','Hai ','Dui ','Pian ','Ping ','Lei ','Fu ','Jia ','Tou ','Hui ','Kui ','Jia ','Le ','Tian ','Cheng ','Ying ','Jun ','Hu ','Han ','Jing ','Tui ','Tui ','Pin ','Lai ','Tui ','Zi ','Zi ','Chui ','Ding ','Lai ','Yan ','Han ','Jian ','Ke ','Cui ','Jiong ','Qin ','Yi ','Sai ','Ti ','E ','E ','Yan ','Hun ','Kan ','Yong ','Zhuan ','Yan ','Xian ','Xin ','Yi ','Yuan ','Sang ','Dian ','Dian ','Jiang ','Ku ','Lei ','Liao ','Piao ','Yi ','Man ','Qi ','Rao ','Hao ','Qiao ','Gu ','Xun ','Qian ','Hui ','Zhan ','Ru ','Hong ','Bin ','Xian ','Pin ','Lu ','Lan ','Nie ','Quan ','Ye ','Ding ','Qing ','Han ','Xiang ','Shun ','Xu ','Xu ','Wan ','Gu ','Dun ','Qi ','Ban ','Song ','Hang ','Yu ','Lu ','Ling ','Po ','Jing ','Jie ','Jia ','Tian ','Han ','Ying ','Jiong ','Hai ','Yi ','Pin ','Hui ','Tui ','Han ','Ying ','Ying ','Ke ','Ti ','Yong ','E ','Zhuan ','Yan ','E ','Nie ','Man ','Dian ','Sang ','Hao ','Lei ','Zhan ','Ru ','Pin ','Quan ','Feng ','Biao ','Oroshi ','Fu ','Xia ','Zhan ','Biao ','Sa ','Ba ','Tai ','Lie ','Gua ','Xuan ','Shao ','Ju ','Bi ','Si ','Wei ','Yang ','Yao ','Sou ','Kai ','Sao ','Fan ','Liu ','Xi ','Liao ','Piao ','Piao ','Liu ','Biao ','Biao ','Biao ','Liao ','[?] ','Se ','Feng ','Biao ','Feng ','Yang ','Zhan ','Biao ','Sa ','Ju ','Si ','Sou ','Yao ','Liu ','Piao ','Biao ','Biao ','Fei ','Fan ','Fei ','Fei ','Shi ','Shi ','Can ','Ji ','Ding ','Si ','Tuo ','Zhan ','Sun ','Xiang ','Tun ','Ren ','Yu ','Juan ','Chi ','Yin ','Fan ','Fan ','Sun ','Yin ','Zhu ','Yi ','Zhai ','Bi ','Jie ','Tao ','Liu ','Ci ','Tie ','Si ','Bao ','Shi ','Duo ',
);
<?php
$UTF8_TO_ASCII[0xc4] = array(
'Hai ','Ren ','Tian ','Jiao ','Jia ','Bing ','Yao ','Tong ','Ci ','Xiang ','Yang ','Yang ','Er ','Yan ','Le ','Yi ','Can ','Bo ','Nei ','E ','Bu ','Jun ','Dou ','Su ','Yu ','Shi ','Yao ','Hun ','Guo ','Shi ','Jian ','Zhui ','Bing ','Xian ','Bu ','Ye ','Tan ','Fei ','Zhang ','Wei ','Guan ','E ','Nuan ','Hun ','Hu ','Huang ','Tie ','Hui ','Jian ','Hou ','He ','Xing ','Fen ','Wei ','Gu ','Cha ','Song ','Tang ','Bo ','Gao ','Xi ','Kui ','Liu ','Sou ','Tao ','Ye ','Yun ','Mo ','Tang ','Man ','Bi ','Yu ','Xiu ','Jin ','San ','Kui ','Zhuan ','Shan ','Chi ','Dan ','Yi ','Ji ','Rao ','Cheng ','Yong ','Tao ','Hui ','Xiang ','Zhan ','Fen ','Hai ','Meng ','Yan ','Mo ','Chan ','Xiang ','Luo ','Zuan ','Nang ','Shi ','Ding ','Ji ','Tuo ','Xing ','Tun ','Xi ','Ren ','Yu ','Chi ','Fan ','Yin ','Jian ','Shi ','Bao ','Si ','Duo ','Yi ','Er ','Rao ','Xiang ','Jia ','Le ','Jiao ','Yi ','Bing ','Bo ','Dou ','E ','Yu ','Nei ','Jun ','Guo ','Hun ','Xian ','Guan ','Cha ','Kui ','Gu ','Sou ','Chan ','Ye ','Mo ','Bo ','Liu ','Xiu ','Jin ','Man ','San ','Zhuan ','Nang ','Shou ','Kui ','Guo ','Xiang ','Fen ','Ba ','Ni ','Bi ','Bo ','Tu ','Han ','Fei ','Jian ','An ','Ai ','Fu ','Xian ','Wen ','Xin ','Fen ','Bin ','Xing ','Ma ','Yu ','Feng ','Han ','Di ','Tuo ','Tuo ','Chi ','Xun ','Zhu ','Zhi ','Pei ','Xin ','Ri ','Sa ','Yin ','Wen ','Zhi ','Dan ','Lu ','You ','Bo ','Bao ','Kuai ','Tuo ','Yi ','Qu ','[?] ','Qu ','Jiong ','Bo ','Zhao ','Yuan ','Peng ','Zhou ','Ju ','Zhu ','Nu ','Ju ','Pi ','Zang ','Jia ','Ling ','Zhen ','Tai ','Fu ','Yang ','Shi ','Bi ','Tuo ','Tuo ','Si ','Liu ','Ma ','Pian ','Tao ','Zhi ','Rong ','Teng ','Dong ','Xun ','Quan ','Shen ','Jiong ','Er ','Hai ','Bo ','Zhu ','Yin ','Luo ','Shuu ','Dan ','Xie ','Liu ','Ju ','Song ','Qin ','Mang ','Liang ','Han ','Tu ','Xuan ','Tui ','Jun ',
);
<?php
$UTF8_TO_ASCII[0xc5] = array(
'E ','Cheng ','Xin ','Ai ','Lu ','Zhui ','Zhou ','She ','Pian ','Kun ','Tao ','Lai ','Zong ','Ke ','Qi ','Qi ','Yan ','Fei ','Sao ','Yan ','Jie ','Yao ','Wu ','Pian ','Cong ','Pian ','Qian ','Fei ','Huang ','Jian ','Huo ','Yu ','Ti ','Quan ','Xia ','Zong ','Kui ','Rou ','Si ','Gua ','Tuo ','Kui ','Sou ','Qian ','Cheng ','Zhi ','Liu ','Pang ','Teng ','Xi ','Cao ','Du ','Yan ','Yuan ','Zou ','Sao ','Shan ','Li ','Zhi ','Shuang ','Lu ','Xi ','Luo ','Zhang ','Mo ','Ao ','Can ','Piao ','Cong ','Qu ','Bi ','Zhi ','Yu ','Xu ','Hua ','Bo ','Su ','Xiao ','Lin ','Chan ','Dun ','Liu ','Tuo ','Zeng ','Tan ','Jiao ','Tie ','Yan ','Luo ','Zhan ','Jing ','Yi ','Ye ','Tuo ','Bin ','Zou ','Yan ','Peng ','Lu ','Teng ','Xiang ','Ji ','Shuang ','Ju ','Xi ','Huan ','Li ','Biao ','Ma ','Yu ','Tuo ','Xun ','Chi ','Qu ','Ri ','Bo ','Lu ','Zang ','Shi ','Si ','Fu ','Ju ','Zou ','Zhu ','Tuo ','Nu ','Jia ','Yi ','Tai ','Xiao ','Ma ','Yin ','Jiao ','Hua ','Luo ','Hai ','Pian ','Biao ','Li ','Cheng ','Yan ','Xin ','Qin ','Jun ','Qi ','Qi ','Ke ','Zhui ','Zong ','Su ','Can ','Pian ','Zhi ','Kui ','Sao ','Wu ','Ao ','Liu ','Qian ','Shan ','Piao ','Luo ','Cong ','Chan ','Zou ','Ji ','Shuang ','Xiang ','Gu ','Wei ','Wei ','Wei ','Yu ','Gan ','Yi ','Ang ','Tou ','Xie ','Bao ','Bi ','Chi ','Ti ','Di ','Ku ','Hai ','Qiao ','Gou ','Kua ','Ge ','Tui ','Geng ','Pian ','Bi ','Ke ','Ka ','Yu ','Sui ','Lou ','Bo ','Xiao ','Pang ','Bo ','Ci ','Kuan ','Bin ','Mo ','Liao ','Lou ','Nao ','Du ','Zang ','Sui ','Ti ','Bin ','Kuan ','Lu ','Gao ','Gao ','Qiao ','Kao ','Qiao ','Lao ','Zao ','Biao ','Kun ','Kun ','Ti ','Fang ','Xiu ','Ran ','Mao ','Dan ','Kun ','Bin ','Fa ','Tiao ','Peng ','Zi ','Fa ','Ran ','Ti ','Pao ','Pi ','Mao ','Fu ','Er ','Rong ','Qu ','Gong ','Xiu ','Gua ','Ji ','Peng ','Zhua ','Shao ','Sha ',
);
<?php
$UTF8_TO_ASCII[0xc6] = array(
'Ti ','Li ','Bin ','Zong ','Ti ','Peng ','Song ','Zheng ','Quan ','Zong ','Shun ','Jian ','Duo ','Hu ','La ','Jiu ','Qi ','Lian ','Zhen ','Bin ','Peng ','Mo ','San ','Man ','Man ','Seng ','Xu ','Lie ','Qian ','Qian ','Nong ','Huan ','Kuai ','Ning ','Bin ','Lie ','Rang ','Dou ','Dou ','Nao ','Hong ','Xi ','Dou ','Han ','Dou ','Dou ','Jiu ','Chang ','Yu ','Yu ','Li ','Juan ','Fu ','Qian ','Gui ','Zong ','Liu ','Gui ','Shang ','Yu ','Gui ','Mei ','Ji ','Qi ','Jie ','Kui ','Hun ','Ba ','Po ','Mei ','Xu ','Yan ','Xiao ','Liang ','Yu ','Tui ','Qi ','Wang ','Liang ','Wei ','Jian ','Chi ','Piao ','Bi ','Mo ','Ji ','Xu ','Chou ','Yan ','Zhan ','Yu ','Dao ','Ren ','Ji ','Eri ','Gong ','Tuo ','Diao ','Ji ','Xu ','E ','E ','Sha ','Hang ','Tun ','Mo ','Jie ','Shen ','Fan ','Yuan ','Bi ','Lu ','Wen ','Hu ','Lu ','Za ','Fang ','Fen ','Na ','You ','Namazu ','Todo ','He ','Xia ','Qu ','Han ','Pi ','Ling ','Tuo ','Bo ','Qiu ','Ping ','Fu ','Bi ','Ji ','Wei ','Ju ','Diao ','Bo ','You ','Gun ','Pi ','Nian ','Xing ','Tai ','Bao ','Fu ','Zha ','Ju ','Gu ','Kajika ','Tong ','[?] ','Ta ','Jie ','Shu ','Hou ','Xiang ','Er ','An ','Wei ','Tiao ','Zhu ','Yin ','Lie ','Luo ','Tong ','Yi ','Qi ','Bing ','Wei ','Jiao ','Bu ','Gui ','Xian ','Ge ','Hui ','Bora ','Mate ','Kao ','Gori ','Duo ','Jun ','Ti ','Man ','Xiao ','Za ','Sha ','Qin ','Yu ','Nei ','Zhe ','Gun ','Geng ','Su ','Wu ','Qiu ','Ting ','Fu ','Wan ','You ','Li ','Sha ','Sha ','Gao ','Meng ','Ugui ','Asari ','Subashiri ','Kazunoko ','Yong ','Ni ','Zi ','Qi ','Qing ','Xiang ','Nei ','Chun ','Ji ','Diao ','Qie ','Gu ','Zhou ','Dong ','Lai ','Fei ','Ni ','Yi ','Kun ','Lu ','Jiu ','Chang ','Jing ','Lun ','Ling ','Zou ','Li ','Meng ','Zong ','Zhi ','Nian ','Shachi ','Dojou ','Sukesou ','Shi ','Shen ','Hun ','Shi ','Hou ','Xing ','Zhu ','La ','Zong ','Ji ','Bian ','Bian ',
);
<?php
$UTF8_TO_ASCII[0xc7] = array(
'Huan ','Quan ','Ze ','Wei ','Wei ','Yu ','Qun ','Rou ','Die ','Huang ','Lian ','Yan ','Qiu ','Qiu ','Jian ','Bi ','E ','Yang ','Fu ','Sai ','Jian ','Xia ','Tuo ','Hu ','Muroaji ','Ruo ','Haraka ','Wen ','Jian ','Hao ','Wu ','Fang ','Sao ','Liu ','Ma ','Shi ','Shi ','Yin ','Z ','Teng ','Ta ','Yao ','Ge ','Rong ','Qian ','Qi ','Wen ','Ruo ','Hatahata ','Lian ','Ao ','Le ','Hui ','Min ','Ji ','Tiao ','Qu ','Jian ','Sao ','Man ','Xi ','Qiu ','Biao ','Ji ','Ji ','Zhu ','Jiang ','Qiu ','Zhuan ','Yong ','Zhang ','Kang ','Xue ','Bie ','Jue ','Qu ','Xiang ','Bo ','Jiao ','Xun ','Su ','Huang ','Zun ','Shan ','Shan ','Fan ','Jue ','Lin ','Xun ','Miao ','Xi ','Eso ','Kyou ','Fen ','Guan ','Hou ','Kuai ','Zei ','Sao ','Zhan ','Gan ','Gui ','Sheng ','Li ','Chang ','Hatahata ','Shiira ','Mutsu ','Ru ','Ji ','Xu ','Huo ','Shiira ','Li ','Lie ','Li ','Mie ','Zhen ','Xiang ','E ','Lu ','Guan ','Li ','Xian ','Yu ','Dao ','Ji ','You ','Tun ','Lu ','Fang ','Ba ','He ','Bo ','Ping ','Nian ','Lu ','You ','Zha ','Fu ','Bo ','Bao ','Hou ','Pi ','Tai ','Gui ','Jie ','Kao ','Wei ','Er ','Tong ','Ze ','Hou ','Kuai ','Ji ','Jiao ','Xian ','Za ','Xiang ','Xun ','Geng ','Li ','Lian ','Jian ','Li ','Shi ','Tiao ','Gun ','Sha ','Wan ','Jun ','Ji ','Yong ','Qing ','Ling ','Qi ','Zou ','Fei ','Kun ','Chang ','Gu ','Ni ','Nian ','Diao ','Jing ','Shen ','Shi ','Zi ','Fen ','Die ','Bi ','Chang ','Shi ','Wen ','Wei ','Sai ','E ','Qiu ','Fu ','Huang ','Quan ','Jiang ','Bian ','Sao ','Ao ','Qi ','Ta ','Yin ','Yao ','Fang ','Jian ','Le ','Biao ','Xue ','Bie ','Man ','Min ','Yong ','Wei ','Xi ','Jue ','Shan ','Lin ','Zun ','Huo ','Gan ','Li ','Zhan ','Guan ','Niao ','Yi ','Fu ','Li ','Jiu ','Bu ','Yan ','Fu ','Diao ','Ji ','Feng ','Nio ','Gan ','Shi ','Feng ','Ming ','Bao ','Yuan ','Zhi ','Hu ','Qin ','Fu ','Fen ','Wen ','Jian ','Shi ','Yu ',
);
<?php
$UTF8_TO_ASCII[0xc8] = array(
'Fou ','Yiao ','Jue ','Jue ','Pi ','Huan ','Zhen ','Bao ','Yan ','Ya ','Zheng ','Fang ','Feng ','Wen ','Ou ','Te ','Jia ','Nu ','Ling ','Mie ','Fu ','Tuo ','Wen ','Li ','Bian ','Zhi ','Ge ','Yuan ','Zi ','Qu ','Xiao ','Zhi ','Dan ','Ju ','You ','Gu ','Zhong ','Yu ','Yang ','Rong ','Ya ','Tie ','Yu ','Shigi ','Ying ','Zhui ','Wu ','Er ','Gua ','Ai ','Zhi ','Yan ','Heng ','Jiao ','Ji ','Lie ','Zhu ','Ren ','Yi ','Hong ','Luo ','Ru ','Mou ','Ge ','Ren ','Jiao ','Xiu ','Zhou ','Zhi ','Luo ','Chidori ','Toki ','Ten ','Luan ','Jia ','Ji ','Yu ','Huan ','Tuo ','Bu ','Wu ','Juan ','Yu ','Bo ','Xun ','Xun ','Bi ','Xi ','Jun ','Ju ','Tu ','Jing ','Ti ','E ','E ','Kuang ','Hu ','Wu ','Shen ','Lai ','Ikaruga ','Kakesu ','Lu ','Ping ','Shu ','Fu ','An ','Zhao ','Peng ','Qin ','Qian ','Bei ','Diao ','Lu ','Que ','Jian ','Ju ','Tu ','Ya ','Yuan ','Qi ','Li ','Ye ','Zhui ','Kong ','Zhui ','Kun ','Sheng ','Qi ','Jing ','Yi ','Yi ','Jing ','Zi ','Lai ','Dong ','Qi ','Chun ','Geng ','Ju ','Qu ','Isuka ','Kikuitadaki ','Ji ','Shu ','[?] ','Chi ','Miao ','Rou ','An ','Qiu ','Ti ','Hu ','Ti ','E ','Jie ','Mao ','Fu ','Chun ','Tu ','Yan ','He ','Yuan ','Pian ','Yun ','Mei ','Hu ','Ying ','Dun ','Mu ','Ju ','Tsugumi ','Cang ','Fang ','Gu ','Ying ','Yuan ','Xuan ','Weng ','Shi ','He ','Chu ','Tang ','Xia ','Ruo ','Liu ','Ji ','Gu ','Jian ','Zhun ','Han ','Zi ','Zi ','Ni ','Yao ','Yan ','Ji ','Li ','Tian ','Kou ','Ti ','Ti ','Ni ','Tu ','Ma ','Jiao ','Gao ','Tian ','Chen ','Li ','Zhuan ','Zhe ','Ao ','Yao ','Yi ','Ou ','Chi ','Zhi ','Liao ','Rong ','Lou ','Bi ','Shuang ','Zhuo ','Yu ','Wu ','Jue ','Yin ','Quan ','Si ','Jiao ','Yi ','Hua ','Bi ','Ying ','Su ','Huang ','Fan ','Jiao ','Liao ','Yan ','Kao ','Jiu ','Xian ','Xian ','Tu ','Mai ','Zun ','Yu ','Ying ','Lu ','Tuan ','Xian ','Xue ','Yi ','Pi ',
);
<?php
$UTF8_TO_ASCII[0xc9] = array(
'Shu ','Luo ','Qi ','Yi ','Ji ','Zhe ','Yu ','Zhan ','Ye ','Yang ','Pi ','Ning ','Huo ','Mi ','Ying ','Meng ','Di ','Yue ','Yu ','Lei ','Bao ','Lu ','He ','Long ','Shuang ','Yue ','Ying ','Guan ','Qu ','Li ','Luan ','Niao ','Jiu ','Ji ','Yuan ','Ming ','Shi ','Ou ','Ya ','Cang ','Bao ','Zhen ','Gu ','Dong ','Lu ','Ya ','Xiao ','Yang ','Ling ','Zhi ','Qu ','Yuan ','Xue ','Tuo ','Si ','Zhi ','Er ','Gua ','Xiu ','Heng ','Zhou ','Ge ','Luan ','Hong ','Wu ','Bo ','Li ','Juan ','Hu ','E ','Yu ','Xian ','Ti ','Wu ','Que ','Miao ','An ','Kun ','Bei ','Peng ','Qian ','Chun ','Geng ','Yuan ','Su ','Hu ','He ','E ','Gu ','Qiu ','Zi ','Mei ','Mu ','Ni ','Yao ','Weng ','Liu ','Ji ','Ni ','Jian ','He ','Yi ','Ying ','Zhe ','Liao ','Liao ','Jiao ','Jiu ','Yu ','Lu ','Xuan ','Zhan ','Ying ','Huo ','Meng ','Guan ','Shuang ','Lu ','Jin ','Ling ','Jian ','Xian ','Cuo ','Jian ','Jian ','Yan ','Cuo ','Lu ','You ','Cu ','Ji ','Biao ','Cu ','Biao ','Zhu ','Jun ','Zhu ','Jian ','Mi ','Mi ','Wu ','Liu ','Chen ','Jun ','Lin ','Ni ','Qi ','Lu ','Jiu ','Jun ','Jing ','Li ','Xiang ','Yan ','Jia ','Mi ','Li ','She ','Zhang ','Lin ','Jing ','Ji ','Ling ','Yan ','Cu ','Mai ','Mai ','Ge ','Chao ','Fu ','Mian ','Mian ','Fu ','Pao ','Qu ','Qu ','Mou ','Fu ','Xian ','Lai ','Qu ','Mian ','[?] ','Feng ','Fu ','Qu ','Mian ','Ma ','Mo ','Mo ','Hui ','Ma ','Zou ','Nen ','Fen ','Huang ','Huang ','Jin ','Guang ','Tian ','Tou ','Heng ','Xi ','Kuang ','Heng ','Shu ','Li ','Nian ','Chi ','Hei ','Hei ','Yi ','Qian ','Dan ','Xi ','Tuan ','Mo ','Mo ','Qian ','Dai ','Chu ','You ','Dian ','Yi ','Xia ','Yan ','Qu ','Mei ','Yan ','Jing ','Yu ','Li ','Dang ','Du ','Can ','Yin ','An ','Yan ','Tan ','An ','Zhen ','Dai ','Can ','Yi ','Mei ','Dan ','Yan ','Du ','Lu ','Zhi ','Fen ','Fu ','Fu ','Min ','Min ','Yuan ',
);
<?php
$UTF8_TO_ASCII[0xca] = array(
'Cu ','Qu ','Chao ','Wa ','Zhu ','Zhi ','Mang ','Ao ','Bie ','Tuo ','Bi ','Yuan ','Chao ','Tuo ','Ding ','Mi ','Nai ','Ding ','Zi ','Gu ','Gu ','Dong ','Fen ','Tao ','Yuan ','Pi ','Chang ','Gao ','Qi ','Yuan ','Tang ','Teng ','Shu ','Shu ','Fen ','Fei ','Wen ','Ba ','Diao ','Tuo ','Tong ','Qu ','Sheng ','Shi ','You ','Shi ','Ting ','Wu ','Nian ','Jing ','Hun ','Ju ','Yan ','Tu ','Ti ','Xi ','Xian ','Yan ','Lei ','Bi ','Yao ','Qiu ','Han ','Wu ','Wu ','Hou ','Xi ','Ge ','Zha ','Xiu ','Weng ','Zha ','Nong ','Nang ','Qi ','Zhai ','Ji ','Zi ','Ji ','Ji ','Qi ','Ji ','Chi ','Chen ','Chen ','He ','Ya ','Ken ','Xie ','Pao ','Cuo ','Shi ','Zi ','Chi ','Nian ','Ju ','Tiao ','Ling ','Ling ','Chu ','Quan ','Xie ','Ken ','Nie ','Jiu ','Yao ','Chuo ','Kun ','Yu ','Chu ','Yi ','Ni ','Cuo ','Zou ','Qu ','Nen ','Xian ','Ou ','E ','Wo ','Yi ','Chuo ','Zou ','Dian ','Chu ','Jin ','Ya ','Chi ','Chen ','He ','Ken ','Ju ','Ling ','Pao ','Tiao ','Zi ','Ken ','Yu ','Chuo ','Qu ','Wo ','Long ','Pang ','Gong ','Pang ','Yan ','Long ','Long ','Gong ','Kan ','Ta ','Ling ','Ta ','Long ','Gong ','Kan ','Gui ','Qiu ','Bie ','Gui ','Yue ','Chui ','He ','Jue ','Xie ','Yu ','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0xcb] = array(
'it','ix','i','ip','iet','iex','ie','iep','at','ax','a','ap','uox','uo','uop','ot','ox','o','op','ex','e','wu','bit','bix','bi','bip','biet','biex','bie','biep','bat','bax','ba','bap','buox','buo','buop','bot','box','bo','bop','bex','be','bep','but','bux','bu','bup','burx','bur','byt','byx','by','byp','byrx','byr','pit','pix','pi','pip','piex','pie','piep','pat','pax','pa','pap','puox','puo','puop','pot','pox','po','pop','put','pux','pu','pup','purx','pur','pyt','pyx','py','pyp','pyrx','pyr','bbit','bbix','bbi','bbip','bbiet','bbiex','bbie','bbiep','bbat','bbax','bba','bbap','bbuox','bbuo','bbuop','bbot','bbox','bbo','bbop','bbex','bbe','bbep','bbut','bbux','bbu','bbup','bburx','bbur','bbyt','bbyx','bby','bbyp','nbit','nbix','nbi','nbip','nbiex','nbie','nbiep','nbat','nbax','nba','nbap','nbot','nbox','nbo','nbop','nbut','nbux','nbu','nbup','nburx','nbur','nbyt','nbyx','nby','nbyp','nbyrx','nbyr','hmit','hmix','hmi','hmip','hmiex','hmie','hmiep','hmat','hmax','hma','hmap','hmuox','hmuo','hmuop','hmot','hmox','hmo','hmop','hmut','hmux','hmu','hmup','hmurx','hmur','hmyx','hmy','hmyp','hmyrx','hmyr','mit','mix','mi','mip','miex','mie','miep','mat','max','ma','map','muot','muox','muo','muop','mot','mox','mo','mop','mex','me','mut','mux','mu','mup','murx','mur','myt','myx','my','myp','fit','fix','fi','fip','fat','fax','fa','fap','fox','fo','fop','fut','fux','fu','fup','furx','fur','fyt','fyx','fy','fyp','vit','vix','vi','vip','viet','viex','vie','viep','vat','vax','va','vap','vot','vox','vo','vop','vex','vep','vut','vux','vu','vup','vurx','vur','vyt','vyx','vy','vyp','vyrx','vyr',
);
<?php
$UTF8_TO_ASCII[0xcc] = array(
'dit','dix','di','dip','diex','die','diep','dat','dax','da','dap','duox','duo','dot','dox','do','dop','dex','de','dep','dut','dux','du','dup','durx','dur','tit','tix','ti','tip','tiex','tie','tiep','tat','tax','ta','tap','tuot','tuox','tuo','tuop','tot','tox','to','top','tex','te','tep','tut','tux','tu','tup','turx','tur','ddit','ddix','ddi','ddip','ddiex','ddie','ddiep','ddat','ddax','dda','ddap','dduox','dduo','dduop','ddot','ddox','ddo','ddop','ddex','dde','ddep','ddut','ddux','ddu','ddup','ddurx','ddur','ndit','ndix','ndi','ndip','ndiex','ndie','ndat','ndax','nda','ndap','ndot','ndox','ndo','ndop','ndex','nde','ndep','ndut','ndux','ndu','ndup','ndurx','ndur','hnit','hnix','hni','hnip','hniet','hniex','hnie','hniep','hnat','hnax','hna','hnap','hnuox','hnuo','hnot','hnox','hnop','hnex','hne','hnep','hnut','nit','nix','ni','nip','niex','nie','niep','nax','na','nap','nuox','nuo','nuop','not','nox','no','nop','nex','ne','nep','nut','nux','nu','nup','nurx','nur','hlit','hlix','hli','hlip','hliex','hlie','hliep','hlat','hlax','hla','hlap','hluox','hluo','hluop','hlox','hlo','hlop','hlex','hle','hlep','hlut','hlux','hlu','hlup','hlurx','hlur','hlyt','hlyx','hly','hlyp','hlyrx','hlyr','lit','lix','li','lip','liet','liex','lie','liep','lat','lax','la','lap','luot','luox','luo','luop','lot','lox','lo','lop','lex','le','lep','lut','lux','lu','lup','lurx','lur','lyt','lyx','ly','lyp','lyrx','lyr','git','gix','gi','gip','giet','giex','gie','giep','gat','gax','ga','gap','guot','guox','guo','guop','got','gox','go','gop','get','gex','ge','gep','gut','gux','gu','gup','gurx','gur','kit','kix','ki','kip','kiex','kie','kiep','kat',
);
<?php
$UTF8_TO_ASCII[0xcd] = array(
'kax','ka','kap','kuox','kuo','kuop','kot','kox','ko','kop','ket','kex','ke','kep','kut','kux','ku','kup','kurx','kur','ggit','ggix','ggi','ggiex','ggie','ggiep','ggat','ggax','gga','ggap','gguot','gguox','gguo','gguop','ggot','ggox','ggo','ggop','gget','ggex','gge','ggep','ggut','ggux','ggu','ggup','ggurx','ggur','mgiex','mgie','mgat','mgax','mga','mgap','mguox','mguo','mguop','mgot','mgox','mgo','mgop','mgex','mge','mgep','mgut','mgux','mgu','mgup','mgurx','mgur','hxit','hxix','hxi','hxip','hxiet','hxiex','hxie','hxiep','hxat','hxax','hxa','hxap','hxuot','hxuox','hxuo','hxuop','hxot','hxox','hxo','hxop','hxex','hxe','hxep','ngiex','ngie','ngiep','ngat','ngax','nga','ngap','nguot','nguox','nguo','ngot','ngox','ngo','ngop','ngex','nge','ngep','hit','hiex','hie','hat','hax','ha','hap','huot','huox','huo','huop','hot','hox','ho','hop','hex','he','hep','wat','wax','wa','wap','wuox','wuo','wuop','wox','wo','wop','wex','we','wep','zit','zix','zi','zip','ziex','zie','ziep','zat','zax','za','zap','zuox','zuo','zuop','zot','zox','zo','zop','zex','ze','zep','zut','zux','zu','zup','zurx','zur','zyt','zyx','zy','zyp','zyrx','zyr','cit','cix','ci','cip','ciet','ciex','cie','ciep','cat','cax','ca','cap','cuox','cuo','cuop','cot','cox','co','cop','cex','ce','cep','cut','cux','cu','cup','curx','cur','cyt','cyx','cy','cyp','cyrx','cyr','zzit','zzix','zzi','zzip','zziet','zziex','zzie','zziep','zzat','zzax','zza','zzap','zzox','zzo','zzop','zzex','zze','zzep','zzux','zzu','zzup','zzurx','zzur','zzyt','zzyx','zzy','zzyp','zzyrx','zzyr','nzit','nzix','nzi','nzip','nziex','nzie','nziep','nzat','nzax','nza','nzap','nzuox','nzuo','nzox','nzop','nzex','nze','nzux','nzu',
);
<?php
$UTF8_TO_ASCII[0xce] = array(
'nzup','nzurx','nzur','nzyt','nzyx','nzy','nzyp','nzyrx','nzyr','sit','six','si','sip','siex','sie','siep','sat','sax','sa','sap','suox','suo','suop','sot','sox','so','sop','sex','se','sep','sut','sux','su','sup','surx','sur','syt','syx','sy','syp','syrx','syr','ssit','ssix','ssi','ssip','ssiex','ssie','ssiep','ssat','ssax','ssa','ssap','ssot','ssox','sso','ssop','ssex','sse','ssep','ssut','ssux','ssu','ssup','ssyt','ssyx','ssy','ssyp','ssyrx','ssyr','zhat','zhax','zha','zhap','zhuox','zhuo','zhuop','zhot','zhox','zho','zhop','zhet','zhex','zhe','zhep','zhut','zhux','zhu','zhup','zhurx','zhur','zhyt','zhyx','zhy','zhyp','zhyrx','zhyr','chat','chax','cha','chap','chuot','chuox','chuo','chuop','chot','chox','cho','chop','chet','chex','che','chep','chux','chu','chup','churx','chur','chyt','chyx','chy','chyp','chyrx','chyr','rrax','rra','rruox','rruo','rrot','rrox','rro','rrop','rret','rrex','rre','rrep','rrut','rrux','rru','rrup','rrurx','rrur','rryt','rryx','rry','rryp','rryrx','rryr','nrat','nrax','nra','nrap','nrox','nro','nrop','nret','nrex','nre','nrep','nrut','nrux','nru','nrup','nrurx','nrur','nryt','nryx','nry','nryp','nryrx','nryr','shat','shax','sha','shap','shuox','shuo','shuop','shot','shox','sho','shop','shet','shex','she','shep','shut','shux','shu','shup','shurx','shur','shyt','shyx','shy','shyp','shyrx','shyr','rat','rax','ra','rap','ruox','ruo','ruop','rot','rox','ro','rop','rex','re','rep','rut','rux','ru','rup','rurx','rur','ryt','ryx','ry','ryp','ryrx','ryr','jit','jix','ji','jip','jiet','jiex','jie','jiep','juot','juox','juo','juop','jot','jox','jo','jop','jut','jux','ju','jup','jurx','jur','jyt','jyx','jy','jyp','jyrx','jyr','qit','qix','qi','qip',
);
<?php
$UTF8_TO_ASCII[0xcf] = array(
'qiet','qiex','qie','qiep','quot','quox','quo','quop','qot','qox','qo','qop','qut','qux','qu','qup','qurx','qur','qyt','qyx','qy','qyp','qyrx','qyr','jjit','jjix','jji','jjip','jjiet','jjiex','jjie','jjiep','jjuox','jjuo','jjuop','jjot','jjox','jjo','jjop','jjut','jjux','jju','jjup','jjurx','jjur','jjyt','jjyx','jjy','jjyp','njit','njix','nji','njip','njiet','njiex','njie','njiep','njuox','njuo','njot','njox','njo','njop','njux','nju','njup','njurx','njur','njyt','njyx','njy','njyp','njyrx','njyr','nyit','nyix','nyi','nyip','nyiet','nyiex','nyie','nyiep','nyuox','nyuo','nyuop','nyot','nyox','nyo','nyop','nyut','nyux','nyu','nyup','xit','xix','xi','xip','xiet','xiex','xie','xiep','xuox','xuo','xot','xox','xo','xop','xyt','xyx','xy','xyp','xyrx','xyr','yit','yix','yi','yip','yiet','yiex','yie','yiep','yuot','yuox','yuo','yuop','yot','yox','yo','yop','yut','yux','yu','yup','yurx','yur','yyt','yyx','yy','yyp','yyrx','yyr','[?]','[?]','[?]','Qot','Li','Kit','Nyip','Cyp','Ssi','Ggop','Gep','Mi','Hxit','Lyr','Bbut','Mop','Yo','Put','Hxuo','Tat','Ga','[?]','[?]','Ddur','Bur','Gguo','Nyop','Tu','Op','Jjut','Zot','Pyt','Hmo','Yit','Vur','Shy','Vep','Za','Jo','[?]','Jjy','Got','Jjie','Wo','Du','Shur','Lie','Cy','Cuop','Cip','Hxop','Shat','[?]','Shop','Che','Zziet','[?]','Ke','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]','[?]',
);
<?php
$UTF8_TO_ASCII[0xd0] = array(
);
<?php
$UTF8_TO_ASCII[0xd1] = array(
);
<?php
$UTF8_TO_ASCII[0xd2] = array(
);
<?php
$UTF8_TO_ASCII[0xd3] = array(
);
<?php
$UTF8_TO_ASCII[0xd4] = array(
);
<?php
$UTF8_TO_ASCII[0xd5] = array(
);
<?php
$UTF8_TO_ASCII[0xd6] = array(
);
<?php
$UTF8_TO_ASCII[0xd7] = array(
'ga','gag','gagg','gags','gan','ganj','ganh','gad','gal','galg','galm','galb','gals','galt','galp','galh','gam','gab','gabs','gas','gass','gang','gaj','gac','gak','gat','gap','gah','gae','gaeg','gaegg','gaegs','gaen','gaenj','gaenh','gaed','gael','gaelg','gaelm','gaelb','gaels','gaelt','gaelp','gaelh','gaem','gaeb','gaebs','gaes','gaess','gaeng','gaej','gaec','gaek','gaet','gaep','gaeh','gya','gyag','gyagg','gyags','gyan','gyanj','gyanh','gyad','gyal','gyalg','gyalm','gyalb','gyals','gyalt','gyalp','gyalh','gyam','gyab','gyabs','gyas','gyass','gyang','gyaj','gyac','gyak','gyat','gyap','gyah','gyae','gyaeg','gyaegg','gyaegs','gyaen','gyaenj','gyaenh','gyaed','gyael','gyaelg','gyaelm','gyaelb','gyaels','gyaelt','gyaelp','gyaelh','gyaem','gyaeb','gyaebs','gyaes','gyaess','gyaeng','gyaej','gyaec','gyaek','gyaet','gyaep','gyaeh','geo','geog','geogg','geogs','geon','geonj','geonh','geod','geol','geolg','geolm','geolb','geols','geolt','geolp','geolh','geom','geob','geobs','geos','geoss','geong','geoj','geoc','geok','geot','geop','geoh','ge','geg','gegg','gegs','gen','genj','genh','ged','gel','gelg','gelm','gelb','gels','gelt','gelp','gelh','gem','geb','gebs','ges','gess','geng','gej','gec','gek','get','gep','geh','gyeo','gyeog','gyeogg','gyeogs','gyeon','gyeonj','gyeonh','gyeod','gyeol','gyeolg','gyeolm','gyeolb','gyeols','gyeolt','gyeolp','gyeolh','gyeom','gyeob','gyeobs','gyeos','gyeoss','gyeong','gyeoj','gyeoc','gyeok','gyeot','gyeop','gyeoh','gye','gyeg','gyegg','gyegs','gyen','gyenj','gyenh','gyed','gyel','gyelg','gyelm','gyelb','gyels','gyelt','gyelp','gyelh','gyem','gyeb','gyebs','gyes','gyess','gyeng','gyej','gyec','gyek','gyet','gyep','gyeh','go','gog','gogg','gogs','gon','gonj','gonh','god','gol','golg','golm','golb','gols','golt','golp','golh','gom','gob','gobs','gos','goss','gong','goj','goc','gok','got','gop','goh','gwa','gwag','gwagg','gwags',
);
<?php
$UTF8_TO_ASCII[0xf9] = array(
'gwan','gwanj','gwanh','gwad','gwal','gwalg','gwalm','gwalb','gwals','gwalt','gwalp','gwalh','gwam','gwab','gwabs','gwas','gwass','gwang','gwaj','gwac','gwak','gwat','gwap','gwah','gwae','gwaeg','gwaegg','gwaegs','gwaen','gwaenj','gwaenh','gwaed','gwael','gwaelg','gwaelm','gwaelb','gwaels','gwaelt','gwaelp','gwaelh','gwaem','gwaeb','gwaebs','gwaes','gwaess','gwaeng','gwaej','gwaec','gwaek','gwaet','gwaep','gwaeh','goe','goeg','goegg','goegs','goen','goenj','goenh','goed','goel','goelg','goelm','goelb','goels','goelt','goelp','goelh','goem','goeb','goebs','goes','goess','goeng','goej','goec','goek','goet','goep','goeh','gyo','gyog','gyogg','gyogs','gyon','gyonj','gyonh','gyod','gyol','gyolg','gyolm','gyolb','gyols','gyolt','gyolp','gyolh','gyom','gyob','gyobs','gyos','gyoss','gyong','gyoj','gyoc','gyok','gyot','gyop','gyoh','gu','gug','gugg','gugs','gun','gunj','gunh','gud','gul','gulg','gulm','gulb','guls','gult','gulp','gulh','gum','gub','gubs','gus','guss','gung','guj','guc','guk','gut','gup','guh','gweo','gweog','gweogg','gweogs','gweon','gweonj','gweonh','gweod','gweol','gweolg','gweolm','gweolb','gweols','gweolt','gweolp','gweolh','gweom','gweob','gweobs','gweos','gweoss','gweong','gweoj','gweoc','gweok','gweot','gweop','gweoh','gwe','gweg','gwegg','gwegs','gwen','gwenj','gwenh','gwed','gwel','gwelg','gwelm','gwelb','gwels','gwelt','gwelp','gwelh','gwem','gweb','gwebs','gwes','gwess','gweng','gwej','gwec','gwek','gwet','gwep','gweh','gwi','gwig','gwigg','gwigs','gwin','gwinj','gwinh','gwid','gwil','gwilg','gwilm','gwilb','gwils','gwilt','gwilp','gwilh','gwim','gwib','gwibs','gwis','gwiss','gwing','gwij','gwic','gwik','gwit','gwip','gwih','gyu','gyug','gyugg','gyugs','gyun','gyunj','gyunh','gyud','gyul','gyulg','gyulm','gyulb','gyuls','gyult','gyulp','gyulh','gyum','gyub','gyubs','gyus','gyuss','gyung','gyuj','gyuc','gyuk','gyut','gyup','gyuh','geu','geug','geugg','geugs','geun','geunj','geunh','geud',
);
<?php
$UTF8_TO_ASCII[0xfa] = array(
'geul','geulg','geulm','geulb','geuls','geult','geulp','geulh','geum','geub','geubs','geus','geuss','geung','geuj','geuc','geuk','geut','geup','geuh','gyi','gyig','gyigg','gyigs','gyin','gyinj','gyinh','gyid','gyil','gyilg','gyilm','gyilb','gyils','gyilt','gyilp','gyilh','gyim','gyib','gyibs','gyis','gyiss','gying','gyij','gyic','gyik','gyit','gyip','gyih','gi','gig','gigg','gigs','gin','ginj','ginh','gid','gil','gilg','gilm','gilb','gils','gilt','gilp','gilh','gim','gib','gibs','gis','giss','ging','gij','gic','gik','git','gip','gih','gga','ggag','ggagg','ggags','ggan','gganj','gganh','ggad','ggal','ggalg','ggalm','ggalb','ggals','ggalt','ggalp','ggalh','ggam','ggab','ggabs','ggas','ggass','ggang','ggaj','ggac','ggak','ggat','ggap','ggah','ggae','ggaeg','ggaegg','ggaegs','ggaen','ggaenj','ggaenh','ggaed','ggael','ggaelg','ggaelm','ggaelb','ggaels','ggaelt','ggaelp','ggaelh','ggaem','ggaeb','ggaebs','ggaes','ggaess','ggaeng','ggaej','ggaec','ggaek','ggaet','ggaep','ggaeh','ggya','ggyag','ggyagg','ggyags','ggyan','ggyanj','ggyanh','ggyad','ggyal','ggyalg','ggyalm','ggyalb','ggyals','ggyalt','ggyalp','ggyalh','ggyam','ggyab','ggyabs','ggyas','ggyass','ggyang','ggyaj','ggyac','ggyak','ggyat','ggyap','ggyah','ggyae','ggyaeg','ggyaegg','ggyaegs','ggyaen','ggyaenj','ggyaenh','ggyaed','ggyael','ggyaelg','ggyaelm','ggyaelb','ggyaels','ggyaelt','ggyaelp','ggyaelh','ggyaem','ggyaeb','ggyaebs','ggyaes','ggyaess','ggyaeng','ggyaej','ggyaec','ggyaek','ggyaet','ggyaep','ggyaeh','ggeo','ggeog','ggeogg','ggeogs','ggeon','ggeonj','ggeonh','ggeod','ggeol','ggeolg','ggeolm','ggeolb','ggeols','ggeolt','ggeolp','ggeolh','ggeom','ggeob','ggeobs','ggeos','ggeoss','ggeong','ggeoj','ggeoc','ggeok','ggeot','ggeop','ggeoh','gge','ggeg','ggegg','ggegs','ggen','ggenj','ggenh','gged','ggel','ggelg','ggelm','ggelb','ggels','ggelt','ggelp','ggelh','ggem','ggeb','ggebs','gges','ggess','ggeng','ggej','ggec','ggek','gget','ggep','ggeh','ggyeo','ggyeog','ggyeogg','ggyeogs','ggyeon','ggyeonj','ggyeonh','ggyeod','ggyeol','ggyeolg','ggyeolm','ggyeolb',
);
<?php
$UTF8_TO_ASCII[0xfb] = array(
'ggyeols','ggyeolt','ggyeolp','ggyeolh','ggyeom','ggyeob','ggyeobs','ggyeos','ggyeoss','ggyeong','ggyeoj','ggyeoc','ggyeok','ggyeot','ggyeop','ggyeoh','ggye','ggyeg','ggyegg','ggyegs','ggyen','ggyenj','ggyenh','ggyed','ggyel','ggyelg','ggyelm','ggyelb','ggyels','ggyelt','ggyelp','ggyelh','ggyem','ggyeb','ggyebs','ggyes','ggyess','ggyeng','ggyej','ggyec','ggyek','ggyet','ggyep','ggyeh','ggo','ggog','ggogg','ggogs','ggon','ggonj','ggonh','ggod','ggol','ggolg','ggolm','ggolb','ggols','ggolt','ggolp','ggolh','ggom','ggob','ggobs','ggos','ggoss','ggong','ggoj','ggoc','ggok','ggot','ggop','ggoh','ggwa','ggwag','ggwagg','ggwags','ggwan','ggwanj','ggwanh','ggwad','ggwal','ggwalg','ggwalm','ggwalb','ggwals','ggwalt','ggwalp','ggwalh','ggwam','ggwab','ggwabs','ggwas','ggwass','ggwang','ggwaj','ggwac','ggwak','ggwat','ggwap','ggwah','ggwae','ggwaeg','ggwaegg','ggwaegs','ggwaen','ggwaenj','ggwaenh','ggwaed','ggwael','ggwaelg','ggwaelm','ggwaelb','ggwaels','ggwaelt','ggwaelp','ggwaelh','ggwaem','ggwaeb','ggwaebs','ggwaes','ggwaess','ggwaeng','ggwaej','ggwaec','ggwaek','ggwaet','ggwaep','ggwaeh','ggoe','ggoeg','ggoegg','ggoegs','ggoen','ggoenj','ggoenh','ggoed','ggoel','ggoelg','ggoelm','ggoelb','ggoels','ggoelt','ggoelp','ggoelh','ggoem','ggoeb','ggoebs','ggoes','ggoess','ggoeng','ggoej','ggoec','ggoek','ggoet','ggoep','ggoeh','ggyo','ggyog','ggyogg','ggyogs','ggyon','ggyonj','ggyonh','ggyod','ggyol','ggyolg','ggyolm','ggyolb','ggyols','ggyolt','ggyolp','ggyolh','ggyom','ggyob','ggyobs','ggyos','ggyoss','ggyong','ggyoj','ggyoc','ggyok','ggyot','ggyop','ggyoh','ggu','ggug','ggugg','ggugs','ggun','ggunj','ggunh','ggud','ggul','ggulg','ggulm','ggulb','gguls','ggult','ggulp','ggulh','ggum','ggub','ggubs','ggus','gguss','ggung','gguj','gguc','gguk','ggut','ggup','gguh','ggweo','ggweog','ggweogg','ggweogs','ggweon','ggweonj','ggweonh','ggweod','ggweol','ggweolg','ggweolm','ggweolb','ggweols','ggweolt','ggweolp','ggweolh','ggweom','ggweob','ggweobs','ggweos','ggweoss','ggweong','ggweoj','ggweoc','ggweok','ggweot','ggweop','ggweoh','ggwe','ggweg','ggwegg','ggwegs','ggwen','ggwenj','ggwenh','ggwed','ggwel','ggwelg','ggwelm','ggwelb','ggwels','ggwelt','ggwelp','ggwelh',
);
<?php
$UTF8_TO_ASCII[0xfc] = array(
'ggwem','ggweb','ggwebs','ggwes','ggwess','ggweng','ggwej','ggwec','ggwek','ggwet','ggwep','ggweh','ggwi','ggwig','ggwigg','ggwigs','ggwin','ggwinj','ggwinh','ggwid','ggwil','ggwilg','ggwilm','ggwilb','ggwils','ggwilt','ggwilp','ggwilh','ggwim','ggwib','ggwibs','ggwis','ggwiss','ggwing','ggwij','ggwic','ggwik','ggwit','ggwip','ggwih','ggyu','ggyug','ggyugg','ggyugs','ggyun','ggyunj','ggyunh','ggyud','ggyul','ggyulg','ggyulm','ggyulb','ggyuls','ggyult','ggyulp','ggyulh','ggyum','ggyub','ggyubs','ggyus','ggyuss','ggyung','ggyuj','ggyuc','ggyuk','ggyut','ggyup','ggyuh','ggeu','ggeug','ggeugg','ggeugs','ggeun','ggeunj','ggeunh','ggeud','ggeul','ggeulg','ggeulm','ggeulb','ggeuls','ggeult','ggeulp','ggeulh','ggeum','ggeub','ggeubs','ggeus','ggeuss','ggeung','ggeuj','ggeuc','ggeuk','ggeut','ggeup','ggeuh','ggyi','ggyig','ggyigg','ggyigs','ggyin','ggyinj','ggyinh','ggyid','ggyil','ggyilg','ggyilm','ggyilb','ggyils','ggyilt','ggyilp','ggyilh','ggyim','ggyib','ggyibs','ggyis','ggyiss','ggying','ggyij','ggyic','ggyik','ggyit','ggyip','ggyih','ggi','ggig','ggigg','ggigs','ggin','gginj','gginh','ggid','ggil','ggilg','ggilm','ggilb','ggils','ggilt','ggilp','ggilh','ggim','ggib','ggibs','ggis','ggiss','gging','ggij','ggic','ggik','ggit','ggip','ggih','na','nag','nagg','nags','nan','nanj','nanh','nad','nal','nalg','nalm','nalb','nals','nalt','nalp','nalh','nam','nab','nabs','nas','nass','nang','naj','nac','nak','nat','nap','nah','nae','naeg','naegg','naegs','naen','naenj','naenh','naed','nael','naelg','naelm','naelb','naels','naelt','naelp','naelh','naem','naeb','naebs','naes','naess','naeng','naej','naec','naek','naet','naep','naeh','nya','nyag','nyagg','nyags','nyan','nyanj','nyanh','nyad','nyal','nyalg','nyalm','nyalb','nyals','nyalt','nyalp','nyalh','nyam','nyab','nyabs','nyas','nyass','nyang','nyaj','nyac','nyak','nyat','nyap','nyah','nyae','nyaeg','nyaegg','nyaegs','nyaen','nyaenj','nyaenh','nyaed','nyael','nyaelg','nyaelm','nyaelb','nyaels','nyaelt','nyaelp','nyaelh','nyaem','nyaeb','nyaebs','nyaes',
);
<?php
$UTF8_TO_ASCII[0xfd] = array(
'nyaess','nyaeng','nyaej','nyaec','nyaek','nyaet','nyaep','nyaeh','neo','neog','neogg','neogs','neon','neonj','neonh','neod','neol','neolg','neolm','neolb','neols','neolt','neolp','neolh','neom','neob','neobs','neos','neoss','neong','neoj','neoc','neok','neot','neop','neoh','ne','neg','negg','negs','nen','nenj','nenh','ned','nel','nelg','nelm','nelb','nels','nelt','nelp','nelh','nem','neb','nebs','nes','ness','neng','nej','nec','nek','net','nep','neh','nyeo','nyeog','nyeogg','nyeogs','nyeon','nyeonj','nyeonh','nyeod','nyeol','nyeolg','nyeolm','nyeolb','nyeols','nyeolt','nyeolp','nyeolh','nyeom','nyeob','nyeobs','nyeos','nyeoss','nyeong','nyeoj','nyeoc','nyeok','nyeot','nyeop','nyeoh','nye','nyeg','nyegg','nyegs','nyen','nyenj','nyenh','nyed','nyel','nyelg','nyelm','nyelb','nyels','nyelt','nyelp','nyelh','nyem','nyeb','nyebs','nyes','nyess','nyeng','nyej','nyec','nyek','nyet','nyep','nyeh','no','nog','nogg','nogs','non','nonj','nonh','nod','nol','nolg','nolm','nolb','nols','nolt','nolp','nolh','nom','nob','nobs','nos','noss','nong','noj','noc','nok','not','nop','noh','nwa','nwag','nwagg','nwags','nwan','nwanj','nwanh','nwad','nwal','nwalg','nwalm','nwalb','nwals','nwalt','nwalp','nwalh','nwam','nwab','nwabs','nwas','nwass','nwang','nwaj','nwac','nwak','nwat','nwap','nwah','nwae','nwaeg','nwaegg','nwaegs','nwaen','nwaenj','nwaenh','nwaed','nwael','nwaelg','nwaelm','nwaelb','nwaels','nwaelt','nwaelp','nwaelh','nwaem','nwaeb','nwaebs','nwaes','nwaess','nwaeng','nwaej','nwaec','nwaek','nwaet','nwaep','nwaeh','noe','noeg','noegg','noegs','noen','noenj','noenh','noed','noel','noelg','noelm','noelb','noels','noelt','noelp','noelh','noem','noeb','noebs','noes','noess','noeng','noej','noec','noek','noet','noep','noeh','nyo','nyog','nyogg','nyogs','nyon','nyonj','nyonh','nyod','nyol','nyolg','nyolm','nyolb','nyols','nyolt','nyolp','nyolh','nyom','nyob','nyobs','nyos','nyoss','nyong','nyoj','nyoc',
);
<?php
$UTF8_TO_ASCII[0xfe] = array(
'nyok','nyot','nyop','nyoh','nu','nug','nugg','nugs','nun','nunj','nunh','nud','nul','nulg','nulm','nulb','nuls','nult','nulp','nulh','num','nub','nubs','nus','nuss','nung','nuj','nuc','nuk','nut','nup','nuh','nweo','nweog','nweogg','nweogs','nweon','nweonj','nweonh','nweod','nweol','nweolg','nweolm','nweolb','nweols','nweolt','nweolp','nweolh','nweom','nweob','nweobs','nweos','nweoss','nweong','nweoj','nweoc','nweok','nweot','nweop','nweoh','nwe','nweg','nwegg','nwegs','nwen','nwenj','nwenh','nwed','nwel','nwelg','nwelm','nwelb','nwels','nwelt','nwelp','nwelh','nwem','nweb','nwebs','nwes','nwess','nweng','nwej','nwec','nwek','nwet','nwep','nweh','nwi','nwig','nwigg','nwigs','nwin','nwinj','nwinh','nwid','nwil','nwilg','nwilm','nwilb','nwils','nwilt','nwilp','nwilh','nwim','nwib','nwibs','nwis','nwiss','nwing','nwij','nwic','nwik','nwit','nwip','nwih','nyu','nyug','nyugg','nyugs','nyun','nyunj','nyunh','nyud','nyul','nyulg','nyulm','nyulb','nyuls','nyult','nyulp','nyulh','nyum','nyub','nyubs','nyus','nyuss','nyung','nyuj','nyuc','nyuk','nyut','nyup','nyuh','neu','neug','neugg','neugs','neun','neunj','neunh','neud','neul','neulg','neulm','neulb','neuls','neult','neulp','neulh','neum','neub','neubs','neus','neuss','neung','neuj','neuc','neuk','neut','neup','neuh','nyi','nyig','nyigg','nyigs','nyin','nyinj','nyinh','nyid','nyil','nyilg','nyilm','nyilb','nyils','nyilt','nyilp','nyilh','nyim','nyib','nyibs','nyis','nyiss','nying','nyij','nyic','nyik','nyit','nyip','nyih','ni','nig','nigg','nigs','nin','ninj','ninh','nid','nil','nilg','nilm','nilb','nils','nilt','nilp','nilh','nim','nib','nibs','nis','niss','ning','nij','nic','nik','nit','nip','nih','da','dag','dagg','dags','dan','danj','danh','dad','dal','dalg','dalm','dalb','dals','dalt','dalp','dalh','dam','dab','dabs','das','dass','dang','daj','dac','dak','dat','dap','dah',
);
<?php
$UTF8_TO_ASCII[0xff] = array(
'dae','daeg','daegg','daegs','daen','daenj','daenh','daed','dael','daelg','daelm','daelb','daels','daelt','daelp','daelh','daem','daeb','daebs','daes','daess','daeng','daej','daec','daek','daet','daep','daeh','dya','dyag','dyagg','dyags','dyan','dyanj','dyanh','dyad','dyal','dyalg','dyalm','dyalb','dyals','dyalt','dyalp','dyalh','dyam','dyab','dyabs','dyas','dyass','dyang','dyaj','dyac','dyak','dyat','dyap','dyah','dyae','dyaeg','dyaegg','dyaegs','dyaen','dyaenj','dyaenh','dyaed','dyael','dyaelg','dyaelm','dyaelb','dyaels','dyaelt','dyaelp','dyaelh','dyaem','dyaeb','dyaebs','dyaes','dyaess','dyaeng','dyaej','dyaec','dyaek','dyaet','dyaep','dyaeh','deo','deog','deogg','deogs','deon','deonj','deonh','deod','deol','deolg','deolm','deolb','deols','deolt','deolp','deolh','deom','deob','deobs','deos','deoss','deong','deoj','deoc','deok','deot','deop','deoh','de','deg','degg','degs','den','denj','denh','ded','del','delg','delm','delb','dels','delt','delp','delh','dem','deb','debs','des','dess','deng','dej','dec','dek','det','dep','deh','dyeo','dyeog','dyeogg','dyeogs','dyeon','dyeonj','dyeonh','dyeod','dyeol','dyeolg','dyeolm','dyeolb','dyeols','dyeolt','dyeolp','dyeolh','dyeom','dyeob','dyeobs','dyeos','dyeoss','dyeong','dyeoj','dyeoc','dyeok','dyeot','dyeop','dyeoh','dye','dyeg','dyegg','dyegs','dyen','dyenj','dyenh','dyed','dyel','dyelg','dyelm','dyelb','dyels','dyelt','dyelp','dyelh','dyem','dyeb','dyebs','dyes','dyess','dyeng','dyej','dyec','dyek','dyet','dyep','dyeh','do','dog','dogg','dogs','don','donj','donh','dod','dol','dolg','dolm','dolb','dols','dolt','dolp','dolh','dom','dob','dobs','dos','doss','dong','doj','doc','dok','dot','dop','doh','dwa','dwag','dwagg','dwags','dwan','dwanj','dwanh','dwad','dwal','dwalg','dwalm','dwalb','dwals','dwalt','dwalp','dwalh','dwam','dwab','dwabs','dwas','dwass','dwang','dwaj','dwac','dwak','dwat','dwap','dwah','dwae','dwaeg','dwaegg','dwaegs',
);
The "Artistic License"
Preamble
The intent of this document is to state the conditions under which a
Package may be copied, such that the Copyright Holder maintains some
semblance of artistic control over the development of the package,
while giving the users of the package the right to use and distribute
the Package in a more-or-less customary fashion, plus the right to make
reasonable modifications.
Definitions:
"Package" refers to the collection of files distributed by the
Copyright Holder, and derivatives of that collection of files
created through textual modification.
"Standard Version" refers to such a Package if it has not been
modified, or has been modified in accordance with the wishes
of the Copyright Holder as specified below.
"Copyright Holder" is whoever is named in the copyright or
copyrights for the package.
"You" is you, if you're thinking about copying or distributing
this Package.
"Reasonable copying fee" is whatever you can justify on the
basis of media cost, duplication charges, time of people involved,
and so on. (You will not be required to justify it to the
Copyright Holder, but only to the computing community at large
as a market that must bear the fee.)
"Freely Available" means that no fee is charged for the item
itself, though there may be fees involved in handling the item.
It also means that recipients of the item may redistribute it
under the same conditions they received it.
1. You may make and give away verbatim copies of the source form of the
Standard Version of this Package without restriction, provided that you
duplicate all of the original copyright notices and associated disclaimers.
2. You may apply bug fixes, portability fixes and other modifications
derived from the Public Domain or from the Copyright Holder. A Package
modified in such a way shall still be considered the Standard Version.
3. You may otherwise modify your copy of this Package in any way, provided
that you insert a prominent notice in each changed file stating how and
when you changed that file, and provided that you do at least ONE of the
following:
a) place your modifications in the Public Domain or otherwise make them
Freely Available, such as by posting said modifications to Usenet or
an equivalent medium, or placing the modifications on a major archive
site such as uunet.uu.net, or by allowing the Copyright Holder to include
your modifications in the Standard Version of the Package.
b) use the modified Package only within your corporation or organization.
c) rename any non-standard executables so the names do not conflict
with standard executables, which must also be provided, and provide
a separate manual page for each non-standard executable that clearly
documents how it differs from the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
4. You may distribute the programs of this Package in object code or
executable form, provided that you do at least ONE of the following:
a) distribute a Standard Version of the executables and library files,
together with instructions (in the manual page or equivalent) on where
to get the Standard Version.
b) accompany the distribution with the machine-readable source of
the Package with your modifications.
c) give non-standard executables non-standard names, and clearly
document the differences in manual pages (or equivalent), together
with instructions on where to get the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
5. You may charge a reasonable copying fee for any distribution of this
Package. You may charge any fee you choose for support of this
Package. You may not charge a fee for this Package itself. However,
you may distribute this Package in aggregate with other (possibly
commercial) programs as part of a larger (possibly commercial) software
distribution provided that you do not advertise this Package as a
product of your own. You may embed this Package's interpreter within
an executable of yours (by linking); this shall be construed as a mere
form of aggregation, provided that the complete Standard Version of the
interpreter is so embedded.
6. The scripts and library files supplied as input to or produced as
output from the programs of this Package do not automatically fall
under the copyright of this Package, but belong to whoever generated
them, and may be sold commercially, and may be aggregated with this
Package. If such scripts or library files are aggregated with this
Package via the so-called "undump" or "unexec" methods of producing a
binary executable image, then distribution of such an image shall
neither be construed as a distribution of this Package nor shall it
fall under the restrictions of Paragraphs 3 and 4, provided that you do
not represent such an executable image as a Standard Version of this
Package.
7. C subroutines (or comparably compiled subroutines in other
languages) supplied by you and linked into this Package in order to
emulate subroutines and variables of the language defined by this
Package shall not be considered part of this Package, but are the
equivalent of input as in Paragraph 6, provided these subroutines do
not change the language in any way that would cause it to fail the
regression tests for the language.
8. Aggregation of this Package with a commercial distribution is always
permitted provided that the use of this Package is embedded; that is,
when no overt attempt is made to make this Package's interfaces visible
to the end user of the commercial distribution. Such use shall not be
construed as a distribution of this Package.
9. The name of the Copyright Holder may not be used to endorse or promote
products derived from this software without specific prior written permission.
10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
The End
<?php
namespace Behat\Behat\Util;
/**
* This is the part taken from Doctrine 1.2.3
* Doctrine inflector has static methods for inflecting text
*
* The methods in these classes are from several different sources collected
* across several different php projects and several different authors. The
* original author names and emails are not known
*
* Uses 3rd party libraries and functions:
* http://sourceforge.net/projects/phputf8
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 1.0
* @version $Revision: 3189 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author <hsivonen@iki.fi>
*/
class Transliterator
{
/**
* Check if a string has utf7 characters in it
*
* By bmorel at ssi dot fr
*
* @param string $string
* @return boolean $bool
*/
public static function seemsUtf8($string)
{
for ($i = 0; $i < strlen($string); $i++) {
if (ord($string[$i]) < 0x80) continue; # 0bbbbbbb
elseif ((ord($string[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
elseif ((ord($string[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
elseif ((ord($string[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
elseif ((ord($string[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
elseif ((ord($string[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
else return false; # Does not match any model
for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
if ((++$i == strlen($string)) || ((ord($string[$i]) & 0xC0) != 0x80))
return false;
}
}
return true;
}
/**
* Remove any illegal characters, accents, etc.
*
* @param string $string String to unaccent
* @return string $string Unaccented string
*/
public static function unaccent($string)
{
if (!preg_match('/[\x80-\xff]/', $string)) {
return $string;
}
if (self::seemsUtf8($string)) {
$chars = array(
// Decompositions for Latin-1 Supplement
chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
chr(195).chr(191) => 'y',
// Decompositions for Latin Extended-A
chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
chr(197).chr(148) => 'R', chr(197).chr(149) => 'r',
chr(197).chr(150) => 'R', chr(197).chr(151) => 'r',
chr(197).chr(152) => 'R', chr(197).chr(153) => 'r',
chr(197).chr(154) => 'S', chr(197).chr(155) => 's',
chr(197).chr(156) => 'S', chr(197).chr(157) => 's',
chr(197).chr(158) => 'S', chr(197).chr(159) => 's',
chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
chr(197).chr(190) => 'z', chr(197).chr(191) => 's',
// Euro Sign
chr(226).chr(130).chr(172) => 'E',
// GBP (Pound) Sign
chr(194).chr(163) => '',
'Ä' => 'Ae', 'ä' => 'ae', 'Ü' => 'Ue', 'ü' => 'ue',
'Ö' => 'Oe', 'ö' => 'oe', 'ß' => 'ss',
// Norwegian characters
'Å'=>'Aa','Æ'=>'Ae','Ø'=>'O','æ'=>'a','ø'=>'o','å'=>'aa'
);
$string = strtr($string, $chars);
} else {
// Assume ISO-8859-1 if not UTF-8
$chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
.chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
.chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
.chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
.chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
.chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
.chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
.chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
.chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
.chr(252).chr(253).chr(255);
$chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
$string = strtr($string, $chars['in'], $chars['out']);
$doubleChars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
$doubleChars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
$string = str_replace($doubleChars['in'], $doubleChars['out'], $string);
}
return $string;
}
/**
* US-ASCII transliterations of Unicode text
* Ported Sean M. Burke's Text::Unidecode Perl module (He did all the hard work!)
* Warning: you should only pass this well formed UTF-8!
* Be aware it works by making a copy of the input string which it appends transliterated
* characters to - it uses a PHP output buffer to do this - it means, memory use will increase,
* requiring up to the same amount again as the input string
*
* @see http://search.cpan.org/~sburke/Text-Unidecode-0.04/lib/Text/Unidecode.pm
* @param string UTF-8 string to convert
* @author <hsivonen@iki.fi>
* @param string (default = ?) Character use if character unknown
* @return string US-ASCII string
*/
public static function utf8ToAscii($str, $unknown = '?')
{
static $UTF8_TO_ASCII;
if (strlen($str) == 0) {
return;
}
preg_match_all('/.{1}|[^\x00]{1,1}$/us', $str, $ar);
$chars = $ar[0];
foreach ($chars as $i => $c) {
$ud = 0;
if (ord($c{0})>=0 && ord($c{0})<=127) { continue; } // ASCII - next please
if (ord($c{0})>=192 && ord($c{0})<=223) { $ord = (ord($c{0})-192)*64 + (ord($c{1})-128); }
if (ord($c{0})>=224 && ord($c{0})<=239) { $ord = (ord($c{0})-224)*4096 + (ord($c{1})-128)*64 + (ord($c{2})-128); }
if (ord($c{0})>=240 && ord($c{0})<=247) { $ord = (ord($c{0})-240)*262144 + (ord($c{1})-128)*4096 + (ord($c{2})-128)*64 + (ord($c{3})-128); }
if (ord($c{0})>=248 && ord($c{0})<=251) { $ord = (ord($c{0})-248)*16777216 + (ord($c{1})-128)*262144 + (ord($c{2})-128)*4096 + (ord($c{3})-128)*64 + (ord($c{4})-128); }
if (ord($c{0})>=252 && ord($c{0})<=253) { $ord = (ord($c{0})-252)*1073741824 + (ord($c{1})-128)*16777216 + (ord($c{2})-128)*262144 + (ord($c{3})-128)*4096 + (ord($c{4})-128)*64 + (ord($c{5})-128); }
if (ord($c{0})>=254 && ord($c{0})<=255) { $chars{$i} = $unknown; continue; } //error
$bank = $ord >> 8;
if (!array_key_exists($bank, (array) $UTF8_TO_ASCII)) {
$bankfile = __DIR__. '/data/'. sprintf("x%02x",$bank).'.php';
if (file_exists($bankfile)) {
include $bankfile;
} else {
$UTF8_TO_ASCII[$bank] = array();
}
}
$newchar = $ord & 255;
if (array_key_exists($newchar, $UTF8_TO_ASCII[$bank])) {
$chars{$i} = $UTF8_TO_ASCII[$bank][$newchar];
} else {
$chars{$i} = $unknown;
}
}
return implode('', $chars);
}
/**
* Does not transliterate correctly eastern languages
*
* @param string $text
* @param string $separator
* @return string
*/
public static function urlize($text, $separator = '-')
{
$text = self::unaccent($text);
return self::postProcessText($text, $separator);
}
/**
* Uses transliteration tables to convert any kind of utf8 character
*
* @param string $text
* @param string $separator
* @return string $text
*/
public static function transliterate($text, $separator = '-')
{
if (preg_match('/[\x80-\xff]/', $text) && self::validUtf8($text)) {
$text = self::utf8ToAscii($text);
}
return self::postProcessText($text, $separator);
}
/**
* Tests a string as to whether it's valid UTF-8 and supported by the
* Unicode standard
* Note: this function has been modified to simple return true or false
* @author <hsivonen@iki.fi>
* @param string UTF-8 encoded string
* @return boolean true if valid
* @see http://hsivonen.iki.fi/php-utf8/
*/
public static function validUtf8($str)
{
$mState = 0; // cached expected number of octets after the current octet
// until the beginning of the next UTF8 character sequence
$mUcs4 = 0; // cached Unicode character
$mBytes = 1; // cached expected number of octets in the current sequence
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
$in = ord($str{$i});
if ($mState == 0) {
// When mState is zero we expect either a US-ASCII character or a
// multi-octet sequence.
if (0 == (0x80 & ($in))) {
// US-ASCII, pass straight through.
$mBytes = 1;
} elseif (0xC0 == (0xE0 & ($in))) {
// First octet of 2 octet sequence
$mUcs4 = ($in);
$mUcs4 = ($mUcs4 & 0x1F) << 6;
$mState = 1;
$mBytes = 2;
} elseif (0xE0 == (0xF0 & ($in))) {
// First octet of 3 octet sequence
$mUcs4 = ($in);
$mUcs4 = ($mUcs4 & 0x0F) << 12;
$mState = 2;
$mBytes = 3;
} elseif (0xF0 == (0xF8 & ($in))) {
// First octet of 4 octet sequence
$mUcs4 = ($in);
$mUcs4 = ($mUcs4 & 0x07) << 18;
$mState = 3;
$mBytes = 4;
} elseif (0xF8 == (0xFC & ($in))) {
/* First octet of 5 octet sequence.
*
* This is illegal because the encoded codepoint must be either
* (a) not the shortest form or
* (b) outside the Unicode range of 0-0x10FFFF.
* Rather than trying to resynchronize, we will carry on until the end
* of the sequence and let the later error handling code catch it.
*/
$mUcs4 = ($in);
$mUcs4 = ($mUcs4 & 0x03) << 24;
$mState = 4;
$mBytes = 5;
} elseif (0xFC == (0xFE & ($in))) {
// First octet of 6 octet sequence, see comments for 5 octet sequence.
$mUcs4 = ($in);
$mUcs4 = ($mUcs4 & 1) << 30;
$mState = 5;
$mBytes = 6;
} else {
/* Current octet is neither in the US-ASCII range nor a legal first
* octet of a multi-octet sequence.
*/
return false;
}
} else {
// When mState is non-zero, we expect a continuation of the multi-octet
// sequence
if (0x80 == (0xC0 & ($in))) {
// Legal continuation.
$shift = ($mState - 1) * 6;
$tmp = $in;
$tmp = ($tmp & 0x0000003F) << $shift;
$mUcs4 |= $tmp;
/**
* End of the multi-octet sequence. mUcs4 now contains the final
* Unicode codepoint to be output
*/
if (0 == --$mState) {
/*
* Check for illegal sequences and codepoints.
*/
// From Unicode 3.1, non-shortest form is illegal
if (((2 == $mBytes) && ($mUcs4 < 0x0080)) ||
((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
((4 == $mBytes) && ($mUcs4 < 0x10000)) ||
(4 < $mBytes) ||
// From Unicode 3.2, surrogate characters are illegal
(($mUcs4 & 0xFFFFF800) == 0xD800) ||
// Codepoints outside the Unicode range are illegal
($mUcs4 > 0x10FFFF)
) {
return false;
}
//initialize UTF8 cache
$mState = 0;
$mUcs4 = 0;
$mBytes = 1;
}
} else {
/**
*((0xC0 & (*in) != 0x80) && (mState != 0))
* Incomplete multi-octet sequence.
*/
return false;
}
}
}
return true;
}
/**
* Cleans up the text and adds separator
*
* @param string $text
* @param string $separator
* @return string
*/
private static function postProcessText($text, $separator)
{
if (function_exists('mb_strtolower')) {
$text = mb_strtolower($text);
} else {
$text = strtolower($text);
}
// Remove all none word characters
$text = preg_replace('/\W/', ' ', $text);
// More stripping. Replace spaces with dashes
$text = strtolower(preg_replace('/[^A-Z^a-z^0-9^\/]+/', $separator,
preg_replace('/([a-z\d])([A-Z])/', '\1_\2',
preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2',
preg_replace('/::/', '/', $text)))));
return trim($text, $separator);
}
}
<?php
// Deprecated file, use the one in root of vendor dir
trigger_error(__FILE__.' is deprecated, please use vendor/autoload.php or vendor/composer/autoload_* instead'.PHP_EOL.'See https://groups.google.com/forum/#!msg/composer-dev/fWIs3KocwoA/nU3aLko9LhQJ for details', E_USER_DEPRECATED);
return include dirname(__DIR__).'/autoload.php';
<?php
// Deprecated file, use the one in root of vendor dir
trigger_error(__FILE__.' is deprecated, please use vendor/autoload.php or vendor/composer/autoload_* instead'.PHP_EOL.'See https://groups.google.com/forum/#!msg/composer-dev/fWIs3KocwoA/nU3aLko9LhQJ for details', E_USER_DEPRECATED);
return include dirname(__DIR__).'/composer/autoload_classmap.php';
<?php
// Deprecated file, use the one in root of vendor dir
trigger_error(__FILE__.' is deprecated, please use vendor/autoload.php or vendor/composer/autoload_* instead'.PHP_EOL.'See https://groups.google.com/forum/#!msg/composer-dev/fWIs3KocwoA/nU3aLko9LhQJ for details', E_USER_DEPRECATED);
return include dirname(__DIR__).'/composer/autoload_namespaces.php';
<?php
// Deprecated file, use the one in root of vendor dir
trigger_error(__FILE__.' is deprecated, please use vendor/autoload.php or vendor/composer/autoload_* instead'.PHP_EOL.'See https://groups.google.com/forum/#!msg/composer-dev/fWIs3KocwoA/nU3aLko9LhQJ for details', E_USER_DEPRECATED);
return include dirname(__DIR__).'/composer/ClassLoader.php';
<?php
// autoload.php generated by Composer
if (!class_exists('Composer\\Autoload\\ClassLoader', false)) {
require __DIR__ . '/composer' . '/ClassLoader.php';
}
return call_user_func(function() {
$loader = new \Composer\Autoload\ClassLoader();
$composerDir = __DIR__ . '/composer';
$map = require $composerDir . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->add($namespace, $path);
}
$classMap = require $composerDir . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register();
return $loader;
});
<?php
include(__DIR__.'/vendor/autoload.php');
<?php return array (
'en' =>
array (
'name' => 'English',
'native' => 'English',
'feature' => 'Feature',
'background' => 'Background',
'scenario' => 'Scenario',
'scenario_outline' => 'Scenario Outline|Scenario Template',
'examples' => 'Examples|Scenarios',
'given' => 'Given',
'when' => 'When',
'then' => 'Then',
'and' => 'And',
'but' => 'But',
),
'ar' =>
array (
'name' => 'Arabic',
'native' => 'العربية',
'feature' => 'خاصية',
'background' => 'الخلÙ<E2809E>ية',
'scenario' => 'سيناريو',
'scenario_outline' => 'سيناريو مخطط',
'examples' => 'امثلة',
'given' => 'بÙ<C2A8>رض',
'when' => 'متى|عندما',
'then' => 'اذاً|ثم',
'and' => 'Ùˆ',
'but' => 'لكن',
),
'bg' =>
array (
'name' => 'Bulgarian',
'native' => 'българÑ<E282AC>ки',
'feature' => 'ФункционалноÑ<C2BE>Ñ',
'background' => 'ПредиÑ<C2B8>ÑориÑ<C2B8>',
'scenario' => 'Сценарий',
'scenario_outline' => 'Рамка на Ñ<>ценарий',
'examples' => 'Примери',
'given' => 'Дадено',
'when' => 'Когато',
'then' => 'То',
'and' => 'И',
'but' => 'Ð<>о',
),
'ca' =>
array (
'name' => 'Catalan',
'native' => 'català',
'background' => 'Rerefons|Antecedents',
'feature' => 'Característica|Funcionalitat',
'scenario' => 'Escenari',
'scenario_outline' => 'Esquema de l\'escenari',
'examples' => 'Exemples',
'given' => 'Donat|Donada|Atès|Atesa',
'when' => 'Quan',
'then' => 'Aleshores|Cal',
'and' => 'I',
'but' => 'Però',
),
'cy-GB' =>
array (
'name' => 'Welsh',
'native' => 'Cymraeg',
'background' => 'Cefndir',
'feature' => 'Arwedd',
'scenario' => 'Scenario',
'scenario_outline' => 'Scenario Amlinellol',
'examples' => 'Enghreifftiau',
'given' => 'Anrhegedig a',
'when' => 'Pryd',
'then' => 'Yna',
'and' => 'A',
'but' => 'Ond',
),
'cs' =>
array (
'name' => 'Czech',
'native' => 'ÄŒesky',
'feature' => 'Požadavek',
'background' => 'Pozadí|Kontext',
'scenario' => 'Scénář',
'scenario_outline' => 'NáÄ<C2A1>rt Scénáře|Osnova scénáře',
'examples' => 'Příklady',
'given' => 'Pokud',
'when' => 'Když',
'then' => 'Pak',
'and' => 'A také|A',
'but' => 'Ale',
),
'da' =>
array (
'name' => 'Danish',
'native' => 'dansk',
'feature' => 'Egenskab',
'background' => 'Baggrund',
'scenario' => 'Scenarie',
'scenario_outline' => 'Abstrakt Scenario',
'examples' => 'Eksempler',
'given' => 'Givet',
'when' => 'NÃ¥r',
'then' => 'SÃ¥',
'and' => 'Og',
'but' => 'Men',
),
'de' =>
array (
'name' => 'German',
'native' => 'Deutsch',
'feature' => 'Funktionalität',
'background' => 'Grundlage',
'scenario' => 'Szenario',
'scenario_outline' => 'Szenariogrundriss',
'examples' => 'Beispiele',
'given' => 'Angenommen|Gegeben sei',
'when' => 'Wenn',
'then' => 'Dann',
'and' => 'Und',
'but' => 'Aber',
),
'en-au' =>
array (
'name' => 'Australian',
'native' => 'Australian',
'feature' => 'Crikey',
'background' => 'Background',
'scenario' => 'Mate',
'scenario_outline' => 'Blokes',
'examples' => 'Cobber',
'given' => 'Ya know how',
'when' => 'When',
'then' => 'Ya gotta',
'and' => 'N',
'but' => 'Cept',
),
'en-lol' =>
array (
'name' => 'LOLCAT',
'native' => 'LOLCAT',
'feature' => 'OH HAI',
'background' => 'B4',
'scenario' => 'MISHUN',
'scenario_outline' => 'MISHUN SRSLY',
'examples' => 'EXAMPLZ',
'given' => 'I CAN HAZ',
'when' => 'WEN',
'then' => 'DEN',
'and' => 'AN',
'but' => 'BUT',
),
'en-pirate' =>
array (
'name' => 'Pirate',
'native' => 'Pirate',
'feature' => 'Ahoy matey!',
'background' => 'Yo-ho-ho',
'scenario' => 'Heave to',
'scenario_outline' => 'Shiver me timbers',
'examples' => 'Dead men tell no tales',
'given' => 'Gangway!',
'when' => 'Blimey!',
'then' => 'Let go and haul',
'and' => 'Aye',
'but' => 'Avast!',
),
'en-Scouse' =>
array (
'name' => 'Scouse',
'native' => 'Scouse',
'feature' => 'Feature',
'background' => 'Dis is what went down',
'scenario' => 'The thing of it is',
'scenario_outline' => 'Wharrimean is',
'examples' => 'Examples',
'given' => 'Givun|Youse know when youse got',
'when' => 'Wun|Youse know like when',
'then' => 'Dun|Den youse gotta',
'and' => 'An',
'but' => 'Buh',
),
'en-tx' =>
array (
'name' => 'Texan',
'native' => 'Texan',
'feature' => 'Feature',
'background' => 'Background',
'scenario' => 'Scenario',
'scenario_outline' => 'All y\'all',
'examples' => 'Examples',
'given' => 'Given y\'all',
'when' => 'When y\'all',
'then' => 'Then y\'all',
'and' => 'And y\'all',
'but' => 'But y\'all',
),
'eo' =>
array (
'name' => 'Esperanto',
'native' => 'Esperanto',
'feature' => 'Trajto',
'background' => 'Fono',
'scenario' => 'Scenaro',
'scenario_outline' => 'Konturo de la scenaro',
'examples' => 'Ekzemploj',
'given' => 'Donitaĵo',
'when' => 'Se',
'then' => 'Do',
'and' => 'Kaj',
'but' => 'Sed',
),
'es' =>
array (
'name' => 'Spanish',
'native' => 'español',
'background' => 'Antecedentes',
'feature' => 'Característica',
'scenario' => 'Escenario',
'scenario_outline' => 'Esquema del escenario',
'examples' => 'Ejemplos',
'given' => 'Dado|Dada|Dados|Dadas',
'when' => 'Cuando',
'then' => 'Entonces',
'and' => 'Y',
'but' => 'Pero',
),
'et' =>
array (
'name' => 'Estonian',
'native' => 'eesti keel',
'feature' => 'Omadus',
'background' => 'Taust',
'scenario' => 'Stsenaarium',
'scenario_outline' => 'Raamstsenaarium',
'examples' => 'Juhtumid',
'given' => 'Eeldades',
'when' => 'Kui',
'then' => 'Siis',
'and' => 'Ja',
'but' => 'Kuid',
),
'fi' =>
array (
'name' => 'Finnish',
'native' => 'suomi',
'feature' => 'Ominaisuus',
'background' => 'Tausta',
'scenario' => 'Tapaus',
'scenario_outline' => 'Tapausaihio',
'examples' => 'Tapaukset',
'given' => 'Oletetaan',
'when' => 'Kun',
'then' => 'Niin',
'and' => 'Ja',
'but' => 'Mutta',
),
'fr' =>
array (
'name' => 'French',
'native' => 'français',
'feature' => 'Fonctionnalité',
'background' => 'Contexte',
'scenario' => 'Scénario',
'scenario_outline' => 'Plan du scénario|Plan du Scénario',
'examples' => 'Exemples',
'given' => 'Soit|Etant donné|Etant donnée|Etant donnés|Etant données|Étant donné|Étant donnée|Étant donnés|Étant données',
'when' => 'Quand|Lorsque|Lorsqu\'<',
'then' => 'Alors',
'and' => 'Et',
'but' => 'Mais',
),
'he' =>
array (
'name' => 'Hebrew',
'native' => 'עברית',
'feature' => 'תכונה',
'background' => 'רקע',
'scenario' => 'תרחיש',
'scenario_outline' => 'תבנית תרחיש',
'examples' => '×××מ×<C5BE>×ת',
'given' => 'בהינתן',
'when' => '××<E280BA>שר',
'then' => '×<>×|×<>××™',
'and' => '×××<E28099>',
'but' => '×<>×ל',
),
'hr' =>
array (
'name' => 'Croatian',
'native' => 'hrvatski',
'feature' => 'Osobina|Mogućnost|Mogucnost',
'background' => 'Pozadina',
'scenario' => 'Scenarij',
'scenario_outline' => 'Skica|Koncept',
'examples' => 'Primjeri|Scenariji',
'given' => 'Zadan|Zadani|Zadano',
'when' => 'Kada|Kad',
'then' => 'Onda',
'and' => 'I',
'but' => 'Ali',
),
'hu' =>
array (
'name' => 'Hungarian',
'native' => 'magyar',
'feature' => 'JellemzÅ',
'background' => 'Háttér',
'scenario' => 'Forgatókönyv',
'scenario_outline' => 'Forgatókönyv vázlat',
'examples' => 'Példák',
'given' => 'Amennyiben|Adott',
'when' => 'Majd|Ha|Amikor',
'then' => 'Akkor',
'and' => 'És',
'but' => 'De',
),
'id' =>
array (
'name' => 'Indonesian',
'native' => 'Bahasa Indonesia',
'feature' => 'Fitur',
'background' => 'Dasar',
'scenario' => 'Skenario',
'scenario_outline' => 'Skenario konsep',
'examples' => 'Contoh',
'given' => 'Dengan',
'when' => 'Ketika',
'then' => 'Maka',
'and' => 'Dan',
'but' => 'Tapi',
),
'is' =>
array (
'name' => 'Icelandic',
'native' => 'Ã<>slenska',
'feature' => 'Eiginleiki',
'background' => 'Bakgrunnur',
'scenario' => 'Atburðarás',
'scenario_outline' => 'Lýsing Atburðarásar|Lýsing Dæma',
'examples' => 'Dæmi|Atburðarásir',
'given' => 'Ef',
'when' => 'Þegar',
'then' => 'Þá',
'and' => 'Og',
'but' => 'En',
),
'it' =>
array (
'name' => 'Italian',
'native' => 'italiano',
'feature' => 'Funzionalità',
'background' => 'Contesto',
'scenario' => 'Scenario',
'scenario_outline' => 'Schema dello scenario',
'examples' => 'Esempi',
'given' => 'Dato|Data|Dati|Date',
'when' => 'Quando',
'then' => 'Allora',
'and' => 'E',
'but' => 'Ma',
),
'ja' =>
array (
'name' => 'Japanese',
'native' => '日本語',
'feature' => 'フã£ãƒ¼ãƒ<C3A3>ャ|機能',
'background' => '背景',
'scenario' => 'シナリオ',
'scenario_outline' => 'シナリオアウトライン|シナリオテンプレート|テンプレ|シナリオテンプレ',
'examples' => '例|サンプル',
'given' => 'å‰<C3A5>æ<EFBFBD><C3A6><',
'when' => 'ãã<E2809A>—<',
'then' => 'ã<>ªã‰ã<E280B0>°<',
'and' => 'ã<>ã<E280B9>¤<',
'but' => 'ã<>—ã<E28094>ã<E280B9>—<|但ã<E280A0>—<|ã<>Ÿã<C5B8> ã<C2A0>—<',
),
'ko' =>
array (
'name' => 'Korean',
'native' => '한국어',
'background' => 'ë°°ê²½',
'feature' => '기능',
'scenario' => '시나리오',
'scenario_outline' => '시나리오 개요',
'examples' => '예',
'given' => '조건<|먼저<',
'when' => '만ì<C592>¼<|만약<',
'then' => '그러면<',
'and' => '그리고<',
'but' => '하지만<|단<',
),
'lt' =>
array (
'name' => 'Lithuanian',
'native' => 'lietuvių kalba',
'feature' => 'SavybÄ—',
'background' => 'Kontekstas',
'scenario' => 'Scenarijus',
'scenario_outline' => 'Scenarijaus Å¡ablonas',
'examples' => 'Pavyzdžiai|Scenarijai|Variantai',
'given' => 'Duota',
'when' => 'Kai',
'then' => 'Tada',
'and' => 'Ir',
'but' => 'Bet',
),
'lu' =>
array (
'name' => 'Luxemburgish',
'native' => 'Lëtzebuergesch',
'feature' => 'Funktionalitéit',
'background' => 'Hannergrond',
'scenario' => 'Szenario',
'scenario_outline' => 'Plang vum Szenario',
'examples' => 'Beispiller',
'given' => 'ugeholl',
'when' => 'wann',
'then' => 'dann',
'and' => 'an|a',
'but' => 'awer|mä',
),
'lv' =>
array (
'name' => 'Latvian',
'native' => 'latviešu',
'feature' => 'FunkcionalitÄ<74>te|FÄ«Ä<C2AB>a',
'background' => 'Konteksts|SituÄ<75>cija',
'scenario' => 'ScenÄ<6E>rijs',
'scenario_outline' => 'ScenÄ<6E>rijs pÄ“c parauga',
'examples' => 'Piemēri|Paraugs',
'given' => 'Kad',
'when' => 'Ja',
'then' => 'Tad',
'and' => 'Un',
'but' => 'Bet',
),
'nl' =>
array (
'name' => 'Dutch',
'native' => 'Nederlands',
'feature' => 'Functionaliteit',
'background' => 'Achtergrond',
'scenario' => 'Scenario',
'scenario_outline' => 'Abstract Scenario',
'examples' => 'Voorbeelden',
'given' => 'Gegeven|Stel',
'when' => 'Als',
'then' => 'Dan',
'and' => 'En',
'but' => 'Maar',
),
'no' =>
array (
'name' => 'Norwegian',
'native' => 'norsk',
'feature' => 'Egenskap',
'background' => 'Bakgrunn',
'scenario' => 'Scenario',
'scenario_outline' => 'Scenariomal|Abstrakt Scenario',
'examples' => 'Eksempler',
'given' => 'Gitt',
'when' => 'NÃ¥r',
'then' => 'SÃ¥',
'and' => 'Og',
'but' => 'Men',
),
'pl' =>
array (
'name' => 'Polish',
'native' => 'polski',
'feature' => 'WÅciwoÅć',
'background' => 'ZaÅożenia',
'scenario' => 'Scenariusz',
'scenario_outline' => 'Szablon scenariusza',
'examples' => 'PrzykÅady',
'given' => 'ZakÅadajÄ…c|MajÄ…c',
'when' => 'Jeżeli|JeÅli',
'then' => 'Wtedy',
'and' => 'Oraz|I',
'but' => 'Ale',
),
'pt' =>
array (
'name' => 'Portuguese',
'native' => 'português',
'background' => 'Contexto|Cenário de Fundo|Cenario de Fundo|Fundo',
'feature' => 'Funcionalidade|Característica|Caracteristica',
'scenario' => 'Cenário|Cenario',
'scenario_outline' => 'Esquema do Cenário|Esquema do Cenario|Delineação do Cenário|Delineacao do Cenario',
'examples' => 'Exemplos|Cenários|Cenarios',
'given' => 'Dado|Dada|Dados|Dadas',
'when' => 'Quando',
'then' => 'Então|Entao',
'and' => 'E',
'but' => 'Mas',
),
'ro' =>
array (
'name' => 'Romanian',
'native' => 'română',
'background' => 'Context',
'feature' => 'Functionalitate|FuncÈionalitate|FuncÅ£ionalitate',
'scenario' => 'Scenariu',
'scenario_outline' => 'Structura scenariu|Structură scenariu',
'examples' => 'Exemple',
'given' => 'Date fiind|Dat fiind|Dati fiind|DaÈi fiind|DaÅ£i fiind',
'when' => 'Cand|Când',
'then' => 'Atunci',
'and' => 'Si|Și|Şi',
'but' => 'Dar',
),
'ru' =>
array (
'name' => 'Russian',
'native' => 'руÑ<C692>Ñ<EFBFBD>кий',
'feature' => 'ФункциÑ<C2B8>|Функционал|СвойÑ<C2B9>Ñво',
'background' => 'ПредÑÑ<E280B9>ÑориÑ<C2B8>|КонÑекÑ<C2BA>Ñ',
'scenario' => 'Сценарий',
'scenario_outline' => 'Структура Ñ<>ценариÑ<C2B8>',
'examples' => 'Примеры',
'given' => 'ДопуÑ<C692>Ñим|Дано|ПуÑ<C692>ÑÑŒ',
'when' => 'ЕÑ<E280A2>ли|Когда',
'then' => 'То|Тогда',
'and' => 'И|К тому же',
'but' => 'Ð<>о|Ð<>',
),
'sv' =>
array (
'name' => 'Swedish',
'native' => 'Svenska',
'feature' => 'Egenskap',
'background' => 'Bakgrund',
'scenario' => 'Scenario',
'scenario_outline' => 'Abstrakt Scenario|Scenariomall',
'examples' => 'Exempel',
'given' => 'Givet',
'when' => 'När',
'then' => 'SÃ¥',
'and' => 'Och',
'but' => 'Men',
),
'sk' =>
array (
'name' => 'Slovak',
'native' => 'Slovensky',
'feature' => 'Požiadavka',
'background' => 'Pozadie',
'scenario' => 'Scenár',
'scenario_outline' => 'NáÄ<C2A1>rt Scenáru',
'examples' => 'Príklady',
'given' => 'Pokiaľ',
'when' => 'KeÄ<65>',
'then' => 'Tak',
'and' => 'A',
'but' => 'Ale',
),
'sr-Latn' =>
array (
'name' => 'Serbian (Latin)',
'native' => 'Srpski (Latinica)',
'feature' => 'Funkcionalnost|Mogućnost|Mogucnost|Osobina',
'background' => 'Kontekst|Osnova|Pozadina',
'scenario' => 'Scenario|Primer',
'scenario_outline' => 'Struktura scenarija|Skica|Koncept',
'examples' => 'Primeri|Scenariji',
'given' => 'Zadato|Zadate|Zatati',
'when' => 'Kada|Kad',
'then' => 'Onda',
'and' => 'I',
'but' => 'Ali',
),
'sr-Cyrl' =>
array (
'name' => 'Serbian',
'native' => 'СрпÑ<C2BF>ки',
'feature' => 'ФункционалноÑ<C2BE>Ñ|МогуÑноÑ<C2BE>Ñ|ОÑ<C5BE>обина',
'background' => 'КонÑекÑ<C2BA>Ñ|ОÑ<C5BE>нова|Позадина',
'scenario' => 'Сценарио|Пример',
'scenario_outline' => 'Структура Ñ<>ценарија|Скица|Концепт',
'examples' => 'Примери|Сценарији',
'given' => 'Задато|Задате|Задати',
'when' => 'Када|Кад',
'then' => 'Онда',
'and' => 'И',
'but' => 'Ð<>ли',
),
'tr' =>
array (
'name' => 'Turkish',
'native' => 'Türkçe',
'feature' => 'Ãzellik',
'background' => 'Geçmiş',
'scenario' => 'Senaryo',
'scenario_outline' => 'Senaryo taslağı',
'examples' => 'Ãrnekler',
'given' => 'Diyelim ki',
'when' => 'EÄŸer ki',
'then' => 'O zaman',
'and' => 'Ve',
'but' => 'Fakat|Ama',
),
'uk' =>
array (
'name' => 'Ukrainian',
'native' => 'УкраїнÑ<C2BD>ька',
'feature' => 'Функціонал',
'background' => 'Передумова',
'scenario' => 'Сценарій',
'scenario_outline' => 'Структура Ñ<>ценарÑÑŽ',
'examples' => 'Приклади',
'given' => 'ПрипуÑ<C692>Ñимо|ПрипуÑ<C692>Ñимо, що|Ð<>ехай|Дано',
'when' => 'Якщо|Коли',
'then' => 'То|Тоді',
'and' => 'І|Ð<> також|Та',
'but' => 'Ð<>ле',
),
'uz' =>
array (
'name' => 'Uzbek',
'native' => 'Узбекча',
'feature' => 'Функционал',
'background' => 'Тарих',
'scenario' => 'Сценарий',
'scenario_outline' => 'Сценарий Ñ<>ÑрукÑураÑ<C2B0>и',
'examples' => 'МиÑ<C2B8>оллар',
'given' => 'Ð<>гар',
'when' => 'Ð<>гар',
'then' => 'Унда',
'and' => 'Ва',
'but' => 'Лекин|Бирок|Ð<>ммо',
),
'vi' =>
array (
'name' => 'Vietnamese',
'native' => 'Tiếng Việt',
'feature' => 'Tính năng',
'background' => 'Bá»i cảnh',
'scenario' => 'Tình huá»ng|Ká»ch bản',
'scenario_outline' => 'Khung tình huá»ng|Khung ká»ch bản',
'examples' => 'Dữ liệu',
'given' => 'Biết|Cho',
'when' => 'Khi',
'then' => 'Thì',
'and' => 'Và',
'but' => 'NhÆ°ng',
),
'zh-CN' =>
array (
'name' => 'Chinese simplified',
'native' => '简体中文',
'feature' => '功能',
'background' => '背景',
'scenario' => '场景|剧本',
'scenario_outline' => '场景大纲|剧本大纲',
'examples' => 'ä¾å­<C3A5>',
'given' => 'å<>‡å¦<|å<>‡è®¾<|å<>‡å®š<',
'when' => '当<',
'then' => '那么<',
'and' => '而且<|并且<|å<>Œæ—¶<',
'but' => '但是<',
),
'zh-TW' =>
array (
'name' => 'Chinese traditional',
'native' => 'ç¹<C3A7>體中æ‡',
'feature' => '功能',
'background' => '背景',
'scenario' => '場景|劇本',
'scenario_outline' => '場景大綱|劇本大綱',
'examples' => 'ä¾å­<C3A5>',
'given' => 'å<>‡å¦<|å<>‡è¨­<|å<>‡å®š<',
'when' => '當<',
'then' => '那麼<',
'and' => '而且<|並且<|å<>Œæ™<',
'but' => '但是<',
),
);<?php
return __DIR__;Copyright (c) 2012 Konstantin Kudryashov <ever.zet@gmail.com>
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.
<?php
namespace Behat\Gherkin\Cache;
use Behat\Gherkin\Node\FeatureNode;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Parser cache interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface CacheInterface
{
/**
* Checks that cache for feature exists and is fresh.
*
* @param string $path Feature path
* @param integer $timestamp The last time feature was updated
*
* @return Boolean
*/
function isFresh($path, $timestamp);
/**
* Reads feature cache from path.
*
* @param string $path Feature path
*
* @return FeatureNode
*/
function read($path);
/**
* Caches feature node.
*
* @param string $path Feature path
* @param FeatureNode $feature Feature instance
*/
function write($path, FeatureNode $feature);
}
<?php
namespace Behat\Gherkin\Cache;
use Behat\Gherkin\Node\FeatureNode;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* File cache.
* Caches feature into a file.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FileCache implements CacheInterface
{
private $path;
/**
* Initializes file cache.
*
* @param string $path Path to the folder where to store caches.
*/
public function __construct($path)
{
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$this->path = rtrim($path, '/');
}
/**
* Checks that cache for feature exists and is fresh.
*
* @param string $path Feature path
* @param integer $timestamp The last time feature was updated
*
* @return Boolean
*/
public function isFresh($path, $timestamp)
{
$cachePath = $this->getCachePathFor($path);
if (!file_exists($cachePath)) {
return false;
}
return filemtime($cachePath) > $timestamp;
}
/**
* Reads feature cache from path.
*
* @param string $path Feature path
*
* @return FeatureNode
*/
public function read($path)
{
return unserialize(file_get_contents($this->getCachePathFor($path)));
}
/**
* Caches feature node.
*
* @param string $path Feature path
* @param FeatureNode $feature Feature instance
*/
public function write($path, FeatureNode $feature)
{
file_put_contents($this->getCachePathFor($path), serialize($feature));
}
/**
* Returns feature cache file path from features path.
*
* @param string $path Feature path
*
* @return string
*/
protected function getCachePathFor($path)
{
return $this->path.'/'.md5($path).'.feature.cache';
}
}
<?php
namespace Behat\Gherkin\Dumper;
use Behat\Gherkin\Exception\Exception,
Behat\Gherkin\Keywords\KeywordsInterface,
Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\BackgroundNode,
Behat\Gherkin\Node\ScenarioNode,
Behat\Gherkin\Node\TableNode,
Behat\Gherkin\Node\StepNode,
Behat\Gherkin\Node\OutlineNode;
/*
* This file is part of the Behat Gherkin.
* (c) 2012 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Gherkin Dumper.
*
* @author Jean-François Lépine <dev@lepine.pro>
*/
class GherkinDumper
{
private $keywords;
private $indent;
/**
* Constructs dumper.
*
* @param KeywordsInterface $keywords Keywords container
* @param string $indent Indentation
*/
public function __construct(KeywordsInterface $keywords, $indent = ' ')
{
$this->keywords = $keywords;
$this->indent = $indent;
}
/**
* Dumps a feature.
*
* @see dumpFeature()
*
* @param FeatureNode $feature Feature instance
*
* @return string
*/
public function dump(FeatureNode $feature)
{
return $this->dumpFeature($feature);
}
/**
* Dumps a background.
*
* @param BackgroundNode $background Background instance
*
* @return string
*/
public function dumpBackground(BackgroundNode $background)
{
$content = $this->dumpKeyword(
$this->keywords->getBackgroundKeywords(), $background->getTitle()
);
foreach ($background->getSteps() as $step) {
$content .=
PHP_EOL . $this->dumpIndent(1)
. $this->dumpStep($step);
}
return $content;
}
/**
* Dumps comment.
*
* @param string $comment Comment string
*
* @return string
*/
public function dumpComment($comment)
{
return $comment ? '# ' . $comment : '';
}
/**
* Dumps feature.
*
* @param FeatureNode $feature Feature instance
*
* @return string
*/
public function dumpFeature(FeatureNode $feature)
{
$language = $feature->getLanguage();
$this->keywords->setLanguage($language);
$content = ''
. $this->dumpLanguage($language)
. ($feature->getTags() ? PHP_EOL . $this->dumpTags($feature->getTags(), 0) : '')
. PHP_EOL . $this->dumpKeyword($this->keywords->getFeatureKeywords(), $feature->getTitle(), 0)
. PHP_EOL . $this->dumpText($feature->getDescription(), 1);
if ($feature->getBackground()) {
$content .= $this->dumpBackground($feature->getBackground());
}
$scenarios = $feature->getScenarios();
foreach ($scenarios as $scenario) {
$content .= PHP_EOL . $this->dumpScenario($scenario);
}
return $content;
}
/**
* Dumps keyword.
*
* @param string $keyword Keyword string
* @param string $text Text
* @param integer $indent Indentation
*
* @return string
*/
public function dumpKeyword($keyword, $text, $indent = 0)
{
if (preg_match('!(^.*)\|!', $keyword, $matches)) {
$keyword = $matches[1];
}
return $this->dumpIndent($indent) . $keyword . ':'
. ((strlen($text) > 0) ? ' ' . ltrim($this->dumpText($text, $indent + 1)) : '')
;
}
/**
* Dumps scenario.
*
* @param ScenarioNode $scenario Scenario instance
*
* @return string
*/
public function dumpScenario(ScenarioNode $scenario)
{
$keyWordToUse = $scenario instanceof OutlineNode ? $this->keywords->getOutlineKeywords() : $this->keywords->getScenarioKeywords();
$content = ''
. (sizeof($scenario->getTags()) > 0 ? PHP_EOL . $this->dumpTags($scenario->getTags(), 1) : '')
. PHP_EOL . $this->dumpKeyword($keyWordToUse, $scenario->getTitle(), 1)
;
foreach ($scenario->getSteps() as $step) {
$content .=
PHP_EOL . $this->dumpIndent(2)
. $this->dumpStep($step);
}
if ($scenario instanceof OutlineNode) {
$content .= ''
. PHP_EOL . PHP_EOL . $this->dumpKeyword($this->keywords->getExamplesKeywords(), '', 1)
;
$examples = $scenario->getExamples();
$content .= $this->dumpTableNode($examples, 2);
}
return $content;
}
/**
* Dumps table node.
*
* @param TableNode $tableNode Table node
* @param integer $indent Indentation
* @return string
*/
public function dumpTableNode(TableNode $tableNode, $indent = 0)
{
$len = sizeof($tableNode->getRows());
$content = '';
for ($i = 0; $i < $len; $i++) {
$content .= PHP_EOL . $this->dumpIndent($indent)
. $tableNode->getRowAsString($i);
}
return $content;
}
/**
* Dumps indentation.
*
* @param integer $indent Indentation
*
* @return string
*/
public function dumpIndent($indent)
{
return str_repeat($this->indent, $indent);
}
/**
* Dumps a step.
*
* @param StepNode $step Step node instance
*
* @return string
*
* @throws Exception if invalid step type providen
*/
public function dumpStep(StepNode $step)
{
switch ($step->getType()) {
case 'Given':
$kw = $this->keywords->getGivenKeywords();
break;
case 'When':
$kw = $this->keywords->getWhenKeywords();
break;
case 'Then':
$kw = $this->keywords->getThenKeywords();
break;
case 'But':
$kw = $this->keywords->getButKeywords();
break;
case 'And':
$kw = $this->keywords->getAndKeywords();
break;
default:
throw new Exception("invalid type given : " . $step->getType());
}
return $this->dumpText($kw . ' ' . $step->getText());
}
/**
* Dumps text.
*
* @param string $text Text to dump
* @param integer $indent Indentation
*
* @return string
*/
public function dumpText($text, $indent = 0)
{
return $this->dumpIndent($indent) . implode(
PHP_EOL . $this->dumpIndent($indent),
explode(PHP_EOL, $text)
);
}
/**
* Dumps tags.
*
* @param array $tags Array of tags
* @param integer $indent Indentation
*
* @return string
*/
public function dumpTags(array $tags, $indent = 0)
{
if (empty($tags)) {
return '';
}
return $this->dumpIndent($indent) . '@' . ltrim(implode(' @', $tags));
}
/**
* Dumps language tag.
*
* @param string $language Language name
*
* @return string
*/
public function dumpLanguage($language)
{
return $this->dumpComment($this->dumpKeyword('language', $language));
}
}
<?php
namespace Behat\Gherkin\Exception;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Exception extends \Exception
{}
<?php
namespace Behat\Gherkin\Exception;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class LexerException extends Exception
{}
<?php
namespace Behat\Gherkin\Exception;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class ParserException extends Exception
{}
<?php
namespace Behat\Gherkin\Filter;
use Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\ScenarioNode;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Filter interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface FilterInterface
{
/**
* Checks if Feature matches specified filter.
*
* @param FeatureNode $feature Feature instance
*
* @return Boolean
*/
function isFeatureMatch(FeatureNode $feature);
/**
* Checks if scenario or outline matches specified filter.
*
* @param ScenarioNode $scenario Scenario or Outline node instance
*
* @return Boolean
*/
function isScenarioMatch(ScenarioNode $scenario);
}
<?php
namespace Behat\Gherkin\Filter;
use Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\ScenarioNode;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Filters scenarios by definition line number.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class LineFilter implements FilterInterface
{
protected $filterLine;
/**
* Initializes filter.
*
* @param string $filterLine Line of the scenario to filter on
*/
public function __construct($filterLine)
{
$this->filterLine = intval($filterLine);
}
/**
* Checks if Feature matches specified filter.
*
* @param FeatureNode $feature Feature instance
*
* @return Boolean
*/
public function isFeatureMatch(FeatureNode $feature)
{
return true;
}
/**
* Checks if scenario or outline matches specified filter.
*
* @param ScenarioNode $scenario Scenario or Outline node instance
*
* @return Boolean
*/
public function isScenarioMatch(ScenarioNode $scenario)
{
return $this->filterLine === $scenario->getLine();
}
}
<?php
namespace Behat\Gherkin\Filter;
use Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\ScenarioNode;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Filters scenarios by definition line number range.
*
* @author Fabian Kiss <headrevision@gmail.com>
*/
class LineRangeFilter implements FilterInterface
{
protected $filterMinLine;
protected $filterMaxLine;
/**
* Initializes filter.
*
* @param string $filterMinLine Minimum line of a scenario to filter on
* @param string $filterMaxLine Maximum line of a scenario to filter on
*/
public function __construct($filterMinLine, $filterMaxLine)
{
$this->filterMinLine = intval($filterMinLine);
if ($filterMaxLine == '*') {
$this->filterMaxLine = PHP_INT_MAX;
} else {
$this->filterMaxLine = intval($filterMaxLine);
}
}
/**
* Checks if Feature matches specified filter.
*
* @param FeatureNode $feature Feature instance
*
* @return Boolean
*/
public function isFeatureMatch(FeatureNode $feature)
{
return true;
}
/**
* Checks if scenario or outline matches specified filter.
*
* @param ScenarioNode $scenario Scenario or Outline node instance
*
* @return Boolean
*/
public function isScenarioMatch(ScenarioNode $scenario)
{
return $this->filterMinLine <= $scenario->getLine()
&& $this->filterMaxLine >= $scenario->getLine();
}
}
<?php
namespace Behat\Gherkin\Filter;
use Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\ScenarioNode;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Filters scenarios by feature/scenario name.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class NameFilter implements FilterInterface
{
protected $filterString;
/**
* Initializes filter.
*
* @param string $filterStringString Name filter string
*/
public function __construct($filterString)
{
$this->filterString = trim($filterString);
}
/**
* Checks if Feature matches specified filter.
*
* @param FeatureNode $feature Feature instance
*
* @return Boolean
*/
public function isFeatureMatch(FeatureNode $feature)
{
if ('/' === $this->filterString[0]) {
return (bool) preg_match($this->filterString, $feature->getTitle());
}
return false !== mb_strpos($feature->getTitle(), $this->filterString);
}
/**
* Checks if scenario or outline matches specified filter.
*
* @param ScenarioNode $scenario Scenario or Outline node instance
*
* @return Boolean
*/
public function isScenarioMatch(ScenarioNode $scenario)
{
if ('/' === $this->filterString[0] && 1 === preg_match($this->filterString, $scenario->getTitle())) {
return true;
} elseif (false !== mb_strpos($scenario->getTitle(), $this->filterString)) {
return true;
}
if (null !== $scenario->getFeature()) {
return $this->isFeatureMatch($scenario->getFeature());
}
return false;
}
}
<?php
namespace Behat\Gherkin\Filter;
use Behat\Gherkin\Node\AbstractNode,
Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\ScenarioNode;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Filters scenarios by feature/scenario tag.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class TagFilter implements FilterInterface
{
protected $filterString;
/**
* Initializes filter.
*
* @param string $filterStringString Name filter string
*/
public function __construct($filterString)
{
$this->filterString = trim($filterString);
}
/**
* Checks if Feature matches specified filter.
*
* @param FeatureNode $feature Feature instance
*
* @return Boolean
*/
public function isFeatureMatch(FeatureNode $feature)
{
return $this->matchesCondition($feature);
}
/**
* Checks if scenario or outline matches specified filter.
*
* @param ScenarioNode $scenario Scenario or Outline node instance
*
* @return Boolean
*/
public function isScenarioMatch(ScenarioNode $scenario)
{
return $this->matchesCondition($scenario);
}
/**
* Checks that node matches condition.
*
* @param AbstractNode $node Node to check
*/
protected function matchesCondition(AbstractNode $node)
{
$satisfies = true;
foreach (explode('&&', $this->filterString) as $andTags) {
$satisfiesComma = false;
foreach (explode(',', $andTags) as $tag) {
$tag = str_replace('@', '', trim($tag));
if ('~' === $tag[0]) {
$tag = mb_substr($tag, 1);
$satisfiesComma = !$node->hasTag($tag) || $satisfiesComma;
} else {
$satisfiesComma = $node->hasTag($tag) || $satisfiesComma;
}
}
$satisfies = (false !== $satisfiesComma && $satisfies && $satisfiesComma) || false;
}
return $satisfies;
}
}
<?php
namespace Behat\Gherkin;
use Behat\Gherkin\Loader\LoaderInterface,
Behat\Gherkin\Filter\FilterInterface,
Behat\Gherkin\Filter\LineFilter,
Behat\Gherkin\Filter\LineRangeFilter;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Gherkin manager.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Gherkin
{
protected $freeze = true;
protected $loaders = array();
protected $filters = array();
/**
* Either to freeze features after loading or not.
*
* @param Boolean $freeze To freeze?
*/
public function setFreeze($freeze = true)
{
$this->freeze = (bool) $freeze;
}
/**
* Adds loader to manager.
*
* @param LoaderInterface $loader Feature loader
*/
public function addLoader(LoaderInterface $loader)
{
$this->loaders[] = $loader;
}
/**
* Adds filter to manager.
*
* @param FilterInterface $filter Feature/Scenario filter
*/
public function addFilter(FilterInterface $filter)
{
$this->filters[] = $filter;
}
/**
* Sets base features path.
*
* @param string $path Loaders base path
*/
public function setBasePath($path)
{
foreach ($this->loaders as $loader) {
$loader->setBasePath($path);
}
}
/**
* Loads & filters resource with added loaders.
*
* @param mixed $resource Resource to load
*
* @return array
*/
public function load($resource)
{
$filters = $this->filters;
$matches = array();
if (preg_match('/^(.*)\:(\d+)-(\d+|\*)$/', $resource, $matches)) {
$resource = $matches[1];
$filters[] = new LineRangeFilter($matches[2], $matches[3]);
} elseif (preg_match('/^(.*)\:(\d+)$/', $resource, $matches)) {
$resource = $matches[1];
$filters[] = new LineFilter($matches[2]);
}
$loader = $this->resolveLoader($resource);
if (null === $loader) {
throw new \InvalidArgumentException(sprintf('Can\'t find loader for resource: %s', $resource));
}
$features = $loader->load($resource);
foreach ($features as $feature) {
$scenarios = $feature->getScenarios();
foreach ($scenarios as $i => $scenario) {
foreach ($filters as $filter) {
if (!$filter->isScenarioMatch($scenario)) {
unset($scenarios[$i]);
break;
}
}
}
$feature->setScenarios($scenarios);
if ($this->freeze) {
$feature->freeze();
}
}
return $features;
}
/**
* Resolves loader by resource.
*
* @param mixed $resoruce Resource to load
*
* @return LoaderInterface
*/
public function resolveLoader($resource)
{
foreach ($this->loaders as $loader) {
if ($loader->supports($resource)) {
return $loader;
}
}
return null;
}
}
<?php
namespace Behat\Gherkin\Keywords;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Array initializable keywords holder.
*
* $keywords = new Behat\Gherkin\Keywords\ArrayKeywords(array(
* 'en' => array(
* 'feature' => 'Feature',
* 'background' => 'Background',
* 'scenario' => 'Scenario',
* 'scenario_outline' => 'Scenario Outline|Scenario Template',
* 'examples' => 'Examples|Scenarios',
* 'given' => 'Given',
* 'when' => 'When',
* 'then' => 'Then',
* 'and' => 'And',
* 'but' => 'But'
* ),
* 'ru' => array(
* 'feature' => 'Функционал',
* 'background' => 'ПредÑÑ<E280B9>ÑориÑ<C2B8>',
* 'scenario' => 'Сценарий',
* 'scenario_outline' => 'Структура Ñ<>ценариÑ<C2B8>',
* 'examples' => 'ЗначениÑ<C2B8>',
* 'given' => 'ДопуÑ<C692>Ñим',
* 'when' => 'ЕÑ<E280A2>ли',
* 'then' => 'То',
* 'and' => 'И',
* 'but' => 'Ð<>о'
* )
* ));
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ArrayKeywords implements KeywordsInterface
{
private $keywords = array();
private $language;
/**
* Initializes holder with keywords.
*
* @param array $keywords Keywords array
*/
public function __construct(array $keywords)
{
$this->keywords = $keywords;
}
/**
* Sets keywords holder language.
*
* @param string $language Language name
*/
public function setLanguage($language)
{
if (!isset($this->keywords[$language])) {
$this->language = 'en';
} else {
$this->language = $language;
}
}
/**
* Returns Feature keywords (splitted by "|").
*
* @return string
*/
public function getFeatureKeywords()
{
return $this->keywords[$this->language]['feature'];
}
/**
* Returns Background keywords (splitted by "|").
*
* @return string
*/
public function getBackgroundKeywords()
{
return $this->keywords[$this->language]['background'];
}
/**
* Returns Scenario keywords (splitted by "|").
*
* @return string
*/
public function getScenarioKeywords()
{
return $this->keywords[$this->language]['scenario'];
}
/**
* Returns Scenario Outline keywords (splitted by "|").
*
* @return string
*/
public function getOutlineKeywords()
{
return $this->keywords[$this->language]['scenario_outline'];
}
/**
* Returns Examples keywords (splitted by "|").
*
* @return string
*/
public function getExamplesKeywords()
{
return $this->keywords[$this->language]['examples'];
}
/**
* Returns Given keywords (splitted by "|").
*
* @return string
*/
public function getGivenKeywords()
{
return $this->keywords[$this->language]['given'];
}
/**
* Returns When keywords (splitted by "|").
*
* @return string
*/
public function getWhenKeywords()
{
return $this->keywords[$this->language]['when'];
}
/**
* Returns Then keywords (splitted by "|").
*
* @return string
*/
public function getThenKeywords()
{
return $this->keywords[$this->language]['then'];
}
/**
* Returns And keywords (splitted by "|").
*
* @return string
*/
public function getAndKeywords()
{
return $this->keywords[$this->language]['and'];
}
/**
* Returns But keywords (splitted by "|").
*
* @return string
*/
public function getButKeywords()
{
return $this->keywords[$this->language]['but'];
}
/**
* Returns all step keywords (Given, When, Then, And, But).
*
* @return string
*/
public function getStepKeywords()
{
return implode('|', array(
$this->getGivenKeywords(),
$this->getWhenKeywords(),
$this->getThenKeywords(),
$this->getAndKeywords(),
$this->getButKeywords()
));
}
}
<?php
namespace Behat\Gherkin\Keywords;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* File initializable keywords holder.
*
* $keywords = new Behat\Gherkin\Keywords\CachedArrayKeywords($file);
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class CachedArrayKeywords extends ArrayKeywords
{
/**
* Initializes holder with file.
*
* @param string $file Cached array path
*/
public function __construct($file)
{
parent::__construct(include($file));
}
}
<?php
namespace Behat\Gherkin\Keywords;
use Symfony\Component\Yaml\Yaml;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Cucumber-translations reader.
*
* $keywords = new Behat\Gherkin\Keywords\CucumberKeywords($i18nYmlPath);
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class CucumberKeywords extends ArrayKeywords
{
/**
* Initializes holder with yaml string OR file.
*
* @param string $yaml Yaml string
*/
public function __construct($yaml)
{
parent::__construct(Yaml::parse($yaml));
}
/**
* Returns Feature keywords (splitted by "|").
*
* @return string
*/
public function getGivenKeywords()
{
return $this->prepareStepString(parent::getGivenKeywords());
}
/**
* Returns When keywords (splitted by "|").
*
* @return string
*/
public function getWhenKeywords()
{
return $this->prepareStepString(parent::getWhenKeywords());
}
/**
* Returns Then keywords (splitted by "|").
*
* @return string
*/
public function getThenKeywords()
{
return $this->prepareStepString(parent::getThenKeywords());
}
/**
* Returns And keywords (splitted by "|").
*
* @return string
*/
public function getAndKeywords()
{
return $this->prepareStepString(parent::getAndKeywords());
}
/**
* Returns But keywords (splitted by "|").
*
* @return string
*/
public function getButKeywords()
{
return $this->prepareStepString(parent::getButKeywords());
}
/**
* Trim *| from the begining of the list.
*
* @param string $keywordsString Keywords string
*
* @return string
*/
private function prepareStepString($keywordsString)
{
if (0 === mb_strpos($keywordsString, '*|')) {
$keywordsString = mb_substr($keywordsString, 2);
}
return $keywordsString;
}
}
<?php
namespace Behat\Gherkin\Keywords;
use Behat\Gherkin\Keywords\KeywordsInterface;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Gherkin keywords dumper.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class KeywordsDumper
{
private $keywords;
private $keywordsDumper;
/**
* Initializes dumper.
*
* @param KeywordsInterface $keywords Keywords instance
*/
public function __construct(KeywordsInterface $keywords)
{
$this->keywords = $keywords;
$this->keywordsDumper = array($this, 'dumpKeywords');
}
/**
* Sets keywords mapper function.
*
* Callable should accept 2 arguments (array $keywords and Boolean $isShort)
*
* @param callable $mapper Mapper function
*/
public function setKeywordsDumperFunction($mapper)
{
$this->keywordsDumper = $mapper;
}
/**
* Defaults keywords dumper.
*
* @param array $keywords Keywords list
* @param Boolean $isShort Is short version
*
* @return string
*/
public function dumpKeywords(array $keywords, $isShort)
{
if ($isShort) {
return 1 < count($keywords) ? '('.implode('|', $keywords).')' : $keywords[0];
}
return $keywords[0];
}
/**
* Dumps keyworded feature into string.
*
* @param string $language Keywords language
* @param Boolean $short Dump short version
*
* @return string|array String for short version and array of features for extended
*/
public function dump($language, $short = true)
{
$this->keywords->setLanguage($language);
$languageComment = '';
if ('en' !== $language) {
$languageComment = "# language: $language\n";
}
$keywords = explode('|', $this->keywords->getFeatureKeywords());
if ($short) {
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
return trim($languageComment.$this->dumpFeature($keywords, $short));
}
$features = array();
foreach ($keywords as $keyword) {
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short);
$features[] = trim($languageComment.$this->dumpFeature($keyword, $short));
}
return $features;
}
/**
* Dumps feature example.
*
* @param string $keyword Item keyword
* @param Boolean $short Dump short version?
*
* @return string
*/
protected function dumpFeature($keyword, $short = true)
{
$dump = <<<GHERKIN
{$keyword}: Internal operations
In order to stay secret
As a secret organization
We need to be able to erase past agents' memory
GHERKIN;
// Background
$keywords = explode('|', $this->keywords->getBackgroundKeywords());
if ($short) {
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
$dump .= $this->dumpBackground($keywords, $short);
} else {
$keyword = call_user_func($this->keywordsDumper, array($keywords[0]), $short);
$dump .= $this->dumpBackground($keyword, $short);
}
// Scenario
$keywords = explode('|', $this->keywords->getScenarioKeywords());
if ($short) {
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
$dump .= $this->dumpScenario($keywords, $short);
} else {
foreach ($keywords as $keyword) {
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short);
$dump .= $this->dumpScenario($keyword, $short);
}
}
// Outline
$keywords = explode('|', $this->keywords->getOutlineKeywords());
if ($short) {
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
$dump .= $this->dumpOutline($keywords, $short);
} else {
foreach ($keywords as $keyword) {
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short);
$dump .= $this->dumpOutline($keyword, $short);
}
}
return $dump;
}
/**
* Dumps background example.
*
* @param string $keyword Item keyword
* @param Boolean $short Dump short version?
*
* @return string
*/
protected function dumpBackground($keyword, $short = true)
{
$dump = <<<GHERKIN
{$keyword}:
GHERKIN;
// Given
$dump .= $this->dumpStep(
$this->keywords->getGivenKeywords(), 'there is agent A', $short
);
// And
$dump .= $this->dumpStep(
$this->keywords->getAndKeywords(), 'there is agent B', $short
);
return $dump."\n";
}
/**
* Dumps scenario example.
*
* @param string $keyword Item keyword
* @param Boolean $short Dump short version?
*
* @return string
*/
protected function dumpScenario($keyword, $short = true)
{
$dump = <<<GHERKIN
{$keyword}: Erasing agent memory
GHERKIN;
// Given
$dump .= $this->dumpStep(
$this->keywords->getGivenKeywords(), 'there is agent J', $short
);
// And
$dump .= $this->dumpStep(
$this->keywords->getAndKeywords(), 'there is agent K', $short
);
// When
$dump .= $this->dumpStep(
$this->keywords->getWhenKeywords(), 'I erase agent K\'s memory', $short
);
// Then
$dump .= $this->dumpStep(
$this->keywords->getThenKeywords(), 'there should be agent J', $short
);
// But
$dump .= $this->dumpStep(
$this->keywords->getButKeywords(), 'there should not be agent K', $short
);
return $dump."\n";
}
/**
* Dumps outline example.
*
* @param string $keyword Item keyword
* @param Boolean $short Dump short version?
*
* @return string
*/
protected function dumpOutline($keyword, $short = true)
{
$dump = <<<GHERKIN
{$keyword}: Erasing other agents' memory
GHERKIN;
// Given
$dump .= $this->dumpStep(
$this->keywords->getGivenKeywords(), 'there is agent <agent1>', $short
);
// And
$dump .= $this->dumpStep(
$this->keywords->getAndKeywords(), 'there is agent <agent2>', $short
);
// When
$dump .= $this->dumpStep(
$this->keywords->getWhenKeywords(), 'I erase agent <agent2>\'s memory', $short
);
// Then
$dump .= $this->dumpStep(
$this->keywords->getThenKeywords(), 'there should be agent <agent1>', $short
);
// But
$dump .= $this->dumpStep(
$this->keywords->getButKeywords(), 'there should not be agent <agent2>', $short
);
$keywords = explode('|', $this->keywords->getExamplesKeywords());
if ($short) {
$keyword = call_user_func($this->keywordsDumper, $keywords, $short);
} else {
$keyword = call_user_func($this->keywordsDumper, array($keywords[0]), $short);
}
$dump .= <<<GHERKIN
{$keyword}:
| agent1 | agent2 |
| D | M |
GHERKIN;
return $dump."\n";
}
/**
* Dumps step example.
*
* @param string $keywords Item keyword
* @param string $text Step text
* @param Boolean $short Dump short version?
*
* @return string
*/
protected function dumpStep($keywords, $text, $short = true)
{
$dump = '';
$keywords = explode('|', $keywords);
if ($short) {
$keywords = array_map(function($keyword) {
return str_replace('<', '', $keyword);
}, $keywords);
$keywords = call_user_func($this->keywordsDumper, $keywords, $short);
$dump .= <<<GHERKIN
{$keywords} {$text}
GHERKIN;
} else {
foreach ($keywords as $keyword) {
$indent = ' ';
if (false !== mb_strpos($keyword, '<')) {
$keyword = mb_substr($keyword, 0, -1);
$indent = '';
}
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short);
$dump .= <<<GHERKIN
{$keyword}{$indent}{$text}
GHERKIN;
}
}
return $dump;
}
}
<?php
namespace Behat\Gherkin\Keywords;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Keywords holder interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface KeywordsInterface
{
/**
* Sets keywords holder language.
*
* @param string $language Language name
*/
function setLanguage($language);
/**
* Returns Feature keywords (splitted by "|").
*
* @return string
*/
function getFeatureKeywords();
/**
* Returns Background keywords (splitted by "|").
*
* @return string
*/
function getBackgroundKeywords();
/**
* Returns Scenario keywords (splitted by "|").
*
* @return string
*/
function getScenarioKeywords();
/**
* Returns Scenario Outline keywords (splitted by "|").
*
* @return string
*/
function getOutlineKeywords();
/**
* Returns Examples keywords (splitted by "|").
*
* @return string
*/
function getExamplesKeywords();
/**
* Returns Given keywords (splitted by "|").
*
* @return string
*/
function getGivenKeywords();
/**
* Returns When keywords (splitted by "|").
*
* @return string
*/
function getWhenKeywords();
/**
* Returns Then keywords (splitted by "|").
*
* @return string
*/
function getThenKeywords();
/**
* Returns And keywords (splitted by "|").
*
* @return string
*/
function getAndKeywords();
/**
* Returns But keywords (splitted by "|").
*
* @return string
*/
function getButKeywords();
/**
* Returns all step keywords (splitted by "|").
*
* @return string
*/
function getStepKeywords();
}
<?php
namespace Behat\Gherkin\Keywords;
use Symfony\Component\Finder\Finder,
Symfony\Component\Translation\Translator,
Symfony\Component\Translation\Loader\XliffFileLoader;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Symfony Translation Component's keywords holder.
*
* $translator = new Symfony\Component\Translation\Translator('en', new Symfony\Component\Translation\MessageSelector());
* $translator->addLoader(...);
* $translator->addResource(...);
* ...
* $translator->addResource(...);
*
* $keywords = new Behat\Gherkin\Keywords\SymfonyTranslationKeywords($translator);
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class SymfonyTranslationKeywords implements KeywordsInterface
{
private $translator;
private $locale = 'en';
/**
* Initializes keywords holder.
*
* @param Translator $translator Translator instance
*/
public function __construct(Translator $translator)
{
$this->translator = $translator;
}
/**
* Sets keywords holder language.
*
* @param string $language Language name
*/
public function setLanguage($language)
{
$this->locale = $language;
}
/**
* Returns Feature keywords (splitted by "|").
*
* @return string
*/
public function getFeatureKeywords()
{
return $this->translator->trans('Feature', array(), 'gherkin', $this->locale);
}
/**
* Returns Background keywords (splitted by "|").
*
* @return string
*/
public function getBackgroundKeywords()
{
return $this->translator->trans('Background', array(), 'gherkin', $this->locale);
}
/**
* Returns Scenario keywords (splitted by "|").
*
* @return string
*/
public function getScenarioKeywords()
{
return $this->translator->trans('Scenario', array(), 'gherkin', $this->locale);
}
/**
* Returns Scenario Outline keywords (splitted by "|").
*
* @return string
*/
public function getOutlineKeywords()
{
return $this->translator->trans('Scenario Outline', array(), 'gherkin', $this->locale);
}
/**
* Returns Examples keywords (splitted by "|").
*
* @return string
*/
public function getExamplesKeywords()
{
return $this->translator->trans('Examples', array(), 'gherkin', $this->locale);
}
/**
* Returns Given keywords (splitted by "|").
*
* @return string
*/
public function getGivenKeywords()
{
}
/**
* Returns When keywords (splitted by "|").
*
* @return string
*/
public function getWhenKeywords()
{
}
/**
* Returns Then keywords (splitted by "|").
*
* @return string
*/
public function getThenKeywords()
{
}
/**
* Returns And keywords (splitted by "|").
*
* @return string
*/
public function getAndKeywords()
{
}
/**
* Returns But keywords (splitted by "|").
*
* @return string
*/
public function getButKeywords()
{
}
/**
* Returns all step keywords (splitted by "|").
*
* @return string
*/
public function getStepKeywords()
{
return $this->translator->trans('Given|When|Then|And|But', array(), 'gherkin', $this->locale);
}
}
<?php
namespace Behat\Gherkin;
use Behat\Gherkin\Exception\LexerException,
Behat\Gherkin\Keywords\KeywordsInterface;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Gherkin lexer.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Lexer
{
private $lines;
private $line;
private $lineNumber;
private $eos;
private $keywords;
private $keywordsCache = array();
private $deferredObjects = array();
private $stash = array();
private $inPyString = false;
private $pyStringSwallow = 0;
private $featureStarted = false;
private $allowMultilineArguments = false;
private $allowSteps = false;
/**
* Initializes lexer.
*
* @param KeywordsInterface $keywords Keywords holder
*/
public function __construct(KeywordsInterface $keywords)
{
$this->keywords = $keywords;
}
/**
* Sets lexer input.
*
* @param string $input Input string
*/
public function setInput($input)
{
// try to detect unsupported encoding
if ('UTF-8' !== mb_detect_encoding($input, 'UTF-8', true)) {
throw new LexerException('Feature file is not in UTF8 encoding');
}
$input = strtr($input, array("\r\n" => "\n", "\r" => "\n"));
$this->lines = explode("\n", $input);
$this->line = array_shift($this->lines);
$this->lineNumber = 1;
$this->eos = false;
$this->deferredObjects = array();
$this->stash = array();
$this->inPyString = false;
$this->pyStringSwallow = 0;
$this->featureStarted = false;
$this->allowMultilineArguments = false;
$this->allowSteps = false;
}
/**
* Sets keywords language.
*
* @param string $language Language name
*/
public function setLanguage($language)
{
$this->keywords->setLanguage($language);
$this->keywordsCache = array();
}
/**
* Returns next token or previously stashed one.
*
* @return stdClass
*/
public function getAdvancedToken()
{
return $this->getStashedToken() ?: $this->getNextToken();
}
/**
* Defers token.
*
* @param stdClass $token Token to defer
*/
public function deferToken(\stdClass $token)
{
$token->defered = true;
$this->deferredObjects[] = $token;
}
/**
* Predicts for number of tokens.
*
* @param integer $number Number of tokens to predict
*
* @return stdClass
*/
public function predictToken($number = 1)
{
$fetch = $number - count($this->stash);
while ($fetch-- > 0) {
$this->stash[] = $this->getNextToken();
}
return $this->stash[--$number];
}
/**
* Constructs token with specified parameters.
*
* @param string $type Token type
* @param string $value Token value
*
* @return stdClass
*/
public function takeToken($type, $value = null)
{
return (Object) array(
'type' => $type,
'line' => $this->lineNumber,
'value' => $value ?: null,
'defered' => false
);
}
/**
* Consumes line from input & increments line counter.
*/
protected function consumeLine()
{
++$this->lineNumber;
if (!count($this->lines)) {
$this->eos = true;
return false;
}
$this->line = array_shift($this->lines);
}
/**
* Returns stashed token or false if hasn't.
*
* @return stdClass|Boolean
*/
protected function getStashedToken()
{
return count($this->stash) ? array_shift($this->stash) : null;
}
/**
* Returns deferred token or false if hasn't.
*
* @return stdClass|Boolean
*/
protected function getDeferredToken()
{
return count($this->deferredObjects) ? array_shift($this->deferredObjects) : null;
}
/**
* Returns next token from input.
*
* @return stdClass
*/
protected function getNextToken()
{
return $this->getDeferredToken()
?: $this->scanEOS()
?: $this->scanLanguage()
?: $this->scanComment()
?: $this->scanPyStringOperator()
?: $this->scanPyStringContent()
?: $this->scanStep()
?: $this->scanScenario()
?: $this->scanBackground()
?: $this->scanOutline()
?: $this->scanExamples()
?: $this->scanFeature()
?: $this->scanTags()
?: $this->scanTableRow()
?: $this->scanNewline()
?: $this->scanText();
}
/**
* Scans for token with specified regex.
*
* @param string $regex Regular expression
* @param string $type Expected token type
*
* @return stdClass|null
*/
protected function scanInput($regex, $type)
{
$matches = array();
if (preg_match($regex, $this->line, $matches)) {
$token = $this->takeToken($type, $matches[1]);
$this->consumeLine();
return $token;
}
}
/**
* Scans for token with specified keywords.
*
* @param string $keywords Keywords (splitted with |)
* @param string $type Expected token type
*
* @return stdClass|null
*/
protected function scanInputForKeywords($keywords, $type)
{
$matches = array();
if (preg_match('/^(\s*)('.$keywords.'):\s*(.*)/u', $this->line, $matches)) {
$token = $this->takeToken($type, $matches[3]);
$token->keyword = $matches[2];
$token->indent = mb_strlen($matches[1]);
$this->consumeLine();
// turn off language searching
if ('Feature' === $type) {
$this->featureStarted = true;
}
// turn off PyString and Table searching
if (in_array($type, array('Feature', 'Scenario', 'Outline'))) {
$this->allowMultilineArguments = false;
} elseif ('Examples' === $type) {
$this->allowMultilineArguments = true;
}
// turn on steps searching
if (in_array($type, array('Scenario', 'Background', 'Outline'))) {
$this->allowSteps = true;
}
return $token;
}
}
/**
* Scans EOS from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanEOS()
{
if (!$this->eos) {
return;
}
return $this->takeToken('EOS');
}
/**
* Returns keywords for provided type.
*
* @param string $type Keyword type
*
* @return string
*/
protected function getKeywords($type)
{
if (!isset($this->keywordsCache[$type])) {
$getter = 'get' . $type . 'Keywords';
$keywords = $this->keywords->$getter();
if ('Step' === $type) {
$paded = array();
foreach (explode('|', $keywords) as $keyword) {
$paded[] = false !== mb_strpos($keyword, '<')
? mb_substr($keyword, 0, -1).'\s*'
: $keyword.'\s+';
}
$keywords = implode('|', $paded);
}
$this->keywordsCache[$type] = $keywords;
}
return $this->keywordsCache[$type];
}
/**
* Scans Feature from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanFeature()
{
return $this->scanInputForKeywords($this->getKeywords('Feature'), 'Feature');
}
/**
* Scans Background from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanBackground()
{
return $this->scanInputForKeywords($this->getKeywords('Background'), 'Background');
}
/**
* Scans Scenario from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanScenario()
{
return $this->scanInputForKeywords($this->getKeywords('Scenario'), 'Scenario');
}
/**
* Scans Scenario Outline from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanOutline()
{
return $this->scanInputForKeywords($this->getKeywords('Outline'), 'Outline');
}
/**
* Scans Scenario Outline Examples from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanExamples()
{
return $this->scanInputForKeywords($this->getKeywords('Examples'), 'Examples');
}
/**
* Scans Step from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanStep()
{
if (!$this->allowSteps) {
return;
}
$matches = array();
$keywords = $this->getKeywords('Step');
if (preg_match('/^\s*('.$keywords.')([^\s].+)/u', $this->line, $matches)) {
$token = $this->takeToken('Step', trim($matches[1]));
$token->text = $matches[2];
$this->consumeLine();
$this->allowMultilineArguments = true;
return $token;
}
}
/**
* Scans PyString from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanPyStringOperator()
{
if (!$this->allowMultilineArguments) {
return;
}
$matches = array();
if (false !== ($pos = mb_strpos($this->line, '"""'))) {
$this->inPyString =! $this->inPyString;
$token = $this->takeToken('PyStringOperator');
$this->pyStringSwallow = $pos;
$this->consumeLine();
return $token;
}
}
/**
* Scans PyString content.
*
* @return stdClass|null
*/
protected function scanPyStringContent()
{
if ($this->inPyString) {
$token = $this->scanText();
// swallow trailing spaces
$token->value = preg_replace('/^\s{0,'.$this->pyStringSwallow.'}/', '', $token->value);
return $token;
}
}
/**
* Scans Table Row from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanTableRow()
{
if (!$this->allowMultilineArguments) {
return;
}
$line = trim($this->line);
if (isset($line[0]) && '|' === $line[0]) {
$token = $this->takeToken('TableRow');
$line = mb_substr($line, 1, mb_strlen($line) - 2);
$columns = array_map(function($column) {
return trim(str_replace('\\|', '|', $column));
}, preg_split('/(?<!\\\)\|/', $line));
$token->columns = $columns;
$this->consumeLine();
return $token;
}
}
/**
* Scans Tags from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanTags()
{
$line = trim($this->line);
if (isset($line[0]) && '@' === $line[0]) {
$token = $this->takeToken('Tag');
$tags = explode('@', mb_substr($line, 1));
$tags = array_map(function($tag){
return trim($tag);
}, $tags);
$token->tags = $tags;
$this->consumeLine();
return $token;
}
}
/**
* Scans Language specifier from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanLanguage()
{
if ($this->featureStarted) {
return;
}
if (!$this->inPyString) {
if (0 === mb_strpos(ltrim($this->line), '#') && false !== mb_strpos($this->line, 'language')) {
return $this->scanInput('/^\s*\#\s*language:\s*([\w_\-]+)\s*$/', 'Language');
}
}
}
/**
* Scans Comment from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanComment()
{
if (!$this->inPyString) {
if (0 === mb_strpos(ltrim($this->line), '#')) {
$token = $this->takeToken('Comment', $this->line);
$this->consumeLine();
return $token;
}
}
}
/**
* Scans Newline from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanNewline()
{
if ('' === trim($this->line)) {
$token = $this->takeToken('Newline', mb_strlen($this->line));
$this->consumeLine();
return $token;
}
}
/**
* Scans text from input & returns it if found.
*
* @return stdClass|null
*/
protected function scanText()
{
$token = $this->takeToken('Text', $this->line);
$this->consumeLine();
return $token;
}
}
<?php
namespace Behat\Gherkin\Loader;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Abstract filesystem loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class AbstractFileLoader implements FileLoaderInterface
{
protected $basePath;
/**
* Sets base features path.
*
* @param string $path Base loader path
*/
public function setBasePath($path)
{
$this->basePath = realpath($path);
}
/**
* Finds relative path for provided absolute (relative to base features path).
*
* @param string $path Absolute path
*
* @return string
*/
protected function findRelativePath($path)
{
if (null !== $this->basePath) {
return strtr($path, array($this->basePath . DIRECTORY_SEPARATOR => ''));
}
return $path;
}
/**
* Finds absolute path for provided relative (relative to base features path).
*
* @param string $path Relative path
*
* @return string
*/
protected function findAbsolutePath($path)
{
if (is_file($path) || is_dir($path)) {
return realpath($path);
} elseif (is_file($this->basePath . DIRECTORY_SEPARATOR . $path)
|| is_dir($this->basePath . DIRECTORY_SEPARATOR . $path)) {
return realpath($this->basePath . DIRECTORY_SEPARATOR . $path);
}
return false;
}
}
<?php
namespace Behat\Gherkin\Loader;
use Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* From-array loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ArrayLoader implements LoaderInterface
{
/**
* Checks if current loader supports provided resource.
*
* @param mixed $resource Resource to load
*
* @return Boolean
*/
public function supports($resource)
{
return is_array($resource) && (isset($resource['features']) || isset($resource['feature']));
}
/**
* Loads features from provided resource.
*
* @param mixed $resource Resource to load
*
* @return array
*/
public function load($resource)
{
$features = array();
if (isset($resource['features'])) {
foreach ($resource['features'] as $iterator => $hash) {
$feature = $this->loadFeatureHash($hash, $iterator);
$features[] = $feature;
}
} elseif (isset($resource['feature'])) {
$feature = $this->loadFeatureHash($resource['feature'], 0);
$features[] = $feature;
}
return $features;
}
/**
* Loads feature from provided feature hash.
*
* @param array $hash Feature hash
* @param integer $line Feature definition line
*
* @return FeatureNode
*/
protected function loadFeatureHash(array $hash, $line = 0)
{
$feature = new Node\FeatureNode(null, null, null, isset($hash['line']) ? $hash['line'] : $line);
$feature->setKeyword(isset($hash['keyword']) ? $hash['keyword'] : 'Feature');
if (isset($hash['title'])) {
$feature->setTitle($hash['title']);
}
if (isset($hash['description'])) {
$feature->setDescription($hash['description']);
}
if (isset($hash['tags'])) {
$feature->setTags($hash['tags']);
}
if (isset($hash['language'])) {
$feature->setLanguage($hash['language']);
}
if (isset($hash['background'])) {
$feature->setBackground($this->loadBackgroundHash($hash['background']));
}
if (isset($hash['scenarios'])) {
foreach ($hash['scenarios'] as $scenarioIterator => $scenarioHash) {
if (isset($scenarioHash['type']) && 'outline' === $scenarioHash['type']) {
$feature->addScenario($this->loadOutlineHash($scenarioHash, $scenarioIterator));
} else {
$feature->addScenario($this->loadScenarioHash($scenarioHash, $scenarioIterator));
}
}
}
return $feature;
}
/**
* Loads background from provided hash.
*
* @param array $hash Background hash
*
* @return BackgroundNode
*/
protected function loadBackgroundHash(array $hash)
{
$background = new Node\BackgroundNode(null, isset($hash['line']) ? $hash['line'] : 0);
$background->setKeyword(isset($hash['keyword']) ? $hash['keyword'] : 'Background');
if (isset($hash['title'])) {
$background->setTitle($hash['title']);
}
if (isset($hash['steps'])) {
foreach ($hash['steps'] as $stepIterator => $stepHash) {
$background->addStep($this->loadStepHash($stepHash, $stepIterator));
}
}
return $background;
}
/**
* Loads scenario from provided scenario hash.
*
* @param array $hash Scenario hash
* @param integer $line Scenario definition line
*
* @return ScenarioNode
*/
protected function loadScenarioHash(array $hash, $line = 0)
{
$scenario = new Node\ScenarioNode(null, isset($hash['line']) ? $hash['line'] : $line);
$scenario->setKeyword(isset($hash['keyword']) ? $hash['keyword'] : 'Scenario');
if (isset($hash['title'])) {
$scenario->setTitle($hash['title']);
}
if (isset($hash['tags'])) {
$scenario->setTags($hash['tags']);
}
if (isset($hash['steps'])) {
foreach ($hash['steps'] as $stepIterator => $stepHash) {
$scenario->addStep($this->loadStepHash($stepHash, $stepIterator));
}
}
return $scenario;
}
/**
* Loads outline from provided outline hash.
*
* @param array $hash Outline hash
* @param integer $line Outline definition line
*
* @return OutlineNode
*/
protected function loadOutlineHash(array $hash, $line = 0)
{
$outline = new Node\OutlineNode(null, isset($hash['line']) ? $hash['line'] : $line);
$outline->setKeyword(isset($hash['keyword']) ? $hash['keyword'] : 'Scenario Outline');
if (isset($hash['title'])) {
$outline->setTitle($hash['title']);
}
if (isset($hash['tags'])) {
$outline->setTags($hash['tags']);
}
if (isset($hash['examples'])) {
if (isset($hash['examples']['keyword'])) {
$keyword = $hash['examples']['keyword'];
unset($hash['examples']['keyword']);
} else {
$keyword = 'Examples';
}
$table = $this->loadTableHash($hash['examples']);
$table->setKeyword($keyword);
$outline->setExamples($table);
}
if (isset($hash['steps'])) {
foreach ($hash['steps'] as $stepIterator => $stepHash) {
$outline->addStep($this->loadStepHash($stepHash, $stepIterator));
}
}
return $outline;
}
/**
* Loads step from provided hash.
*
* @param array $hash Step hash
* @param integer $line Step definition line
*
* @return StepNode
*/
protected function loadStepHash(array $hash, $line = 0)
{
$step = new Node\StepNode(
$hash['type'], isset($hash['text']) ? $hash['text'] : null, isset($hash['line']) ? $hash['line'] : $line
);
if (isset($hash['arguments'])) {
foreach ($hash['arguments'] as $argumentHash) {
if ('table' === $argumentHash['type']) {
$step->addArgument($this->loadTableHash($argumentHash['rows']));
} elseif ('pystring' === $argumentHash['type']) {
$step->addArgument($this->loadPyStringHash($argumentHash));
}
}
}
return $step;
}
/**
* Loads table from provided hash.
*
* @param array $hash Table hash
*
* @return TableNode
*/
protected function loadTableHash(array $hash)
{
$table = new Node\TableNode();
foreach ($hash as $row) {
$table->addRow($row);
}
return $table;
}
/**
* Loads PyString from provided hash.
*
* @param array $hash PyString hash
*
* @return PyStringNode
*/
protected function loadPyStringHash(array $hash)
{
$string = new Node\PyStringNode($hash['text']);
return $string;
}
}
<?php
namespace Behat\Gherkin\Loader;
use Symfony\Component\Finder\Finder;
use Behat\Gherkin\Gherkin;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Directory contents loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class DirectoryLoader extends AbstractFileLoader
{
protected $gherkin;
/**
* Initializes loader.
*
* @param Gherkin $gherkin Gherkin manager
*/
public function __construct(Gherkin $gherkin)
{
$this->gherkin = $gherkin;
}
/**
* Checks if current loader supports provided resource.
*
* @param mixed $resource Resource to load
*
* @return Boolean
*/
public function supports($path)
{
return is_string($path)
&& is_dir($this->findAbsolutePath($path));
}
/**
* Loads features from provided resource.
*
* @param mixed $resource Resource to load
*
* @return array
*/
public function load($path)
{
$path = $this->findAbsolutePath($path);
$finder = new Finder();
$iterator = $finder->files()->in($path);
$features = array();
foreach ($iterator as $path) {
$path = (string) $path;
$loader = $this->gherkin->resolveLoader($path);
if (null !== $loader) {
$features = array_merge($features, $loader->load($path));
}
}
return $features;
}
}
<?php
namespace Behat\Gherkin\Loader;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* File Loader interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface FileLoaderInterface extends LoaderInterface
{
/**
* Sets base features path.
*
* @param string $path Base loader path
*/
function setBasePath($path);
}
<?php
namespace Behat\Gherkin\Loader;
use Symfony\Component\Finder\Finder;
use Behat\Gherkin\Parser,
Behat\Gherkin\Cache\CacheInterface;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Gherkin *.feature files loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class GherkinFileLoader extends AbstractFileLoader
{
protected $parser;
protected $cache;
/**
* Initializes loader.
*
* @param Parser $parser Parser
* @param CacheInterface $cache Cache layer
*/
public function __construct(Parser $parser, CacheInterface $cache = null)
{
$this->parser = $parser;
$this->cache = $cache;
}
/**
* Sets cache layer.
*
* @param CacheInterface $cache Cache layer
*/
public function setCache(CacheInterface $cache)
{
$this->cache = $cache;
}
/**
* Checks if current loader supports provided resource.
*
* @param mixed $resource Resource to load
*
* @return Boolean
*/
public function supports($path)
{
return is_string($path)
&& is_file($absolute = $this->findAbsolutePath($path))
&& 'feature' === pathinfo($absolute, PATHINFO_EXTENSION);
}
/**
* Loads features from provided resource.
*
* @param mixed $resource Resource to load
*
* @return array
*/
public function load($path)
{
$path = $this->findAbsolutePath($path);
if ($this->cache) {
if ($this->cache->isFresh($path, filemtime($path))) {
$feature = $this->cache->read($path);
} else {
$feature = $this->parseFeature($path);
$this->cache->write($path, $feature);
}
} else {
$feature = $this->parseFeature($path);
}
return array($feature);
}
/**
* Parses feature at provided absolute path.
*
* @param string $path Feature path
*
* @return FeatureNode
*/
protected function parseFeature($path)
{
$filename = $this->findRelativePath($path);
$content = file_get_contents($path);
$feature = $this->parser->parse($content, $filename);
return $feature;
}
}
<?php
namespace Behat\Gherkin\Loader;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loader interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface LoaderInterface
{
/**
* Checks if current loader supports provided resource.
*
* @param mixed $resource Resource to load
*
* @return Boolean
*/
function supports($resource);
/**
* Loads features from provided resource.
*
* @param mixed $resource Resource to load
*
* @return array
*/
function load($resource);
}
<?php
namespace Behat\Gherkin\Loader;
use Symfony\Component\Yaml\Yaml;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Yaml files loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class YamlFileLoader extends ArrayLoader implements FileLoaderInterface
{
protected $basePath;
/**
* Checks if current loader supports provided resource.
*
* @param mixed $resource Resource to load
*
* @return Boolean
*/
public function supports($path)
{
return is_string($path)
&& is_file($absolute = $this->findAbsolutePath($path))
&& 'yml' === pathinfo($absolute, PATHINFO_EXTENSION);
}
/**
* Loads features from provided resource.
*
* @param mixed $resource Resource to load
*
* @return array
*/
public function load($path)
{
$path = $this->findAbsolutePath($path);
$hash = Yaml::parse($path);
$features = parent::load($hash);
$filename = $this->findRelativePath($path);
foreach ($features as $feature) {
$feature->setFile($filename);
}
return $features;
}
/**
* Sets base features path.
*
* @param string $path Base loader path
*/
public function setBasePath($path)
{
$this->basePath = realpath($path);
}
/**
* Finds relative path for provided absolute (relative to base features path).
*
* @param string $path Absolute path
*
* @return string
*/
protected function findRelativePath($path)
{
if (null !== $this->basePath) {
return strtr($path, array($this->basePath . DIRECTORY_SEPARATOR => ''));
}
return $path;
}
/**
* Finds absolute path for provided relative (relative to base features path).
*
* @param string $path Relative path
*
* @return string
*/
protected function findAbsolutePath($path)
{
if (is_file($path) || is_dir($path)) {
return realpath($path);
} elseif (is_file($this->basePath . DIRECTORY_SEPARATOR . $path)
|| is_dir($this->basePath . DIRECTORY_SEPARATOR . $path)) {
return realpath($this->basePath . DIRECTORY_SEPARATOR . $path);
}
return false;
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Abstract Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class AbstractNode
{
private $line;
private $keyword;
/**
* Initializes node.
*
* @param integer $line Line number
*/
public function __construct($line = 0)
{
$this->line = $line;
}
/**
* Accepts specific visitor & visits current node.
*
* @param NodeVisitorInterface $visitor Node visitor
*
* @return mixed
*/
public function accept(NodeVisitorInterface $visitor)
{
return $visitor->visit($this);
}
/**
* Returns node line number.
*
* @return integer
*/
public function getLine()
{
return $this->line;
}
/**
* Sets current node definition keyword.
*
* @param string $keyword Keyword
*/
public function setKeyword($keyword)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen node keyword.');
}
$this->keyword = $keyword;
}
/**
* Returns current node definition keyword.
*
* @return string
*/
public function getKeyword()
{
return $this->keyword;
}
/**
* Checks whether node has been frozen.
*
* @return Boolean
*/
abstract public function isFrozen();
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Abstract Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class AbstractScenarioNode extends AbstractNode
{
protected $title;
protected $steps = array();
protected $feature;
/**
* Initializes scenario.
*
* @param string $title Scenario title
* @param integer $line Definition line
*/
public function __construct($title = null, $line = 0)
{
parent::__construct($line);
$this->title = $title;
}
/**
* Sets scenario title.
*
* @param string $title Scenario title
*/
public function setTitle($title)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change scenario/background title in frozen feature.');
}
$this->title = $title;
}
/**
* Returns scenario title.
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Adds step to the node.
*
* @param StepNode $step Step
*/
public function addStep(StepNode $step)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change scenario/background steps in frozen feature.');
}
$step->setParent($this);
$this->steps[] = $step;
}
/**
* Sets scenario steps.
*
* @param array $steps Array of StepNode
*/
public function setSteps(array $steps)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change scenario/background steps in frozen feature.');
}
$this->steps = array();
foreach ($steps as $step) {
$this->addStep($step);
}
}
/**
* Checks if node has steps.
*
* @return Boolean
*/
public function hasSteps()
{
return count($this->steps) > 0;
}
/**
* Returns scenario steps.
*
* @return array
*/
public function getSteps()
{
return $this->steps;
}
/**
* Sets parent feature of the node.
*
* @param FeatureNode $feature Feature instance
*/
public function setFeature(FeatureNode $feature)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to reassign scenario/background in frozen feature.');
}
$this->feature = $feature;
}
/**
* Returns parent feature of the node.
*
* @return FeatureNode
*/
public function getFeature()
{
return $this->feature;
}
/**
* Returns definition file.
*
* @return string
*/
public function getFile()
{
return null !== $this->feature
? $this->feature->getFile()
: null;
}
/**
* Returns language of the feature.
*
* @return string
*/
public function getLanguage()
{
return null !== $this->feature
? $this->feature->getLanguage()
: null;
}
/**
* Checks whether scenario has been frozen.
*
* @return Boolean
*/
public function isFrozen()
{
return null !== $this->feature
? $this->feature->isFrozen()
: false;
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Background Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BackgroundNode extends AbstractScenarioNode
{
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* PyString Argument for outline examples row Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ExamplePyStringNode extends PyStringNode
{
private $cleanLines = array();
/**
* Initializes PyString.
*
* @param PyStringNode $simpleString String from which this example string should be created
* @param array $tokens Replacement tokens values
*/
public function __construct(PyStringNode $simpleString, array $tokens)
{
$this->cleanLines = $lines = $simpleString->getLines();
foreach ($tokens as $key => $value) {
foreach (array_keys($lines) as $line) {
$lines[$line] = str_replace('<'.$key.'>', $value, $lines[$line]);
}
}
$this->setLines($lines);
}
/**
* Returns not replaced with tokens string lines.
*
* @return array
*/
public function getCleanLines()
{
return $this->cleanLines;
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Outline example step Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ExampleStepNode extends StepNode
{
private $cleanText;
/**
* Initizalizes step.
*
* @param StepNode $simpleStep Initial step
* @param array $tokens Example table row tokens
*/
public function __construct(StepNode $simpleStep, array $tokens)
{
$text = $this->cleanText = $simpleStep->getText();
foreach ($tokens as $key => $value) {
$text = str_replace('<' . $key . '>', $value, $text);
}
parent::__construct(
$simpleStep->getType(),
$text,
$simpleStep->getLine()
);
foreach ($simpleStep->getArguments() as $argument) {
if ($argument instanceof TableNode || $argument instanceof PyStringNode) {
$this->addArgument($argument->createExampleRowStepArgument($tokens));
}
}
$this->setParent($simpleStep->getParent());
}
/**
* Returns untokenized step text.
*
* @return string
*/
public function getCleanText()
{
return $this->cleanText;
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Table Argument Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ExampleTableNode extends TableNode
{
private $cleanRows = array();
/**
* Initializes table.
*
* @param string $table Initial table string
*/
public function __construct(TableNode $cleanTable, array $tokens)
{
$this->cleanRows = $rows = $cleanTable->getRows();
foreach ($tokens as $key => $value) {
foreach (array_keys($rows) as $row) {
foreach (array_keys($rows[$row]) as $col) {
$rows[$row][$col] = str_replace('<'.$key.'>', $value, $rows[$row][$col]);
}
}
}
$this->setKeyword($cleanTable->getKeyword());
$this->setRows($rows);
}
/**
* Returns rows without tokens being replaced.
*
* @return array
*/
public function getCleanRows()
{
return $this->cleanRows();
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Feature Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class FeatureNode extends AbstractNode
{
private $title;
private $description;
private $file;
private $background;
private $language = 'en';
private $scenarios = array();
private $tags = array();
private $frozen = false;
/**
* Initializes feature.
*
* @param string $title Feature title
* @param string $description Feature description (3-liner)
* @param string $file Feature filename
* @param integer $line Definition line
*/
public function __construct($title = null, $description = null, $file = null, $line = 0)
{
parent::__construct($line);
$this->title = $title;
$this->description = $description;
$this->file = $file;
}
/**
* Sets feature title.
*
* @param string $title Feature title
*/
public function setTitle($title)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature title.');
}
$this->title = $title;
}
/**
* Returns feature title.
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Sets feature description (narrative).
*
* @param string $description Feature description
*/
public function setDescription($description)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature description.');
}
$this->description = $description;
}
/**
* Returns feature description (narrative).
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Sets language of the feature.
*
* @param string $language Langauge name
*/
public function setLanguage($language)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature language.');
}
$this->language = $language;
}
/**
* Returns language of the feature.
*
* @return string
*/
public function getLanguage()
{
return $this->language;
}
/**
* Sets feature background.
*
* @param BackgroundNode $background Background instance
*/
public function setBackground(BackgroundNode $background)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature background.');
}
$background->setFeature($this);
$this->background = $background;
}
/**
* Checks if feature has background.
*
* @return Boolean
*/
public function hasBackground()
{
return null !== $this->background;
}
/**
* Returns feature background.
*
* @return BackgroundNode
*/
public function getBackground()
{
return $this->background;
}
/**
* Adds scenario or outline to the feature.
*
* @param ScenarioNode $scenario Scenario instance
*/
public function addScenario(ScenarioNode $scenario)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature scenarios.');
}
$scenario->setFeature($this);
$this->scenarios[] = $scenario;
}
/**
* Sets scenarios & outlines to the feature.
*
* @param array $scenarios Array of ScenariosNode's or OutlineNode's
*/
public function setScenarios(array $scenarios)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature scenarios.');
}
$this->scenarios = array();
foreach ($scenarios as $scenario) {
$this->addScenario($scenario);
}
}
/**
* Checks that feature has scenarios.
*
* @return Boolean
*/
public function hasScenarios()
{
return count($this->scenarios) > 0;
}
/**
* Returns feature scenarios & outlines.
*
* @return array
*/
public function getScenarios()
{
return $this->scenarios;
}
/**
* Sets feature tags.
*
* @param array $tags Array of tags
*/
public function setTags(array $tags)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature tags.');
}
$this->tags = $tags;
}
/**
* Adds tag to the feature.
*
* @param string $tag Tag name
*/
public function addTag($tag)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature tags.');
}
$this->tags[] = $tag;
}
/**
* Checks if the feature has tags.
*
* @return Boolean
*/
public function hasTags()
{
return count($this->getTags()) > 0;
}
/**
* Checks if the feature has tag.
*
* @param string $tag Tag name
*
* @return Boolean
*/
public function hasTag($tag)
{
return in_array($tag, $this->getTags());
}
/**
* Returns feature tags.
*
* @return array
*/
public function getTags()
{
return $this->tags;
}
/**
* Returns only own tags (without inherited ones).
*
* @return array
*/
public function getOwnTags()
{
return $this->tags;
}
/**
* Sets feature filename.
*
* @param string $path Sets feature file
*/
public function setFile($path)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change frozen feature.');
}
$this->file = $path;
}
/**
* Returns feature filename.
*
* @return string
*/
public function getFile()
{
return $this->file;
}
/**
* Freeze feature to changes.
* Prevents feature modification in future
*/
public function freeze()
{
$this->frozen = true;
}
/**
* Checks whether feature has been frozen.
*
* @return Boolean
*/
public function isFrozen()
{
return $this->frozen;
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Node Visitor Interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface NodeVisitorInterface
{
/**
* Visits specific node.
*
* @param AbstractNode $visitee Visitee object
*
* @return mixed
*/
function visit(AbstractNode $visitee);
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Scenario Outline Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class OutlineNode extends ScenarioNode
{
private $examples;
/**
* Sets outline examples table.
*
* @param TableNode $examples Examples table
*/
public function setExamples(TableNode $examples)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change outline examples in frozen feature.');
}
$this->examples = $examples;
}
/**
* Checks if outline has examples.
*
* @return Boolean
*/
public function hasExamples()
{
return null !== $this->examples;
}
/**
* Returns examples table.
*
* @return TableNode
*/
public function getExamples()
{
return $this->examples;
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* PyString Argument Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class PyStringNode implements StepArgumentNodeInterface
{
private $lines = array();
/**
* Initializes PyString.
*
* @param string $string Initial string
*/
public function __construct($string = null)
{
if (null !== $string) {
$string = preg_replace("/\r\n|\r/", "\n", $string);
$this->lines = explode("\n", $string);
}
}
/**
* Returns new PyString node with replaced outline example row tokens.
*
* @return ExamplePyStringNode
*/
public function createExampleRowStepArgument(array $tokens)
{
return new ExamplePyStringNode($this, $tokens);
}
/**
* Adds a line to the PyString.
*
* @param string $line Line of text
*/
public function addLine($line)
{
$this->lines[] = $line;
}
/**
* Sets PyString lines.
*
* @param array $lines Array of text lines
*/
public function setLines(array $lines)
{
$this->lines = $lines;
}
/**
* Returns PyString lines.
*
* @return array
*/
public function getLines()
{
return $this->lines;
}
/**
* Returns raw string.
*
* @return string
*/
public function getRaw()
{
return implode("\n", $this->lines);
}
/**
* Converts PyString into string.
*
* @return string
*/
public function __toString()
{
return $this->getRaw();
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Scenario Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ScenarioNode extends AbstractScenarioNode
{
private $tags = array();
/**
* Sets scenario tags.
*
* @param array $tags Array of tag names
*/
public function setTags(array $tags)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change scenario tags in frozen feature.');
}
$this->tags = $tags;
}
/**
* Adds tag to scenario.
*
* @param string $tag Tag name
*/
public function addTag($tag)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change scenario tags in frozen feature.');
}
$this->tags[] = $tag;
}
/**
* Checks if scenario has tags.
*
* @return Boolean
*/
public function hasTags()
{
return count($this->getTags()) > 0;
}
/**
* Checks if scenario has tag.
*
* @param string $tag
*
* @return Boolean
*/
public function hasTag($tag)
{
return in_array($tag, $this->getTags());
}
/**
* Returns scenario tags.
*
* @return array
*/
public function getTags()
{
$tags = $this->tags;
if ($feature = $this->getFeature()) {
$tags = array_merge($tags, $feature->getTags());
}
return $tags;
}
/**
* Returns only own tags (without inherited ones).
*
* @return array
*/
public function getOwnTags()
{
return $this->tags;
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Node Visitor Interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface StepArgumentNodeInterface
{
/**
* Returns new node with replaced outline example row tokens.
*
* @return ExamplePyStringNode
*/
function createExampleRowStepArgument(array $tokens);
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Step Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class StepNode extends AbstractNode
{
private $type;
private $text;
private $parent;
private $arguments = array();
/**
* Initizalizes step.
*
* @param string $type Step type
* @param string $text Step text
* @param integer $line Definition line
*/
public function __construct($type, $text = null, $line = 0)
{
parent::__construct($line);
$this->type = $type;
$this->text = $text;
}
/**
* Returns new example step, initialized with values from specific row.
*
* @return ExampleStepNode
*/
public function createExampleRowStep(array $tokens)
{
if (!$this->isFrozen()) {
throw new \LogicException('Impossible to get example step from non-frozen one.');
}
return new ExampleStepNode($this, $tokens);
}
/**
* Sets step type.
*
* @param string $type Step type (Given|When|Then|And etc)
*/
public function setType($type)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change step type in frozen feature.');
}
$this->type = $type;
}
/**
* Returns step type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Sets step text.
*
* @param string $text Step text
*/
public function setText($text)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change step text in frozen feature.');
}
$this->text = $text;
}
/**
* Returns step text.
*
* @return string
*/
public function getText()
{
return $this->text;
}
/**
* Adds argument to step.
*
* @param StepArgumentNodeInterface $argument Step argument
*/
public function addArgument(StepArgumentNodeInterface $argument)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change step arguments in frozen feature.');
}
$this->arguments[] = $argument;
}
/**
* Sets step arguments.
*
* @param array $arguments Array of arguments
*/
public function setArguments(array $arguments)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to change step arguments in frozen feature.');
}
foreach ($arguments as $argument) {
$this->addArgument($argument);
}
}
/**
* Checks if step has arguments.
*
* @return Boolean
*/
public function hasArguments()
{
return count($this->arguments) > 0;
}
/**
* Returns step arguments.
*
* @return array
*/
public function getArguments()
{
return $this->arguments;
}
/**
* Sets parent node of the step.
*
* @param AbstractScenarioNode $node Parent scenario
*/
public function setParent(AbstractScenarioNode $node)
{
if ($this->isFrozen()) {
throw new \LogicException('Impossible to reassign step from frozen feature.');
}
$this->parent = $node;
}
/**
* Returns parent node of the step.
*
* @return AbstractScenarioNode
*/
public function getParent()
{
return $this->parent;
}
/**
* Returns definition file.
*
* @return string
*/
public function getFile()
{
return null !== $this->parent
? $this->parent->getFile()
: null;
}
/**
* Returns language of the feature.
*
* @return string
*/
public function getLanguage()
{
return null !== $this->parent
? $this->parent->getLanguage()
: null;
}
/**
* Checks whether step has been frozen.
*
* @return Boolean
*/
public function isFrozen()
{
return null !== $this->parent
? $this->parent->isFrozen()
: false;
}
}
<?php
namespace Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Table Argument Gherkin AST node.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class TableNode implements StepArgumentNodeInterface
{
private $rows = array();
private $keyword;
/**
* Initializes table.
*
* @param string $table Initial table string
*/
public function __construct($table = null)
{
if (null !== $table) {
$table = preg_replace("/\r\n|\r/", "\n", $table);
foreach (explode("\n", $table) as $row) {
$this->addRow($row);
}
}
}
/**
* Returns new node with replaced outline example row tokens.
*
* @returns ExampleTableNode
*/
public function createExampleRowStepArgument(array $tokens)
{
return new ExampleTableNode($this, $tokens);
}
/**
* Adds a row to the string.
*
* @param string|array $row Columns hash (column1 => value, column2 => value) or row string
*/
public function addRow($row)
{
if (is_array($row)) {
$this->rows[] = $row;
} else {
$row = preg_replace("/^\s*\||\|\s*$/", '', $row);
$this->rows[] = array_map(function($item) {
return preg_replace("/^\s*|\s*$/", '', $item);
}, explode('|', $row));
}
}
/**
* Returns table rows.
*
* @return array
*/
public function getRows()
{
return $this->rows;
}
/**
* Sets table rows.
*
* @param array $rows
*/
public function setRows(array $rows)
{
$this->rows = $rows;
}
/**
* Returns specific row in a table.
*
* @param integer $rowNum Row number
*
* @return array
*/
public function getRow($rowNum)
{
return $this->rows[$rowNum];
}
/**
* Converts row into delimited string.
*
* @param integer $rowNum Row number
*
* @return string
*/
public function getRowAsString($rowNum)
{
$values = array();
foreach ($this->getRow($rowNum) as $col => $value) {
$values[] = $this->padRight(' '.$value.' ', $this->getMaxLengthForColumn($col) + 2);
}
return sprintf('|%s|', implode('|', $values));
}
/**
* Returns table hash, formed by columns (ColumnHash).
*
* @return array
*/
public function getHash()
{
$rows = $this->getRows();
$keys = array_shift($rows);
$hash = array();
foreach ($rows as $row) {
$hash[] = array_combine($keys, $row);
}
return $hash;
}
/**
* Returns table hash, formed by rows (RowsHash).
*
* @return array
*/
public function getRowsHash()
{
$hash = array();
$rows = $this->getRows();
foreach ($this->getRows() as $row) {
$hash[$row[0]] = $row[1];
}
return $hash;
}
/**
* Converts table into string
*
* @return string
*/
public function __toString()
{
$string = '';
for ($i = 0; $i < count($this->getRows()); $i++) {
if ('' !== $string) {
$string .= "\n";
}
$string .= $this->getRowAsString($i);
}
return $string;
}
/**
* Sets current node definition keyword.
*
* @param string $keyword Sets table keyword
*/
public function setKeyword($keyword)
{
$this->keyword = $keyword;
}
/**
* Returns current node definition keyword.
*
* @return string
*/
public function getKeyword()
{
return $this->keyword;
}
/**
* Returns max length of specific column.
*
* @param integer $columnNum Column number
*
* @return integer
*/
protected function getMaxLengthForColumn($columnNum)
{
$max = 0;
foreach ($this->getRows() as $row) {
if (($tmp = mb_strlen($row[$columnNum])) > $max) {
$max = $tmp;
}
}
return $max;
}
/**
* Pads string right.
*
* @param string $text Text to pad
* @param integer $length Lenght
*
* @return string
*/
protected function padRight($text, $length)
{
while ($length > mb_strlen($text)) {
$text = $text . ' ';
}
return $text;
}
}
<?php
namespace Behat\Gherkin;
use Behat\Gherkin\Exception\ParserException,
Behat\Gherkin\Exception\LexerException,
Behat\Gherkin\Node;
/*
* This file is part of the Behat Gherkin.
* (c) 2011 Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Gherkin parser.
*
* $lexer = new Behat\Gherkin\Lexer($keywords);
* $parser = new Behat\Gherkin\Parser($lexer);
* $featuresArray = $parser->parse('/path/to/feature.feature');
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Parser
{
private $file;
private $lexer;
/**
* Initializes parser.
*
* @param Lexer $lexer Lexer instance
*/
public function __construct(Lexer $lexer)
{
$this->lexer = $lexer;
}
/**
* Parses input & returns features array.
*
* @param string $input Gherkin string document
*
* @return array
*
* @throws ParserException
*/
public function parse($input, $file = null)
{
$this->file = $file;
try {
$this->lexer->setInput($input);
} catch (LexerException $e) {
throw new ParserException(
sprintf('Lexer exception "%s" throwed for file %s', $e->getMessage(), $file)
);
}
$this->lexer->setLanguage($language = 'en');
$languageSpecifierLine = null;
$feature = null;
while ('EOS' !== ($predicted = $this->predictTokenType())) {
if ('Newline' === $predicted || 'Comment' === $predicted) {
$this->lexer->getAdvancedToken();
} elseif ('Language' === $predicted) {
$token = $this->expectTokenType('Language');
$language = $token->value;
if (null === $languageSpecifierLine) {
// Reparse input with new language
$languageSpecifierLine = $token->line;
$this->lexer->setInput($input);
$this->lexer->setLanguage($language);
} elseif ($languageSpecifierLine !== $token->line) {
// Language already specified
throw new ParserException(sprintf(
'Ambigious language specifiers on lines: %d and %d%s',
$languageSpecifierLine,
$token->line,
$this->file ? ' in file: ' . $this->file : ''
));
}
} elseif (null === $feature &&
('Feature' === $predicted || (
'Tag' === $predicted && 'Feature' === $this->predictTokenType(2))
)) {
$feature = $this->parseExpression();
$feature->setLanguage($language);
} else {
$this->expectTokenType(array('Comment', 'Scenario', 'Outline', 'Step'));
}
}
return $feature;
}
/**
* Returns next token if it's type equals to expected.
*
* @param string $types Token type
*
* @return stdClass
*
* @throws ParserException if token type is differ from expected one
*/
protected function expectTokenType($type)
{
$types = (array) $type;
if (in_array($this->predictTokenType(), $types)) {
return $this->lexer->getAdvancedToken();
}
throw new ParserException(sprintf('Expected %s token, but got %s on line: %d%s',
implode(' or ', $types), $this->predictTokenType(), $this->lexer->predictToken()->line,
$this->file ? ' in file: ' . $this->file : ''
));
}
/**
* Returns next token if it's type equals to expected.
*
* @param string $type Token type
*
* @return stdClass
*/
protected function acceptTokenType($type)
{
if ($type === $this->predictTokenType()) {
return $this->lexer->getAdvancedToken();
}
}
/**
* Returns next token type without real input reading (prediction).
*
* @param integer $number Number of tokens to predict
*
* @return string
*/
protected function predictTokenType($number = 1)
{
return $this->lexer->predictToken($number)->type;
}
/**
* Parses current expression & returns Node.
*
* @return string|AbstractNode
*/
protected function parseExpression()
{
switch ($this->predictTokenType()) {
case 'Feature':
return $this->parseFeature();
case 'Background':
return $this->parseBackground();
case 'Scenario':
return $this->parseScenario();
case 'Outline':
return $this->parseOutline();
case 'TableRow':
return $this->parseTable();
case 'PyStringOperator':
return $this->parsePyString();
case 'Step':
return $this->parseStep();
case 'Comment':
return $this->parseComment();
case 'Text':
return $this->parseText();
case 'Tag':
$token = $this->lexer->getAdvancedToken();
$this->skipExtraChars();
$this->lexer->deferToken($this->lexer->getAdvancedToken());
$this->lexer->deferToken($token);
return $this->parseExpression();
}
}
/**
* Parses feature token & returns it's node.
*
* @return FeatureNode
*/
protected function parseFeature()
{
$token = $this->expectTokenType('Feature');
$node = new Node\FeatureNode(trim($token->value) ?: null, null, $this->file, $token->line);
$node->setKeyword($token->keyword);
// Parse tags
$this->parseNodeTags($node);
// Parse description
$this->parseNodeDescription($node, $token->indent+2);
// Parse background
if ('Background' === $this->predictTokenType()) {
$node->setBackground($this->parseExpression());
}
// Parse scenarios & outlines
while ('Scenario' === ($predicted = $this->predictTokenType())
|| ('Tag' === $predicted && 'Scenario' === ($predicted2 = $this->predictTokenType(2)))
|| 'Outline' === $predicted
|| ('Tag' === $predicted && 'Outline' === $predicted2)) {
$node->addScenario($this->parseExpression());
}
return $node;
}
/**
* Parses background token & returns it's node.
*
* @return BackgroundNode
*/
protected function parseBackground()
{
$token = $this->expectTokenType('Background');
$node = new Node\BackgroundNode(trim($token->value) ?: null, $token->line);
$node->setKeyword($token->keyword);
$this->skipComments();
// Parse title
$this->parseNodeDescription($node, $token->indent+2);
// Parse steps
while ('Step' === $this->predictTokenType()) {
$node->addStep($this->parseExpression());
}
return $node;
}
/**
* Parses scenario outline token & returns it's node.
*
* @return OutlineNode
*/
protected function parseOutline()
{
$token = $this->expectTokenType('Outline');
$node = new Node\OutlineNode(trim($token->value) ?: null, $token->line);
$node->setKeyword($token->keyword);
// Parse tags
$this->parseNodeTags($node);
// Parse title
$this->parseNodeDescription($node, $token->indent+2);
// Parse steps
while ('Step' === $this->predictTokenType()) {
$node->addStep($this->parseExpression());
}
// Examples block
$examplesToken = $this->expectTokenType('Examples');
$this->skipExtraChars();
// Parse examples table
$table = $this->parseTable();
$table->setKeyword($examplesToken->keyword);
$node->setExamples($table);
return $node;
}
/**
* Parses scenario token & returns it's node.
*
* @return ScenarioNode
*/
protected function parseScenario()
{
$token = $this->expectTokenType('Scenario');
$node = new Node\ScenarioNode(trim($token->value) ?: null, $token->line);
$node->setKeyword($token->keyword);
// Parse tags
$this->parseNodeTags($node);
// Parse title
$this->parseNodeDescription($node, $token->indent+2);
// Parse scenario steps
while ('Step' === $this->predictTokenType()) {
$node->addStep($this->parseExpression());
}
return $node;
}
/**
* Parses step token & returns it's node.
*
* @return StepNode
*/
protected function parseStep()
{
$token = $this->expectTokenType('Step');
$node = new Node\StepNode($token->value, trim($token->text) ?: null, $token->line);
$this->skipExtraChars();
// Parse PyString argument
if ('PyStringOperator' === $this->predictTokenType()) {
$node->addArgument($this->parseExpression());
}
// Parse Table argument
if ('TableRow' === $this->predictTokenType()) {
$node->addArgument($this->parseExpression());
}
return $node;
}
/**
* Parses table token & returns it's node.
*
* @return TableNode
*/
protected function parseTable()
{
$token = $this->expectTokenType('TableRow');
$node = new Node\TableNode();
$node->addRow($token->columns);
$this->skipExtraChars();
while ('TableRow' === $this->predictTokenType()) {
$token = $this->expectTokenType('TableRow');
$node->addRow($token->columns);
$this->skipExtraChars();
}
return $node;
}
/**
* Parses PyString token & returns it's node.
*
* @return PyStringNode
*/
protected function parsePyString()
{
$token = $this->expectTokenType('PyStringOperator');
$node = new Node\PyStringNode();
while ('PyStringOperator' !== ($predicted = $this->predictTokenType()) && 'Text' === $predicted) {
$node->addLine($this->parseText(false));
}
$this->expectTokenType('PyStringOperator');
$this->skipExtraChars();
return $node;
}
/**
* Parses next text token & returns it's string content.
*
* @param Boolean $skipExtraChars Do we need to skip newlines & spaces
*
* @return string
*/
protected function parseText($skipExtraChars = true)
{
$token = $this->expectTokenType('Text');
if ($skipExtraChars) {
$this->skipExtraChars();
}
return $token->value;
}
/**
* Parses next comment token & returns it's string content.
*
* @return string
*/
protected function parseComment()
{
$token = $this->expectTokenType('Comment');
return $token->value;
}
/**
* Parse tags for the feature/scenario/outline node.
*
* @param AbstractNode $node Node with tags
*/
private function parseNodeTags(Node\AbstractNode $node)
{
$this->skipComments();
while ('Tag' === $this->predictTokenType()) {
$node->setTags($this->lexer->getAdvancedToken()->tags);
$this->skipComments();
}
}
/**
* Parse description/title for feature/background/scenario/outline node.
*
* @param AbstractNode $node Node with description
* @param integer $indentation Indentation
*/
private function parseNodeDescription(Node\AbstractNode $node, $indentation)
{
$setter = 'setTitle';
$getter = 'getTitle';
if ($node instanceof Node\FeatureNode) {
$setter = 'setDescription';
$getter = 'getDescription';
}
// Parse description/title
while (in_array($predicted = $this->predictTokenType(), array('Text', 'Newline'))) {
if ('Text' === $predicted) {
$text = $this->parseText(false);
$text = preg_replace('/^\s{0,'.$indentation.'}|\s*$/', '', $text);
} else {
$this->acceptTokenType('Newline');
$text = '';
}
if ($node instanceof Node\FeatureNode && null === $node->$getter()) {
$node->$setter($text);
} else {
$node->$setter($node->$getter() . "\n" . $text);
}
$this->skipComments();
}
// Trim title/description
if (null !== $node->$getter()) {
$node->$setter(rtrim($node->$getter()) ?: null);
}
}
/**
* Skips newlines & comments in input.
*
* @param Boolean $skipNL Skip newline?
*/
private function skipExtraChars()
{
while ($this->acceptTokenType('Newline') || $this->acceptTokenType('Comment'));
}
/**
* Skips newlines & comments in input.
*/
private function skipComments()
{
while ($this->acceptTokenType('Comment'));
}
}
<?php
// autoload_classmap.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);
<?php
// autoload_namespace.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Component\\Yaml' => $baseDir . '/vendor/symfony/yaml/',
'Symfony\\Component\\Translation' => $baseDir . '/vendor/symfony/translation/',
'Symfony\\Component\\Finder' => $baseDir . '/vendor/symfony/finder/',
'Symfony\\Component\\EventDispatcher' => $baseDir . '/vendor/symfony/event-dispatcher/',
'Symfony\\Component\\DependencyInjection' => $baseDir . '/vendor/symfony/dependency-injection/',
'Symfony\\Component\\Console' => $baseDir . '/vendor/symfony/console/',
'Symfony\\Component\\Config' => $baseDir . '/vendor/symfony/config/',
'Behat\\Gherkin' => $baseDir . '/vendor/behat/gherkin/src/',
'Behat\\Behat' => $baseDir . '/src/',
);
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0 class loader
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ClassLoader
{
private $prefixes = array();
private $fallbackDirs = array();
private $useIncludePath = false;
private $classMap = array();
public function getPrefixes()
{
return $this->prefixes;
}
public function getFallbackDirs()
{
return $this->fallbackDirs;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of classes
*
* @param string $prefix The classes prefix
* @param array|string $paths The location(s) of the classes
*/
public function add($prefix, $paths)
{
if (!$prefix) {
foreach ((array) $paths as $path) {
$this->fallbackDirs[] = $path;
}
return;
}
if (isset($this->prefixes[$prefix])) {
$this->prefixes[$prefix] = array_merge(
$this->prefixes[$prefix],
(array) $paths
);
} else {
$this->prefixes[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param Boolean $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return Boolean
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Registers this instance as an autoloader.
*
* @param Boolean $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return Boolean|null True, if loaded
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
require $file;
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|null The path, if found
*/
public function findFile($class)
{
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR;
$className = substr($class, $pos + 1);
} else {
// PEAR-like class name
$classPath = null;
$className = $class;
}
$classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
foreach ($this->prefixes as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
return $dir . DIRECTORY_SEPARATOR . $classPath;
}
}
}
}
foreach ($this->fallbackDirs as $dir) {
if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
return $dir . DIRECTORY_SEPARATOR . $classPath;
}
}
if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
return $file;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
/**
* ConfigCache manages PHP cache files.
*
* When debug is enabled, it knows when to flush the cache
* thanks to an array of ResourceInterface instances.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ConfigCache
{
private $debug;
private $file;
/**
* Constructor.
*
* @param string $file The absolute cache path
* @param Boolean $debug Whether debugging is enabled or not
*/
public function __construct($file, $debug)
{
$this->file = $file;
$this->debug = (Boolean) $debug;
}
/**
* Gets the cache file path.
*
* @return string The cache file path
*/
public function __toString()
{
return $this->file;
}
/**
* Checks if the cache is still fresh.
*
* This method always returns true when debug is off and the
* cache file exists.
*
* @return Boolean true if the cache is fresh, false otherwise
*/
public function isFresh()
{
if (!file_exists($this->file)) {
return false;
}
if (!$this->debug) {
return true;
}
$metadata = $this->file.'.meta';
if (!file_exists($metadata)) {
return false;
}
$time = filemtime($this->file);
$meta = unserialize(file_get_contents($metadata));
foreach ($meta as $resource) {
if (!$resource->isFresh($time)) {
return false;
}
}
return true;
}
/**
* Writes cache.
*
* @param string $content The content to write in the cache
* @param array $metadata An array of ResourceInterface instances
*
* @throws \RuntimeException When cache file can't be wrote
*/
public function write($content, array $metadata = null)
{
$dir = dirname($this->file);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true)) {
throw new \RuntimeException(sprintf('Unable to create the %s directory', $dir));
}
} elseif (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in the %s directory', $dir));
}
$tmpFile = tempnam(dirname($this->file), basename($this->file));
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $this->file)) {
chmod($this->file, 0666);
} else {
throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $this->file));
}
if (null !== $metadata && true === $this->debug) {
$file = $this->file.'.meta';
$tmpFile = tempnam(dirname($file), basename($file));
if (false !== @file_put_contents($tmpFile, serialize($metadata)) && @rename($tmpFile, $file)) {
chmod($file, 0666);
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
/**
* Represents an Array node in the config tree.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ArrayNode extends BaseNode implements PrototypeNodeInterface
{
protected $xmlRemappings;
protected $children;
protected $allowFalse;
protected $allowNewKeys;
protected $addIfNotSet;
protected $performDeepMerging;
protected $ignoreExtraKeys;
/**
* Constructor.
*
* @param string $name The Node's name
* @param NodeInterface $parent The node parent
*/
public function __construct($name, NodeInterface $parent = null)
{
parent::__construct($name, $parent);
$this->children = array();
$this->xmlRemappings = array();
$this->removeKeyAttribute = true;
$this->allowFalse = false;
$this->addIfNotSet = false;
$this->allowNewKeys = true;
$this->performDeepMerging = true;
}
/**
* Sets the xml remappings that should be performed.
*
* @param array $remappings an array of the form array(array(string, string))
*/
public function setXmlRemappings(array $remappings)
{
$this->xmlRemappings = $remappings;
}
/**
* Sets whether to add default values for this array if it has not been
* defined in any of the configuration files.
*
* @param Boolean $boolean
*/
public function setAddIfNotSet($boolean)
{
$this->addIfNotSet = (Boolean) $boolean;
}
/**
* Sets whether false is allowed as value indicating that the array should be unset.
*
* @param Boolean $allow
*/
public function setAllowFalse($allow)
{
$this->allowFalse = (Boolean) $allow;
}
/**
* Sets whether new keys can be defined in subsequent configurations.
*
* @param Boolean $allow
*/
public function setAllowNewKeys($allow)
{
$this->allowNewKeys = (Boolean) $allow;
}
/**
* Sets if deep merging should occur.
*
* @param Boolean $boolean
*/
public function setPerformDeepMerging($boolean)
{
$this->performDeepMerging = (Boolean) $boolean;
}
/**
* Whether extra keys should just be ignore without an exception.
*
* @param Boolean $boolean To allow extra keys
*/
public function setIgnoreExtraKeys($boolean)
{
$this->ignoreExtraKeys = (Boolean) $boolean;
}
/**
* Sets the node Name.
*
* @param string $name The node's name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Checks if the node has a default value.
*
* @return Boolean
*/
public function hasDefaultValue()
{
return $this->addIfNotSet;
}
/**
* Retrieves the default value.
*
* @return array The default value
*
* @throws \RuntimeException if the node has no default value
*/
public function getDefaultValue()
{
if (!$this->hasDefaultValue()) {
throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath()));
}
$defaults = array();
foreach ($this->children as $name => $child) {
if ($child->hasDefaultValue()) {
$defaults[$name] = $child->getDefaultValue();
}
}
return $defaults;
}
/**
* Adds a child node.
*
* @param NodeInterface $node The child node to add
*
* @throws \InvalidArgumentException when the child node has no name
* @throws \InvalidArgumentException when the child node's name is not unique
*/
public function addChild(NodeInterface $node)
{
$name = $node->getName();
if (empty($name)) {
throw new \InvalidArgumentException('Child nodes must be named.');
}
if (isset($this->children[$name])) {
throw new \InvalidArgumentException(sprintf('A child node named "%s" already exists.', $name));
}
$this->children[$name] = $node;
}
/**
* Finalizes the value of this node.
*
* @param mixed $value
*
* @return mixed The finalised value
*
* @throws UnsetKeyException
* @throws InvalidConfigurationException if the node doesn't have enough children
*/
protected function finalizeValue($value)
{
if (false === $value) {
$msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
throw new UnsetKeyException($msg);
}
foreach ($this->children as $name => $child) {
if (!array_key_exists($name, $value)) {
if ($child->isRequired()) {
$msg = sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath());
$ex = new InvalidConfigurationException($msg);
$ex->setPath($this->getPath());
throw $ex;
}
if ($child->hasDefaultValue()) {
$value[$name] = $child->getDefaultValue();
}
continue;
}
try {
$value[$name] = $child->finalize($value[$name]);
} catch (UnsetKeyException $unset) {
unset($value[$name]);
}
}
return $value;
}
/**
* Validates the type of the value.
*
* @param mixed $value
*
* @throws InvalidTypeException
*/
protected function validateType($value)
{
if (!is_array($value) && (!$this->allowFalse || false !== $value)) {
$ex = new InvalidTypeException(sprintf(
'Invalid type for path "%s". Expected array, but got %s',
$this->getPath(),
gettype($value)
));
$ex->setPath($this->getPath());
throw $ex;
}
}
/**
* Normalizes the value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
*/
protected function normalizeValue($value)
{
if (false === $value) {
return $value;
}
$value = $this->remapXml($value);
$normalized = array();
foreach ($this->children as $name => $child) {
if (array_key_exists($name, $value)) {
$normalized[$name] = $child->normalize($value[$name]);
unset($value[$name]);
}
}
// if extra fields are present, throw exception
if (count($value) && !$this->ignoreExtraKeys) {
$msg = sprintf('Unrecognized options "%s" under "%s"', implode(', ', array_keys($value)), $this->getPath());
$ex = new InvalidConfigurationException($msg);
$ex->setPath($this->getPath());
throw $ex;
}
return $normalized;
}
/**
* Remaps multiple singular values to a single plural value.
*
* @param array $value The source values
*
* @return array The remapped values
*/
protected function remapXml($value)
{
foreach ($this->xmlRemappings as $transformation) {
list($singular, $plural) = $transformation;
if (!isset($value[$singular])) {
continue;
}
$value[$plural] = Processor::normalizeConfig($value, $singular, $plural);
unset($value[$singular]);
}
return $value;
}
/**
* Merges values together.
*
* @param mixed $leftSide The left side to merge.
* @param mixed $rightSide The right side to merge.
*
* @return mixed The merged values
*
* @throws InvalidConfigurationException
* @throws \RuntimeException
*/
protected function mergeValues($leftSide, $rightSide)
{
if (false === $rightSide) {
// if this is still false after the last config has been merged the
// finalization pass will take care of removing this key entirely
return false;
}
if (false === $leftSide || !$this->performDeepMerging) {
return $rightSide;
}
foreach ($rightSide as $k => $v) {
// no conflict
if (!array_key_exists($k, $leftSide)) {
if (!$this->allowNewKeys) {
$ex = new InvalidConfigurationException(sprintf(
'You are not allowed to define new elements for path "%s". '
.'Please define all elements for this path in one config file. '
.'If you are trying to overwrite an element, make sure you redefine it '
.'with the same name.',
$this->getPath()
));
$ex->setPath($this->getPath());
throw $ex;
}
$leftSide[$k] = $v;
continue;
}
if (!isset($this->children[$k])) {
throw new \RuntimeException('merge() expects a normalized config array.');
}
$leftSide[$k] = $this->children[$k]->merge($leftSide[$k], $v);
}
return $leftSide;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
/**
* The base node class
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
abstract class BaseNode implements NodeInterface
{
protected $name;
protected $parent;
protected $normalizationClosures;
protected $finalValidationClosures;
protected $allowOverwrite;
protected $required;
protected $equivalentValues;
/**
* Constructor.
*
* @param string $name The name of the node
* @param NodeInterface $parent The parent of this node
*
* @throws \InvalidArgumentException if the name contains a period.
*/
public function __construct($name, NodeInterface $parent = null)
{
if (false !== strpos($name, '.')) {
throw new \InvalidArgumentException('The name must not contain ".".');
}
$this->name = $name;
$this->parent = $parent;
$this->normalizationClosures = array();
$this->finalValidationClosures = array();
$this->allowOverwrite = true;
$this->required = false;
$this->equivalentValues = array();
}
/**
* Adds an equivalent value.
*
* @param mixed $originalValue
* @param mixed $equivalentValue
*/
public function addEquivalentValue($originalValue, $equivalentValue)
{
$this->equivalentValues[] = array($originalValue, $equivalentValue);
}
/**
* Set this node as required.
*
* @param Boolean $boolean Required node
*/
public function setRequired($boolean)
{
$this->required = (Boolean) $boolean;
}
/**
* Sets if this node can be overridden.
*
* @param Boolean $allow
*/
public function setAllowOverwrite($allow)
{
$this->allowOverwrite = (Boolean) $allow;
}
/**
* Sets the closures used for normalization.
*
* @param array $closures An array of Closures used for normalization
*/
public function setNormalizationClosures(array $closures)
{
$this->normalizationClosures = $closures;
}
/**
* Sets the closures used for final validation.
*
* @param array $closures An array of Closures used for final validation
*/
public function setFinalValidationClosures(array $closures)
{
$this->finalValidationClosures = $closures;
}
/**
* Checks if this node is required.
*
* @return Boolean
*/
public function isRequired()
{
return $this->required;
}
/**
* Returns the name of this node
*
* @return string The Node's name.
*/
public function getName()
{
return $this->name;
}
/**
* Retrieves the path of this node.
*
* @return string The Node's path
*/
public function getPath()
{
$path = $this->name;
if (null !== $this->parent) {
$path = $this->parent->getPath().'.'.$path;
}
return $path;
}
/**
* Merges two values together.
*
* @param mixed $leftSide
* @param mixed $rightSide
*
* @return mixed The merged value
*
* @throws ForbiddenOverwriteException
*/
public final function merge($leftSide, $rightSide)
{
if (!$this->allowOverwrite) {
throw new ForbiddenOverwriteException(sprintf(
'Configuration path "%s" cannot be overwritten. You have to '
.'define all options for this path, and any of its sub-paths in '
.'one configuration section.',
$this->getPath()
));
}
$this->validateType($leftSide);
$this->validateType($rightSide);
return $this->mergeValues($leftSide, $rightSide);
}
/**
* Normalizes a value, applying all normalization closures.
*
* @param mixed $value Value to normalize.
*
* @return mixed The normalized value.
*/
public final function normalize($value)
{
// run custom normalization closures
foreach ($this->normalizationClosures as $closure) {
$value = $closure($value);
}
// replace value with their equivalent
foreach ($this->equivalentValues as $data) {
if ($data[0] === $value) {
$value = $data[1];
}
}
// validate type
$this->validateType($value);
// normalize value
return $this->normalizeValue($value);
}
/**
* Finalizes a value, applying all finalization closures.
*
* @param mixed $value The value to finalize
*
* @return mixed The finalized value
*/
public final function finalize($value)
{
$this->validateType($value);
$value = $this->finalizeValue($value);
// Perform validation on the final value if a closure has been set.
// The closure is also allowed to return another value.
foreach ($this->finalValidationClosures as $closure) {
try {
$value = $closure($value);
} catch (Exception $correctEx) {
throw $correctEx;
} catch (\Exception $invalid) {
throw new InvalidConfigurationException(sprintf(
'Invalid configuration for path "%s": %s',
$this->getPath(),
$invalid->getMessage()
), $invalid->getCode(), $invalid);
}
}
return $value;
}
/**
* Validates the type of a Node.
*
* @param mixed $value The value to validate
*
* @throws InvalidTypeException when the value is invalid
*/
abstract protected function validateType($value);
/**
* Normalizes the value.
*
* @param mixed $value The value to normalize.
*
* @return mixed The normalized value
*/
abstract protected function normalizeValue($value);
/**
* Merges two values together.
*
* @param mixed $leftSide
* @param mixed $rightSide
*
* @return mixed The merged value
*/
abstract protected function mergeValues($leftSide, $rightSide);
/**
* Finalizes a value.
*
* @param mixed $value The value to finalize
*
* @return mixed The finalized value
*/
abstract protected function finalizeValue($value);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* This node represents a Boolean value in the config tree.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class BooleanNode extends ScalarNode
{
/**
* {@inheritDoc}
*/
protected function validateType($value)
{
if (!is_bool($value)) {
$ex = new InvalidTypeException(sprintf(
'Invalid type for path "%s". Expected boolean, but got %s.',
$this->getPath(),
gettype($value)
));
$ex->setPath($this->getPath());
throw $ex;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
/**
* This class provides a fluent interface for defining an array node.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinitionInterface
{
protected $performDeepMerging;
protected $ignoreExtraKeys;
protected $children;
protected $prototype;
protected $atLeastOne;
protected $allowNewKeys;
protected $key;
protected $removeKeyItem;
protected $addDefaults;
protected $nodeBuilder;
/**
* {@inheritDoc}
*/
public function __construct($name, NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
$this->children = array();
$this->addDefaults = false;
$this->allowNewKeys = true;
$this->atLeastOne = false;
$this->allowEmptyValue = true;
$this->performDeepMerging = true;
$this->nullEquivalent = array();
$this->trueEquivalent = array();
}
/**
* Set a custom children builder
*
* @param NodeBuilder $builder A custom NodeBuilder
*/
public function setBuilder(NodeBuilder $builder)
{
$this->nodeBuilder = $builder;
}
/**
* Returns a builder to add children nodes
*
* @return NodeBuilder
*/
public function children()
{
return $this->getNodeBuilder();
}
/**
* Sets a prototype for child nodes.
*
* @param string $type the type of node
*
* @return NodeDefinition
*/
public function prototype($type)
{
$builder = $this->getNodeBuilder();
$this->prototype = $builder->node(null, $type);
$this->prototype->parent = $this;
return $this->prototype;
}
/**
* Adds the default value if the node is not set in the configuration.
*
* @return ArrayNodeDefinition
*/
public function addDefaultsIfNotSet()
{
$this->addDefaults = true;
return $this;
}
/**
* Requires the node to have at least one element.
*
* @return ArrayNodeDefinition
*/
public function requiresAtLeastOneElement()
{
$this->atLeastOne = true;
return $this;
}
/**
* Disallows adding news keys in a subsequent configuration.
*
* If used all keys have to be defined in the same configuration file.
*
* @return ArrayNodeDefinition
*/
public function disallowNewKeysInSubsequentConfigs()
{
$this->allowNewKeys = false;
return $this;
}
/**
* Sets a normalization rule for XML configurations.
*
* @param string $singular The key to remap
* @param string $plural The plural of the key for irregular plurals
*
* @return ArrayNodeDefinition
*/
public function fixXmlConfig($singular, $plural = null)
{
$this->normalization()->remap($singular, $plural);
return $this;
}
/**
* Set the attribute which value is to be used as key.
*
* This is useful when you have an indexed array that should be an
* associative array. You can select an item from within the array
* to be the key of the particular item. For example, if "id" is the
* "key", then:
*
* array(
* array('id' => 'my_name', 'foo' => 'bar'),
* )
*
* becomes
*
* array(
* 'my_name' => array('foo' => 'bar'),
* )
*
* If you'd like "'id' => 'my_name'" to still be present in the resulting
* array, then you can set the second argument of this method to false.
*
* @param string $name The name of the key
* @param Boolean $removeKeyItem Whether or not the key item should be removed.
*
* @return ArrayNodeDefinition
*/
public function useAttributeAsKey($name, $removeKeyItem = true)
{
$this->key = $name;
$this->removeKeyItem = $removeKeyItem;
return $this;
}
/**
* Sets whether the node can be unset.
*
* @param Boolean $allow
*
* @return ArrayNodeDefinition
*/
public function canBeUnset($allow = true)
{
$this->merge()->allowUnset($allow);
return $this;
}
/**
* Disables the deep merging of the node.
*
* @return ArrayNodeDefinition
*/
public function performNoDeepMerging()
{
$this->performDeepMerging = false;
return $this;
}
/**
* Allows extra config keys to be specified under an array without
* throwing an exception.
*
* Those config values are simply ignored. This should be used only
* in special cases where you want to send an entire configuration
* array through a special tree that processes only part of the array.
*
* @return ArrayNodeDefinition
*/
public function ignoreExtraKeys()
{
$this->ignoreExtraKeys = true;
return $this;
}
/**
* Append a node definition.
*
* $node = new ArrayNodeDefinition()
* ->children()
* ->scalarNode('foo')
* ->scalarNode('baz')
* ->end()
* ->append($this->getBarNodeDefinition())
* ;
*
* @param NodeDefinition $node A NodeDefinition instance
*
* @return ArrayNodeDefinition This node
*/
public function append(NodeDefinition $node)
{
$this->children[$node->name] = $node->setParent($this);
return $this;
}
/**
* Returns a node builder to be used to add children and prototype
*
* @return NodeBuilder The node builder
*/
protected function getNodeBuilder()
{
if (null === $this->nodeBuilder) {
$this->nodeBuilder = new NodeBuilder();
}
return $this->nodeBuilder->setParent($this);
}
/**
* {@inheritDoc}
*/
protected function createNode()
{
if (null == $this->prototype) {
$node = new ArrayNode($this->name, $this->parent);
} else {
$node = new PrototypedArrayNode($this->name, $this->parent);
}
$node->setAddIfNotSet($this->addDefaults);
$node->setAllowNewKeys($this->allowNewKeys);
$node->addEquivalentValue(null, $this->nullEquivalent);
$node->addEquivalentValue(true, $this->trueEquivalent);
$node->addEquivalentValue(false, $this->falseEquivalent);
$node->setPerformDeepMerging($this->performDeepMerging);
$node->setRequired($this->required);
$node->setIgnoreExtraKeys($this->ignoreExtraKeys);
if (null !== $this->normalization) {
$node->setNormalizationClosures($this->normalization->before);
$node->setXmlRemappings($this->normalization->remappings);
}
if (null !== $this->merge) {
$node->setAllowOverwrite($this->merge->allowOverwrite);
$node->setAllowFalse($this->merge->allowFalse);
}
if (null !== $this->validation) {
$node->setFinalValidationClosures($this->validation->rules);
}
if (null == $this->prototype) {
foreach ($this->children as $child) {
$child->parent = $node;
$node->addChild($child->getNode());
}
} else {
if (null !== $this->key) {
$node->setKeyAttribute($this->key, $this->removeKeyItem);
}
if (true === $this->atLeastOne) {
$node->setMinNumberOfElements(1);
}
if (null !== $this->defaultValue) {
$node->setDefaultValue($this->defaultValue);
}
$this->prototype->parent = $node;
$node->setPrototype($this->prototype->getNode());
}
return $node;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\BooleanNode;
/**
* This class provides a fluent interface for defining a node.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class BooleanNodeDefinition extends ScalarNodeDefinition
{
/**
* {@inheritDoc}
*/
public function __construct($name, NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
$this->nullEquivalent = true;
}
/**
* Instantiate a Node
*
* @return BooleanNode The node
*/
protected function instantiateNode()
{
return new BooleanNode($this->name, $this->parent);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
/**
* This class builds an if expression.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Christophe Coevoet <stof@notk.org>
*/
class ExprBuilder
{
protected $node;
public $ifPart;
public $thenPart;
/**
* Constructor
*
* @param NodeDefinition $node The related node
*/
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* Mark the expression as being always used.
*
* @param \Closure $then
*
* @return ExprBuilder
*/
public function always(\Closure $then = null)
{
$this->ifPart = function($v) { return true; };
if (null !== $then) {
$this->thenPart = $then;
}
return $this;
}
/**
* Sets a closure to use as tests.
*
* The default one tests if the value is true.
*
* @param \Closure $closure
*
* @return ExprBuilder
*/
public function ifTrue(\Closure $closure = null)
{
if (null === $closure) {
$closure = function($v) { return true === $v; };
}
$this->ifPart = $closure;
return $this;
}
/**
* Tests if the value is a string.
*
* @return ExprBuilder
*/
public function ifString()
{
$this->ifPart = function($v) { return is_string($v); };
return $this;
}
/**
* Tests if the value is null.
*
* @return ExprBuilder
*/
public function ifNull()
{
$this->ifPart = function($v) { return null === $v; };
return $this;
}
/**
* Tests if the value is an array.
*
* @return ExprBuilder
*/
public function ifArray()
{
$this->ifPart = function($v) { return is_array($v); };
return $this;
}
/**
* Tests if the value is in an array.
*
* @param array $array
*
* @return ExprBuilder
*/
public function ifInArray(array $array)
{
$this->ifPart = function($v) use ($array) { return in_array($v, $array, true); };
return $this;
}
/**
* Tests if the value is not in an array.
*
* @param array $array
*
* @return ExprBuilder
*/
public function ifNotInArray(array $array)
{
$this->ifPart = function($v) use ($array) { return !in_array($v, $array, true); };
return $this;
}
/**
* Sets the closure to run if the test pass.
*
* @param \Closure $closure
*
* @return ExprBuilder
*/
public function then(\Closure $closure)
{
$this->thenPart = $closure;
return $this;
}
/**
* Sets a closure returning an empty array.
*
* @return ExprBuilder
*/
public function thenEmptyArray()
{
$this->thenPart = function($v) { return array(); };
return $this;
}
/**
* Sets a closure marking the value as invalid at validation time.
*
* if you want to add the value of the node in your message just use a %s placeholder.
*
* @param string $message
*
* @return ExprBuilder
*/
public function thenInvalid($message)
{
$this->thenPart = function ($v) use ($message) {throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
return $this;
}
/**
* Sets a closure unsetting this key of the array at validation time.
*
* @return ExprBuilder
*/
public function thenUnset()
{
$this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key'); };
return $this;
}
/**
* Returns the related node
*
* @return NodeDefinition
*/
public function end()
{
if (null === $this->ifPart) {
throw new \RuntimeException('You must specify an if part.');
}
if (null === $this->thenPart) {
throw new \RuntimeException('You must specify a then part.');
}
return $this->node;
}
/**
* Builds the expressions.
*
* @param array $expressions An array of ExprBuilder instances to build
*
* @return array
*/
static public function buildExpressions(array $expressions)
{
foreach ($expressions as $k => $expr) {
if ($expr instanceof ExprBuilder) {
$expressions[$k] = function($v) use($expr) {
return call_user_func($expr->ifPart, $v) ? call_user_func($expr->thenPart, $v) : $v;
};
}
}
return $expressions;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This class builds merge conditions.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class MergeBuilder
{
protected $node;
public $allowFalse;
public $allowOverwrite;
/**
* Constructor
*
* @param NodeDefinition $node The related node
*/
public function __construct(NodeDefinition $node)
{
$this->node = $node;
$this->allowFalse = false;
$this->allowOverwrite = true;
}
/**
* Sets whether the node can be unset.
*
* @param Boolean $allow
*
* @return MergeBuilder
*/
public function allowUnset($allow = true)
{
$this->allowFalse = $allow;
return $this;
}
/**
* Sets whether the node can be overwritten.
*
* @param Boolean $deny Whether the overwriting is forbidden or not
*
* @return MergeBuilder
*/
public function denyOverwrite($deny = true)
{
$this->allowOverwrite = !$deny;
return $this;
}
/**
* Returns the related node.
*
* @return NodeDefinition
*/
public function end()
{
return $this->node;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This class provides a fluent interface for building a node.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class NodeBuilder implements NodeParentInterface
{
protected $parent;
protected $nodeMapping;
/**
* Constructor
*
*/
public function __construct()
{
$this->nodeMapping = array(
'variable' => __NAMESPACE__.'\\VariableNodeDefinition',
'scalar' => __NAMESPACE__.'\\ScalarNodeDefinition',
'boolean' => __NAMESPACE__.'\\BooleanNodeDefinition',
'array' => __NAMESPACE__.'\\ArrayNodeDefinition',
);
}
/**
* Set the parent node
*
* @param ParentNodeDefinitionInterface $parent The parent node
*
* @return NodeBuilder This node builder
*/
public function setParent(ParentNodeDefinitionInterface $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* Creates a child array node
*
* @param string $name The name of the node
*
* @return ArrayNodeDefinition The child node
*/
public function arrayNode($name)
{
return $this->node($name, 'array');
}
/**
* Creates a child scalar node.
*
* @param string $name the name of the node
*
* @return ScalarNodeDefinition The child node
*/
public function scalarNode($name)
{
return $this->node($name, 'scalar');
}
/**
* Creates a child Boolean node.
*
* @param string $name The name of the node
*
* @return BooleanNodeDefinition The child node
*/
public function booleanNode($name)
{
return $this->node($name, 'boolean');
}
/**
* Creates a child variable node.
*
* @param string $name The name of the node
*
* @return VariableNodeDefinition The builder of the child node
*/
public function variableNode($name)
{
return $this->node($name, 'variable');
}
/**
* Returns the parent node.
*
* @return ParentNodeDefinitionInterface The parent node
*/
public function end()
{
return $this->parent;
}
/**
* Creates a child node.
*
* @param string $name The name of the node
* @param string $type The type of the node
*
* @return NodeDefinition The child node
*
* @throws \RuntimeException When the node type is not registered
* @throws \RuntimeException When the node class is not found
*/
public function node($name, $type)
{
$class = $this->getNodeClass($type);
$node = new $class($name);
if ($node instanceof ParentNodeDefinitionInterface) {
$builder = clone $this;
$builder->setParent(null);
$node->setBuilder($builder);
}
if (null !== $this->parent) {
$this->parent->append($node);
// Make this builder the node parent to allow for a fluid interface
$node->setParent($this);
}
return $node;
}
/**
* Add or override a node Type
*
* @param string $type The name of the type
* @param string $class The fully qualified name the node definition class
*
* @return NodeBuilder This node builder
*/
public function setNodeClass($type, $class)
{
$this->nodeMapping[strtolower($type)] = $class;
return $this;
}
/**
* Returns the class name of the node definition
*
* @param string $type The node type
*
* @return string The node definition class name
*
* @throws \RuntimeException When the node type is not registered
* @throws \RuntimeException When the node class is not found
*/
protected function getNodeClass($type)
{
$type = strtolower($type);
if (!isset($this->nodeMapping[$type])) {
throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type));
}
$class = $this->nodeMapping[$type];
if (!class_exists($class)) {
throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class));
}
return $class;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\NodeInterface;
/**
* This class provides a fluent interface for defining a node.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
abstract class NodeDefinition implements NodeParentInterface
{
protected $name;
protected $normalization;
protected $validation;
protected $defaultValue;
protected $default;
protected $required;
protected $merge;
protected $allowEmptyValue;
protected $nullEquivalent;
protected $trueEquivalent;
protected $falseEquivalent;
protected $parent;
/**
* Constructor
*
* @param string $name The name of the node
* @param NodeParentInterface $parent The parent
*/
public function __construct($name, NodeParentInterface $parent = null)
{
$this->parent = $parent;
$this->name = $name;
$this->default = false;
$this->required = false;
$this->trueEquivalent = true;
$this->falseEquivalent = false;
}
/**
* Sets the parent node
*
* @param NodeParentInterface $parent The parent
*
* @return NodeDefinition
*/
public function setParent(NodeParentInterface $parent)
{
$this->parent = $parent;
return $this;
}
/**
* Returns the parent node.
*
* @return NodeParentInterface The builder of the parent node
*/
public function end()
{
return $this->parent;
}
/**
* Creates the node.
*
* @param Boolean $forceRootNode Whether to force this node as the root node
*
* @return NodeInterface
*/
public function getNode($forceRootNode = false)
{
if ($forceRootNode) {
$this->parent = null;
}
if (null !== $this->normalization) {
$this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
}
if (null !== $this->validation) {
$this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules);
}
return $this->createNode();
}
/**
* Sets the default value.
*
* @param mixed $value The default value
*
* @return NodeDefinition
*/
public function defaultValue($value)
{
$this->default = true;
$this->defaultValue = $value;
return $this;
}
/**
* Sets the node as required.
*
* @return NodeDefinition
*/
public function isRequired()
{
$this->required = true;
return $this;
}
/**
* Sets the equivalent value used when the node contains null.
*
* @param mixed $value
*
* @return NodeDefinition
*/
public function treatNullLike($value)
{
$this->nullEquivalent = $value;
return $this;
}
/**
* Sets the equivalent value used when the node contains true.
*
* @param mixed $value
*
* @return NodeDefinition
*/
public function treatTrueLike($value)
{
$this->trueEquivalent = $value;
return $this;
}
/**
* Sets the equivalent value used when the node contains false.
*
* @param mixed $value
*
* @return NodeDefinition
*/
public function treatFalseLike($value)
{
$this->falseEquivalent = $value;
return $this;
}
/**
* Sets null as the default value.
*
* @return NodeDefinition
*/
public function defaultNull()
{
return $this->defaultValue(null);
}
/**
* Sets true as the default value.
*
* @return NodeDefinition
*/
public function defaultTrue()
{
return $this->defaultValue(true);
}
/**
* Sets false as the default value.
*
* @return NodeDefinition
*/
public function defaultFalse()
{
return $this->defaultValue(false);
}
/**
* Gets the builder for normalization rules.
*
* @return NormalizationBuilder
*/
protected function normalization()
{
if (null === $this->normalization) {
$this->normalization = new NormalizationBuilder($this);
}
return $this->normalization;
}
/**
* Sets an expression to run before the normalization.
*
* @return ExprBuilder
*/
public function beforeNormalization()
{
return $this->normalization()->before();
}
/**
* Denies the node value being empty.
*
* @return NodeDefinition
*/
public function cannotBeEmpty()
{
$this->allowEmptyValue = false;
return $this;
}
/**
* Gets the builder for validation rules.
*
* @return ValidationBuilder
*/
protected function validation()
{
if (null === $this->validation) {
$this->validation = new ValidationBuilder($this);
}
return $this->validation;
}
/**
* Sets an expression to run for the validation.
*
* The expression receives the value of the node and must return it. It can
* modify it.
* An exception should be thrown when the node is not valid.
*
* @return ExprBuilder
*/
public function validate()
{
return $this->validation()->rule();
}
/**
* Gets the builder for merging rules.
*
* @return MergeBuilder
*/
protected function merge()
{
if (null === $this->merge) {
$this->merge = new MergeBuilder($this);
}
return $this->merge;
}
/**
* Sets whether the node can be overwritten.
*
* @param Boolean $deny Whether the overwriting is forbidden or not
*
* @return NodeDefinition
*/
public function cannotBeOverwritten($deny = true)
{
$this->merge()->denyOverwrite($deny);
return $this;
}
/**
* Instantiate and configure the node according to this definition
*
* @return NodeInterface $node The node instance
*/
abstract protected function createNode();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* An interface that must be implemented by all node parents
*
* @author Victor Berchet <victor@suumit.com>
*/
interface NodeParentInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This class builds normalization conditions.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class NormalizationBuilder
{
protected $node;
public $before;
public $remappings;
/**
* Constructor
*
* @param NodeDefinition $node The related node
*/
public function __construct(NodeDefinition $node)
{
$this->node = $node;
$this->keys = false;
$this->remappings = array();
$this->before = array();
}
/**
* Registers a key to remap to its plural form.
*
* @param string $key The key to remap
* @param string $plural The plural of the key in case of irregular plural
*
* @return NormalizationBuilder
*/
public function remap($key, $plural = null)
{
$this->remappings[] = array($key, null === $plural ? $key.'s' : $plural);
return $this;
}
/**
* Registers a closure to run before the normalization or an expression builder to build it if null is provided.
*
* @param \Closure $closure
*
* @return ExprBuilder|NormalizationBuilder
*/
public function before(\Closure $closure = null)
{
if (null !== $closure) {
$this->before[] = $closure;
return $this;
}
return $this->before[] = new ExprBuilder($this->node);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* An interface that must be implemented by nodes which can have children
*
* @author Victor Berchet <victor@suumit.com>
*/
interface ParentNodeDefinitionInterface
{
function children();
function append(NodeDefinition $node);
function setBuilder(NodeBuilder $builder);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\ScalarNode;
/**
* This class provides a fluent interface for defining a node.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ScalarNodeDefinition extends VariableNodeDefinition
{
/**
* Instantiate a Node
*
* @return ScalarNode The node
*/
protected function instantiateNode()
{
return new ScalarNode($this->name, $this->parent);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This is the entry class for building a config tree.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class TreeBuilder implements NodeParentInterface
{
protected $tree;
protected $root;
protected $builder;
/**
* Creates the root node.
*
* @param string $name The name of the root node
* @param string $type The type of the root node
* @param NodeBuilder $builder A custom node builder instance
*
* @return ArrayNodeDefinition|NodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array')
*
* @throws \RuntimeException When the node type is not supported
*/
public function root($name, $type = 'array', NodeBuilder $builder = null)
{
$builder = null === $builder ? new NodeBuilder() : $builder;
$this->root = $builder->node($name, $type);
$this->root->setParent($this);
return $this->root;
}
/**
* Builds the tree.
*
* @return NodeInterface
*/
public function buildTree()
{
if (null === $this->root) {
throw new \RuntimeException('The configuration tree has no root node.');
}
if (null !== $this->tree) {
return $this->tree;
}
return $this->tree = $this->root->getNode(true);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This class builds validation conditions.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class ValidationBuilder
{
protected $node;
public $rules;
/**
* Constructor
*
* @param NodeDefinition $node The related node
*/
public function __construct(NodeDefinition $node)
{
$this->node = $node;
$this->rules = array();
}
/**
* Registers a closure to run as normalization or an expression builder to build it if null is provided.
*
* @param \Closure $closure
*
* @return ExprBuilder|ValidationBuilder
*/
public function rule(\Closure $closure = null)
{
if (null !== $closure) {
$this->rules[] = $closure;
return $this;
}
return $this->rules[] = new ExprBuilder($this->node);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\VariableNode;
/**
* This class provides a fluent interface for defining a node.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class VariableNodeDefinition extends NodeDefinition
{
/**
* Instantiate a Node
*
* @return VariableNode The node
*/
protected function instantiateNode()
{
return new VariableNode($this->name, $this->parent);
}
/**
* {@inheritDoc}
*/
protected function createNode()
{
$node = $this->instantiateNode();
if (null !== $this->normalization) {
$node->setNormalizationClosures($this->normalization->before);
}
if (null !== $this->merge) {
$node->setAllowOverwrite($this->merge->allowOverwrite);
}
if (true === $this->default) {
$node->setDefaultValue($this->defaultValue);
}
if (false === $this->allowEmptyValue) {
$node->setAllowEmptyValue($this->allowEmptyValue);
}
$node->addEquivalentValue(null, $this->nullEquivalent);
$node->addEquivalentValue(true, $this->trueEquivalent);
$node->addEquivalentValue(false, $this->falseEquivalent);
$node->setRequired($this->required);
if (null !== $this->validation) {
$node->setFinalValidationClosures($this->validation->rules);
}
return $node;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
/**
* Configuration interface
*
* @author Victor Berchet <victor@suumit.com>
*/
interface ConfigurationInterface
{
/**
* Generates the configuration tree builder.
*
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
*/
function getConfigTreeBuilder();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* This exception is thrown whenever the key of an array is not unique. This can
* only be the case if the configuration is coming from an XML file.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class DuplicateKeyException extends InvalidConfigurationException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* Base exception for all configuration exceptions
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class Exception extends \RuntimeException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* This exception is thrown when a configuration path is overwritten from a
* subsequent configuration file, but the entry node specifically forbids this.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ForbiddenOverwriteException extends InvalidConfigurationException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* A very general exception which can be thrown whenever non of the more specific
* exceptions is suitable.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class InvalidConfigurationException extends Exception
{
private $path;
public function setPath($path)
{
$this->path = $path;
}
public function getPath()
{
return $this->path;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* This exception is thrown if an invalid type is encountered.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class InvalidTypeException extends InvalidConfigurationException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* This exception is usually not encountered by the end-user, but only used
* internally to signal the parent scope to unset a key.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class UnsetKeyException extends Exception
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
/**
* Common Interface among all nodes.
*
* In most cases, it is better to inherit from BaseNode instead of implementing
* this interface yourself.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface NodeInterface
{
/**
* Returns the name of the node.
*
* @return string The name of the node
*/
function getName();
/**
* Returns the path of the node.
*
* @return string The node path
*/
function getPath();
/**
* Returns true when the node is required.
*
* @return Boolean If the node is required
*/
function isRequired();
/**
* Returns true when the node has a default value.
*
* @return Boolean If the node has a default value
*/
function hasDefaultValue();
/**
* Returns the default value of the node.
*
* @return mixed The default value
* @throws \RuntimeException if the node has no default value
*/
function getDefaultValue();
/**
* Normalizes the supplied value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
*/
function normalize($value);
/**
* Merges two values together.
*
* @param mixed $leftSide
* @param mixed $rightSide
*
* @return mixed The merged values
*/
function merge($leftSide, $rightSide);
/**
* Finalizes a value.
*
* @param mixed $value The value to finalize
*
* @return mixed The finalized value
*/
function finalize($value);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
/**
* This class is the entry point for config normalization/merging/finalization.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class Processor
{
/**
* Processes an array of configurations.
*
* @param NodeInterface $configTree The node tree describing the configuration
* @param array $configs An array of configuration items to process
*
* @return array The processed configuration
*/
public function process(NodeInterface $configTree, array $configs)
{
$configs = self::normalizeKeys($configs);
$currentConfig = array();
foreach ($configs as $config) {
$config = $configTree->normalize($config);
$currentConfig = $configTree->merge($currentConfig, $config);
}
return $configTree->finalize($currentConfig);
}
/**
* Processes an array of configurations.
*
* @param ConfigurationInterface $configuration The configuration class
* @param array $configs An array of configuration items to process
*
* @return array The processed configuration
*/
public function processConfiguration(ConfigurationInterface $configuration, array $configs)
{
return $this->process($configuration->getConfigTreeBuilder()->buildTree(), $configs);
}
/**
* This method normalizes keys between the different configuration formats
*
* Namely, you mostly have foo_bar in YAML while you have foo-bar in XML.
* After running this method, all keys are normalized to foo_bar.
*
* If you have a mixed key like foo-bar_moo, it will not be altered.
* The key will also not be altered if the target key already exists.
*
* @param array $config
*
* @return array the config with normalized keys
*/
static public function normalizeKeys(array $config)
{
foreach ($config as $key => $value) {
if (is_array($value)) {
$config[$key] = self::normalizeKeys($value);
}
if (false !== strpos($key, '-') && false === strpos($key, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $key), $config)) {
$config[$normalizedKey] = $config[$key];
unset($config[$key]);
}
}
return $config;
}
/**
* Normalizes a configuration entry.
*
* This method returns a normalize configuration array for a given key
* to remove the differences due to the original format (YAML and XML mainly).
*
* Here is an example.
*
* The configuration is XML:
*
* <twig:extension id="twig.extension.foo" />
* <twig:extension id="twig.extension.bar" />
*
* And the same configuration in YAML:
*
* twig.extensions: ['twig.extension.foo', 'twig.extension.bar']
*
* @param array $config A config array
* @param string $key The key to normalize
* @param string $plural The plural form of the key if it is irregular
*
* @return array
*/
static public function normalizeConfig($config, $key, $plural = null)
{
if (null === $plural) {
$plural = $key.'s';
}
$values = array();
if (isset($config[$plural])) {
$values = $config[$plural];
} elseif (isset($config[$key])) {
if (is_string($config[$key]) || !is_int(key($config[$key]))) {
// only one
$values = array($config[$key]);
} else {
$values = $config[$key];
}
}
return $values;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\DuplicateKeyException;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
/**
* Represents a prototyped Array node in the config tree.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class PrototypedArrayNode extends ArrayNode
{
protected $prototype;
protected $keyAttribute;
protected $removeKeyAttribute;
protected $minNumberOfElements;
protected $defaultValue;
/**
* Constructor.
*
* @param string $name The Node's name
* @param NodeInterface $parent The node parent
*/
public function __construct($name, NodeInterface $parent = null)
{
parent::__construct($name, $parent);
$this->minNumberOfElements = 0;
}
/**
* Sets the minimum number of elements that a prototype based node must
* contain. By default this is zero, meaning no elements.
*
* @param integer $number
*/
public function setMinNumberOfElements($number)
{
$this->minNumberOfElements = $number;
}
/**
* The name of the attribute which value should be used as key.
*
* This is only relevant for XML configurations, and only in combination
* with a prototype based node.
*
* For example, if "id" is the keyAttribute, then:
*
* array('id' => 'my_name', 'foo' => 'bar')
*
* becomes
*
* 'my_name' => array('foo' => 'bar')
*
* If $remove is false, the resulting array will still have the
* "'id' => 'my_name'" item in it.
*
* @param string $attribute The name of the attribute which value is to be used as a key
* @param Boolean $remove Whether or not to remove the key
*/
public function setKeyAttribute($attribute, $remove = true)
{
$this->keyAttribute = $attribute;
$this->removeKeyAttribute = $remove;
}
/**
* Sets the default value of this node.
*
* @param string $value
*
* @throws \InvalidArgumentException if the default value is not an array
*/
public function setDefaultValue($value)
{
if (!is_array($value)) {
throw new \InvalidArgumentException($this->getPath().': the default value of an array node has to be an array.');
}
$this->defaultValue = $value;
}
/**
* Checks if the node has a default value.
*
* @return Boolean
*/
public function hasDefaultValue()
{
return true;
}
/**
* Retrieves the default value.
*
* @return array The default value
*/
public function getDefaultValue()
{
return $this->defaultValue ?: array();
}
/**
* Sets the node prototype.
*
* @param PrototypeNodeInterface $node
*/
public function setPrototype(PrototypeNodeInterface $node)
{
$this->prototype = $node;
}
/**
* Disable adding concrete children for prototyped nodes.
*
* @param NodeInterface $node The child node to add
*
* @throws \RuntimeException Prototyped array nodes can't have concrete children.
*/
public function addChild(NodeInterface $node)
{
throw new \RuntimeException('A prototyped array node can not have concrete children.');
}
/**
* Finalizes the value of this node.
*
* @param mixed $value
*
* @return mixed The finalised value
*
* @throws UnsetKeyException
* @throws InvalidConfigurationException if the node doesn't have enough children
*/
protected function finalizeValue($value)
{
if (false === $value) {
$msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
throw new UnsetKeyException($msg);
}
foreach ($value as $k => $v) {
$this->prototype->setName($k);
try {
$value[$k] = $this->prototype->finalize($v);
} catch (UnsetKeyException $unset) {
unset($value[$k]);
}
}
if (count($value) < $this->minNumberOfElements) {
$msg = sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements);
$ex = new InvalidConfigurationException($msg);
$ex->setPath($this->getPath());
throw $ex;
}
return $value;
}
/**
* Normalizes the value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
*/
protected function normalizeValue($value)
{
if (false === $value) {
return $value;
}
$value = $this->remapXml($value);
$normalized = array();
foreach ($value as $k => $v) {
if (null !== $this->keyAttribute && is_array($v)) {
if (!isset($v[$this->keyAttribute]) && is_int($k)) {
$msg = sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath());
$ex = new InvalidConfigurationException($msg);
$ex->setPath($this->getPath());
throw $ex;
} elseif (isset($v[$this->keyAttribute])) {
$k = $v[$this->keyAttribute];
// remove the key attribute when required
if ($this->removeKeyAttribute) {
unset($v[$this->keyAttribute]);
}
// if only "value" is left
if (1 == count($v) && isset($v['value'])) {
$v = $v['value'];
}
}
if (array_key_exists($k, $normalized)) {
$msg = sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath());
$ex = new DuplicateKeyException($msg);
$ex->setPath($this->getPath());
throw $ex;
}
}
$this->prototype->setName($k);
if (null !== $this->keyAttribute) {
$normalized[$k] = $this->prototype->normalize($v);
} else {
$normalized[] = $this->prototype->normalize($v);
}
}
return $normalized;
}
/**
* Merges values together.
*
* @param mixed $leftSide The left side to merge.
* @param mixed $rightSide The right side to merge.
*
* @return mixed The merged values
*
* @throws InvalidConfigurationException
* @throws \RuntimeException
*/
protected function mergeValues($leftSide, $rightSide)
{
if (false === $rightSide) {
// if this is still false after the last config has been merged the
// finalization pass will take care of removing this key entirely
return false;
}
if (false === $leftSide || !$this->performDeepMerging) {
return $rightSide;
}
foreach ($rightSide as $k => $v) {
// prototype, and key is irrelevant, so simply append the element
if (null === $this->keyAttribute) {
$leftSide[] = $v;
continue;
}
// no conflict
if (!array_key_exists($k, $leftSide)) {
if (!$this->allowNewKeys) {
$ex = new InvalidConfigurationException(sprintf(
'You are not allowed to define new elements for path "%s". ' .
'Please define all elements for this path in one config file.',
$this->getPath()
));
$ex->setPath($this->getPath());
throw $ex;
}
$leftSide[$k] = $v;
continue;
}
$this->prototype->setName($k);
$leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
}
return $leftSide;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
/**
* This interface must be implemented by nodes which can be used as prototypes.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface PrototypeNodeInterface extends NodeInterface
{
/**
* Sets the name of the node.
*
* @param string $name The name of the node
*/
function setName($name);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\VariableNode;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* This node represents a scalar value in the config tree.
*
* The following values are considered scalars:
* * booleans
* * strings
* * null
* * integers
* * floats
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ScalarNode extends VariableNode
{
/**
* {@inheritDoc}
*/
protected function validateType($value)
{
if (!is_scalar($value) && null !== $value) {
$ex = new InvalidTypeException(sprintf(
'Invalid type for path "%s". Expected scalar, but got %s.',
$this->getPath(),
gettype($value)
));
$ex->setPath($this->getPath());
throw $ex;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
/**
* This node represents a value of variable type in the config tree.
*
* This node is intended for values of arbitrary type.
* Any PHP type is accepted as a value.
*
* @author Jeremy Mikola <jmikola@gmail.com>
*/
class VariableNode extends BaseNode implements PrototypeNodeInterface
{
protected $defaultValueSet = false;
protected $defaultValue;
protected $allowEmptyValue = true;
/**
* {@inheritDoc}
*/
public function setDefaultValue($value)
{
$this->defaultValueSet = true;
$this->defaultValue = $value;
}
/**
* {@inheritDoc}
*/
public function hasDefaultValue()
{
return $this->defaultValueSet;
}
/**
* {@inheritDoc}
*/
public function getDefaultValue()
{
return $this->defaultValue instanceof \Closure ? call_user_func($this->defaultValue) : $this->defaultValue;
}
/**
* Sets if this node is allowed to have an empty value.
*
* @param Boolean $boolean True if this entity will accept empty values.
*/
public function setAllowEmptyValue($boolean)
{
$this->allowEmptyValue = (Boolean) $boolean;
}
/**
* {@inheritDoc}
*/
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritDoc}
*/
protected function validateType($value)
{
}
/**
* {@inheritDoc}
*/
protected function finalizeValue($value)
{
if (!$this->allowEmptyValue && empty($value)) {
$ex = new InvalidConfigurationException(sprintf(
'The path "%s" cannot contain an empty value, but got %s.',
$this->getPath(),
json_encode($value)
));
$ex->setPath($this->getPath());
throw $ex;
}
return $value;
}
/**
* {@inheritDoc}
*/
protected function normalizeValue($value)
{
return $value;
}
/**
* {@inheritDoc}
*/
protected function mergeValues($leftSide, $rightSide)
{
return $rightSide;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Exception;
/**
* Exception class for when a circular reference is detected when importing resources.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FileLoaderImportCircularReferenceException extends FileLoaderLoadException
{
public function __construct(array $resources, $code = null, $previous = null)
{
$message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);
call_user_func('Exception::__construct', $message, $code, $previous);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Exception;
/**
* Exception class for when a resource cannot be loaded or imported.
*
* @author Ryan Weaver <ryan@thatsquality.com>
*/
class FileLoaderLoadException extends \Exception
{
/**
* @param string $resource The resource that could not be imported
* @param string $sourceResource The original resource importing the new resource
* @param integer $code The error code
* @param Exception $previous A previous exception
*/
public function __construct($resource, $sourceResource = null, $code = null, $previous = null)
{
if (null === $sourceResource) {
$message = sprintf('Cannot load resource "%s".', $this->varToString($resource));
} else {
$message = sprintf('Cannot import resource "%s" from "%s".', $this->varToString($resource), $this->varToString($sourceResource));
}
// Is the resource located inside a bundle?
if ('@' === $resource[0]) {
$parts = explode(DIRECTORY_SEPARATOR, $resource);
$bundle = substr($parts[0], 1);
$message .= ' '.sprintf('Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
}
parent::__construct($message, $code, $previous);
}
protected function varToString($var)
{
if (is_object($var)) {
return sprintf('Object(%s)', get_class($var));
}
if (is_array($var)) {
$a = array();
foreach ($var as $k => $v) {
$a[] = sprintf('%s => %s', $k, $this->varToString($v));
}
return sprintf("Array(%s)", implode(', ', $a));
}
if (is_resource($var)) {
return sprintf('Resource(%s)', get_resource_type($var));
}
if (null === $var) {
return 'null';
}
if (false === $var) {
return 'false';
}
if (true === $var) {
return 'true';
}
return (string) $var;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
/**
* FileLocator uses an array of pre-defined paths to find files.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FileLocator implements FileLocatorInterface
{
protected $paths;
/**
* Constructor.
*
* @param string|array $paths A path or an array of paths where to look for resources
*/
public function __construct($paths = array())
{
$this->paths = (array) $paths;
}
/**
* Returns a full path for a given file name.
*
* @param mixed $name The file name to locate
* @param string $currentPath The current path
* @param Boolean $first Whether to return the first occurrence or an array of filenames
*
* @return string|array The full path to the file|An array of file paths
*
* @throws \InvalidArgumentException When file is not found
*/
public function locate($name, $currentPath = null, $first = true)
{
if ($this->isAbsolutePath($name)) {
if (!file_exists($name)) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $name));
}
return $name;
}
$filepaths = array();
if (null !== $currentPath && file_exists($file = $currentPath.DIRECTORY_SEPARATOR.$name)) {
if (true === $first) {
return $file;
}
$filepaths[] = $file;
}
foreach ($this->paths as $path) {
if (file_exists($file = $path.DIRECTORY_SEPARATOR.$name)) {
if (true === $first) {
return $file;
}
$filepaths[] = $file;
}
}
if (!$filepaths) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist (in: %s%s).', $name, null !== $currentPath ? $currentPath.', ' : '', implode(', ', $this->paths)));
}
return array_values(array_unique($filepaths));
}
/**
* Returns whether the file path is an absolute path.
*
* @param string $file A file path
*
* @return Boolean
*/
private function isAbsolutePath($file)
{
if ($file[0] == '/' || $file[0] == '\\'
|| (strlen($file) > 3 && ctype_alpha($file[0])
&& $file[1] == ':'
&& ($file[2] == '\\' || $file[2] == '/')
)
) {
return true;
}
return false;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
interface FileLocatorInterface
{
/**
* Returns a full path for a given file name.
*
* @param mixed $name The file name to locate
* @param string $currentPath The current path
* @param Boolean $first Whether to return the first occurrence or an array of filenames
*
* @return string|array The full path to the file|An array of file paths
*
* @throws \InvalidArgumentException When file is not found
*/
function locate($name, $currentPath = null, $first = true);
}
Copyright (c) 2004-2012 Fabien Potencier
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.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
/**
* DelegatingLoader delegates loading to other loaders using a loader resolver.
*
* This loader acts as an array of LoaderInterface objects - each having
* a chance to load a given resource (handled by the resolver)
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DelegatingLoader extends Loader
{
/**
* Constructor.
*
* @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
*/
public function __construct(LoaderResolverInterface $resolver)
{
$this->resolver = $resolver;
}
/**
* Loads a resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return mixed
*
* @throws FileLoaderLoadException if no loader is found.
*/
public function load($resource, $type = null)
{
if (false === $loader = $this->resolver->resolve($resource, $type)) {
throw new FileLoaderLoadException($resource);
}
return $loader->load($resource, $type);
}
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean true if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return false === $this->resolver->resolve($resource, $type) ? false : true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException;
/**
* FileLoader is the abstract class used by all built-in loaders that are file based.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class FileLoader extends Loader
{
static protected $loading = array();
protected $locator;
private $currentDir;
/**
* Constructor.
*
* @param FileLocatorInterface $locator A FileLocatorInterface instance
*/
public function __construct(FileLocatorInterface $locator)
{
$this->locator = $locator;
}
public function setCurrentDir($dir)
{
$this->currentDir = $dir;
}
public function getLocator()
{
return $this->locator;
}
/**
* Imports a resource.
*
* @param mixed $resource A Resource
* @param string $type The resource type
* @param Boolean $ignoreErrors Whether to ignore import errors or not
* @param string $sourceResource The original resource importing the new resource
*
* @return mixed
*/
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
{
try {
$loader = $this->resolve($resource, $type);
if ($loader instanceof FileLoader && null !== $this->currentDir) {
$resource = $this->locator->locate($resource, $this->currentDir);
}
if (isset(self::$loading[$resource])) {
throw new FileLoaderImportCircularReferenceException(array_keys(self::$loading));
}
self::$loading[$resource] = true;
$ret = $loader->load($resource);
unset(self::$loading[$resource]);
return $ret;
} catch (FileLoaderImportCircularReferenceException $e) {
throw $e;
} catch (\Exception $e) {
if (!$ignoreErrors) {
// prevent embedded imports from nesting multiple exceptions
if ($e instanceof FileLoaderLoadException) {
throw $e;
}
throw new FileLoaderLoadException($resource, $sourceResource, null, $e);
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
/**
* Loader is the abstract class used by all built-in loaders.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Loader implements LoaderInterface
{
protected $resolver;
/**
* Gets the loader resolver.
*
* @return LoaderResolver A LoaderResolver instance
*/
public function getResolver()
{
return $this->resolver;
}
/**
* Sets the loader resolver.
*
* @param LoaderResolver $resolver A LoaderResolver instance
*/
public function setResolver(LoaderResolver $resolver)
{
$this->resolver = $resolver;
}
/**
* Imports a resource.
*
* @param mixed $resource A Resource
* @param string $type The resource type
*/
public function import($resource, $type = null)
{
$this->resolve($resource)->load($resource, $type);
}
/**
* Finds a loader able to load an imported resource.
*
* @param mixed $resource A Resource
* @param string $type The resource type
*
* @return LoaderInterface A LoaderInterface instance
*
* @throws FileLoaderLoadException if no loader is found
*/
public function resolve($resource, $type = null)
{
if ($this->supports($resource, $type)) {
return $this;
}
$loader = null === $this->resolver ? false : $this->resolver->resolve($resource, $type);
if (false === $loader) {
throw new FileLoaderLoadException($resource);
}
return $loader;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
/**
* LoaderInterface is the interface implemented by all loader classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface LoaderInterface
{
/**
* Loads a resource.
*
* @param mixed $resource The resource
* @param string $type The resource type
*/
function load($resource, $type = null);
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean true if this class supports the given resource, false otherwise
*/
function supports($resource, $type = null);
/**
* Gets the loader resolver.
*
* @return LoaderResolver A LoaderResolver instance
*/
function getResolver();
/**
* Sets the loader resolver.
*
* @param LoaderResolver $resolver A LoaderResolver instance
*/
function setResolver(LoaderResolver $resolver);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
/**
* LoaderResolver selects a loader for a given resource.
*
* A resource can be anything (e.g. a full path to a config file or a Closure).
* Each loader determines whether it can load a resource and how.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class LoaderResolver implements LoaderResolverInterface
{
/**
* @var LoaderInterface[] An array of LoaderInterface objects
*/
private $loaders;
/**
* Constructor.
*
* @param LoaderInterface[] $loaders An array of loaders
*/
public function __construct(array $loaders = array())
{
$this->loaders = array();
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
/**
* Returns a loader able to load the resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return LoaderInterface|false A LoaderInterface instance
*/
public function resolve($resource, $type = null)
{
foreach ($this->loaders as $loader) {
if ($loader->supports($resource, $type)) {
return $loader;
}
}
return false;
}
/**
* Adds a loader.
*
* @param LoaderInterface $loader A LoaderInterface instance
*/
public function addLoader(LoaderInterface $loader)
{
$this->loaders[] = $loader;
$loader->setResolver($this);
}
/**
* Returns the registered loaders.
*
* @return LoaderInterface[] An array of LoaderInterface instances
*/
public function getLoaders()
{
return $this->loaders;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
/**
* LoaderResolverInterface selects a loader for a given resource.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface LoaderResolverInterface
{
/**
* Returns a loader able to load the resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return LoaderInterface A LoaderInterface instance
*/
function resolve($resource, $type = null);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* DirectoryResource represents a resources stored in a subdirectory tree.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DirectoryResource implements ResourceInterface
{
private $resource;
private $pattern;
/**
* Constructor.
*
* @param string $resource The file path to the resource
* @param string $pattern A pattern to restrict monitored files
*/
public function __construct($resource, $pattern = null)
{
$this->resource = $resource;
$this->pattern = $pattern;
}
/**
* Returns a string representation of the Resource.
*
* @return string A string representation of the Resource
*/
public function __toString()
{
return (string) $this->resource;
}
/**
* Returns the resource tied to this Resource.
*
* @return mixed The resource
*/
public function getResource()
{
return $this->resource;
}
/**
* Returns true if the resource has not been updated since the given timestamp.
*
* @param integer $timestamp The last time the resource was loaded
*
* @return Boolean true if the resource has not been updated, false otherwise
*/
public function isFresh($timestamp)
{
if (!file_exists($this->resource)) {
return false;
}
$newestMTime = filemtime($this->resource);
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
// if regex filtering is enabled only check matching files
if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
continue;
}
// always monitor directories for changes, except the .. entries
// (otherwise deleted files wouldn't get detected)
if ($file->isDir() && '/..' === substr($file, -3)) {
continue;
}
$newestMTime = max($file->getMTime(), $newestMTime);
}
return $newestMTime < $timestamp;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* FileResource represents a resource stored on the filesystem.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FileResource implements ResourceInterface
{
private $resource;
/**
* Constructor.
*
* @param string $resource The file path to the resource
*/
public function __construct($resource)
{
$this->resource = realpath($resource);
}
/**
* Returns a string representation of the Resource.
*
* @return string A string representation of the Resource
*/
public function __toString()
{
return (string) $this->resource;
}
/**
* Returns the resource tied to this Resource.
*
* @return mixed The resource
*/
public function getResource()
{
return $this->resource;
}
/**
* Returns true if the resource has not been updated since the given timestamp.
*
* @param integer $timestamp The last time the resource was loaded
*
* @return Boolean true if the resource has not been updated, false otherwise
*/
public function isFresh($timestamp)
{
if (!file_exists($this->resource)) {
return false;
}
return filemtime($this->resource) < $timestamp;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* ResourceInterface is the interface that must be implemented by all Resource classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ResourceInterface
{
/**
* Returns a string representation of the Resource.
*
* @return string A string representation of the Resource
*/
function __toString();
/**
* Returns true if the resource has not been updated since the given timestamp.
*
* @param integer $timestamp The last time the resource was loaded
*
* @return Boolean true if the resource has not been updated, false otherwise
*/
function isFresh($timestamp);
/**
* Returns the resource tied to this Resource.
*
* @return mixed The resource
*/
function getResource();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Command\HelpCommand;
use Symfony\Component\Console\Command\ListCommand;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\DialogHelper;
/**
* An Application is the container for a collection of commands.
*
* It is the main entry point of a Console application.
*
* This class is optimized for a standard CLI environment.
*
* Usage:
*
* $app = new Application('myapp', '1.0 (stable)');
* $app->add(new SimpleCommand());
* $app->run();
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Application
{
private $commands;
private $wantHelps = false;
private $runningCommand;
private $name;
private $version;
private $catchExceptions;
private $autoExit;
private $definition;
private $helperSet;
/**
* Constructor.
*
* @param string $name The name of the application
* @param string $version The version of the application
*
* @api
*/
public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
{
$this->name = $name;
$this->version = $version;
$this->catchExceptions = true;
$this->autoExit = true;
$this->commands = array();
$this->helperSet = new HelperSet(array(
new FormatterHelper(),
new DialogHelper(),
));
$this->add(new HelpCommand());
$this->add(new ListCommand());
$this->definition = new InputDefinition(array(
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message.'),
new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message.'),
new InputOption('--verbose', '-v', InputOption::VALUE_NONE, 'Increase verbosity of messages.'),
new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version.'),
new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output.'),
new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output.'),
new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question.'),
));
}
/**
* Runs the current application.
*
* @param InputInterface $input An Input instance
* @param OutputInterface $output An Output instance
*
* @return integer 0 if everything went fine, or an error code
*
* @throws \Exception When doRun returns Exception
*
* @api
*/
public function run(InputInterface $input = null, OutputInterface $output = null)
{
if (null === $input) {
$input = new ArgvInput();
}
if (null === $output) {
$output = new ConsoleOutput();
}
try {
$statusCode = $this->doRun($input, $output);
} catch (\Exception $e) {
if (!$this->catchExceptions) {
throw $e;
}
$this->renderException($e, $output);
$statusCode = $e->getCode();
$statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1;
}
if ($this->autoExit) {
if ($statusCode > 255) {
$statusCode = 255;
}
// @codeCoverageIgnoreStart
exit($statusCode);
// @codeCoverageIgnoreEnd
}
return $statusCode;
}
/**
* Runs the current application.
*
* @param InputInterface $input An Input instance
* @param OutputInterface $output An Output instance
*
* @return integer 0 if everything went fine, or an error code
*/
public function doRun(InputInterface $input, OutputInterface $output)
{
$name = $this->getCommandName($input);
if (true === $input->hasParameterOption(array('--ansi'))) {
$output->setDecorated(true);
} elseif (true === $input->hasParameterOption(array('--no-ansi'))) {
$output->setDecorated(false);
}
if (true === $input->hasParameterOption(array('--help', '-h'))) {
if (!$name) {
$name = 'help';
$input = new ArrayInput(array('command' => 'help'));
} else {
$this->wantHelps = true;
}
}
if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) {
$input->setInteractive(false);
}
if (true === $input->hasParameterOption(array('--quiet', '-q'))) {
$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
} elseif (true === $input->hasParameterOption(array('--verbose', '-v'))) {
$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
}
if (true === $input->hasParameterOption(array('--version', '-V'))) {
$output->writeln($this->getLongVersion());
return 0;
}
if (!$name) {
$name = 'list';
$input = new ArrayInput(array('command' => 'list'));
}
// the command name MUST be the first element of the input
$command = $this->find($name);
$this->runningCommand = $command;
$statusCode = $command->run($input, $output);
$this->runningCommand = null;
return is_numeric($statusCode) ? $statusCode : 0;
}
/**
* Set a helper set to be used with the command.
*
* @param HelperSet $helperSet The helper set
*
* @api
*/
public function setHelperSet(HelperSet $helperSet)
{
$this->helperSet = $helperSet;
}
/**
* Get the helper set associated with the command.
*
* @return HelperSet The HelperSet instance associated with this command
*
* @api
*/
public function getHelperSet()
{
return $this->helperSet;
}
/**
* Gets the InputDefinition related to this Application.
*
* @return InputDefinition The InputDefinition instance
*/
public function getDefinition()
{
return $this->definition;
}
/**
* Gets the help message.
*
* @return string A help message.
*/
public function getHelp()
{
$messages = array(
$this->getLongVersion(),
'',
'<comment>Usage:</comment>',
sprintf(" [options] command [arguments]\n"),
'<comment>Options:</comment>',
);
foreach ($this->getDefinition()->getOptions() as $option) {
$messages[] = sprintf(' %-29s %s %s',
'<info>--'.$option->getName().'</info>',
$option->getShortcut() ? '<info>-'.$option->getShortcut().'</info>' : ' ',
$option->getDescription()
);
}
return implode("\n", $messages);
}
/**
* Sets whether to catch exceptions or not during commands execution.
*
* @param Boolean $boolean Whether to catch exceptions or not during commands execution
*
* @api
*/
public function setCatchExceptions($boolean)
{
$this->catchExceptions = (Boolean) $boolean;
}
/**
* Sets whether to automatically exit after a command execution or not.
*
* @param Boolean $boolean Whether to automatically exit after a command execution or not
*
* @api
*/
public function setAutoExit($boolean)
{
$this->autoExit = (Boolean) $boolean;
}
/**
* Gets the name of the application.
*
* @return string The application name
*
* @api
*/
public function getName()
{
return $this->name;
}
/**
* Sets the application name.
*
* @param string $name The application name
*
* @api
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Gets the application version.
*
* @return string The application version
*
* @api
*/
public function getVersion()
{
return $this->version;
}
/**
* Sets the application version.
*
* @param string $version The application version
*
* @api
*/
public function setVersion($version)
{
$this->version = $version;
}
/**
* Returns the long version of the application.
*
* @return string The long application version
*
* @api
*/
public function getLongVersion()
{
if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
}
return '<info>Console Tool</info>';
}
/**
* Registers a new command.
*
* @param string $name The command name
*
* @return Command The newly created command
*
* @api
*/
public function register($name)
{
return $this->add(new Command($name));
}
/**
* Adds an array of command objects.
*
* @param Command[] $commands An array of commands
*
* @api
*/
public function addCommands(array $commands)
{
foreach ($commands as $command) {
$this->add($command);
}
}
/**
* Adds a command object.
*
* If a command with the same name already exists, it will be overridden.
*
* @param Command $command A Command object
*
* @return Command The registered command
*
* @api
*/
public function add(Command $command)
{
$command->setApplication($this);
$this->commands[$command->getName()] = $command;
foreach ($command->getAliases() as $alias) {
$this->commands[$alias] = $command;
}
return $command;
}
/**
* Returns a registered command by name or alias.
*
* @param string $name The command name or alias
*
* @return Command A Command object
*
* @throws \InvalidArgumentException When command name given does not exist
*
* @api
*/
public function get($name)
{
if (!isset($this->commands[$name])) {
throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
}
$command = $this->commands[$name];
if ($this->wantHelps) {
$this->wantHelps = false;
$helpCommand = $this->get('help');
$helpCommand->setCommand($command);
return $helpCommand;
}
return $command;
}
/**
* Returns true if the command exists, false otherwise.
*
* @param string $name The command name or alias
*
* @return Boolean true if the command exists, false otherwise
*
* @api
*/
public function has($name)
{
return isset($this->commands[$name]);
}
/**
* Returns an array of all unique namespaces used by currently registered commands.
*
* It does not returns the global namespace which always exists.
*
* @return array An array of namespaces
*/
public function getNamespaces()
{
$namespaces = array();
foreach ($this->commands as $command) {
$namespaces[] = $this->extractNamespace($command->getName());
foreach ($command->getAliases() as $alias) {
$namespaces[] = $this->extractNamespace($alias);
}
}
return array_values(array_unique(array_filter($namespaces)));
}
/**
* Finds a registered namespace by a name or an abbreviation.
*
* @param string $namespace A namespace or abbreviation to search for
*
* @return string A registered namespace
*
* @throws \InvalidArgumentException When namespace is incorrect or ambiguous
*/
public function findNamespace($namespace)
{
$allNamespaces = array();
foreach ($this->getNamespaces() as $n) {
$allNamespaces[$n] = explode(':', $n);
}
$found = array();
foreach (explode(':', $namespace) as $i => $part) {
$abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $allNamespaces)))));
if (!isset($abbrevs[$part])) {
throw new \InvalidArgumentException(sprintf('There are no commands defined in the "%s" namespace.', $namespace));
}
if (count($abbrevs[$part]) > 1) {
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$part])));
}
$found[] = $abbrevs[$part][0];
}
return implode(':', $found);
}
/**
* Finds a command by name or alias.
*
* Contrary to get, this command tries to find the best
* match if you give it an abbreviation of a name or alias.
*
* @param string $name A command name or a command alias
*
* @return Command A Command instance
*
* @throws \InvalidArgumentException When command name is incorrect or ambiguous
*
* @api
*/
public function find($name)
{
// namespace
$namespace = '';
$searchName = $name;
if (false !== $pos = strrpos($name, ':')) {
$namespace = $this->findNamespace(substr($name, 0, $pos));
$searchName = $namespace.substr($name, $pos);
}
// name
$commands = array();
foreach ($this->commands as $command) {
if ($this->extractNamespace($command->getName()) == $namespace) {
$commands[] = $command->getName();
}
}
$abbrevs = static::getAbbreviations(array_unique($commands));
if (isset($abbrevs[$searchName]) && 1 == count($abbrevs[$searchName])) {
return $this->get($abbrevs[$searchName][0]);
}
if (isset($abbrevs[$searchName]) && count($abbrevs[$searchName]) > 1) {
$suggestions = $this->getAbbreviationSuggestions($abbrevs[$searchName]);
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
}
// aliases
$aliases = array();
foreach ($this->commands as $command) {
foreach ($command->getAliases() as $alias) {
if ($this->extractNamespace($alias) == $namespace) {
$aliases[] = $alias;
}
}
}
$abbrevs = static::getAbbreviations(array_unique($aliases));
if (!isset($abbrevs[$searchName])) {
throw new \InvalidArgumentException(sprintf('Command "%s" is not defined.', $name));
}
if (count($abbrevs[$searchName]) > 1) {
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $this->getAbbreviationSuggestions($abbrevs[$searchName])));
}
return $this->get($abbrevs[$searchName][0]);
}
/**
* Gets the commands (registered in the given namespace if provided).
*
* The array keys are the full names and the values the command instances.
*
* @param string $namespace A namespace name
*
* @return array An array of Command instances
*
* @api
*/
public function all($namespace = null)
{
if (null === $namespace) {
return $this->commands;
}
$commands = array();
foreach ($this->commands as $name => $command) {
if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
$commands[$name] = $command;
}
}
return $commands;
}
/**
* Returns an array of possible abbreviations given a set of names.
*
* @param array $names An array of names
*
* @return array An array of abbreviations
*/
static public function getAbbreviations($names)
{
$abbrevs = array();
foreach ($names as $name) {
for ($len = strlen($name) - 1; $len > 0; --$len) {
$abbrev = substr($name, 0, $len);
if (!isset($abbrevs[$abbrev])) {
$abbrevs[$abbrev] = array($name);
} else {
$abbrevs[$abbrev][] = $name;
}
}
}
// Non-abbreviations always get entered, even if they aren't unique
foreach ($names as $name) {
$abbrevs[$name] = array($name);
}
return $abbrevs;
}
/**
* Returns a text representation of the Application.
*
* @param string $namespace An optional namespace name
*
* @return string A string representing the Application
*/
public function asText($namespace = null)
{
$commands = $namespace ? $this->all($this->findNamespace($namespace)) : $this->commands;
$messages = array($this->getHelp(), '');
if ($namespace) {
$messages[] = sprintf("<comment>Available commands for the \"%s\" namespace:</comment>", $namespace);
} else {
$messages[] = '<comment>Available commands:</comment>';
}
$width = 0;
foreach ($commands as $command) {
$width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width;
}
$width += 2;
// add commands by namespace
foreach ($this->sortCommands($commands) as $space => $commands) {
if (!$namespace && '_global' !== $space) {
$messages[] = '<comment>'.$space.'</comment>';
}
foreach ($commands as $name => $command) {
$messages[] = sprintf(" <info>%-${width}s</info> %s", $name, $command->getDescription());
}
}
return implode(PHP_EOL, $messages);
}
/**
* Returns an XML representation of the Application.
*
* @param string $namespace An optional namespace name
* @param Boolean $asDom Whether to return a DOM or an XML string
*
* @return string|DOMDocument An XML string representing the Application
*/
public function asXml($namespace = null, $asDom = false)
{
$commands = $namespace ? $this->all($this->findNamespace($namespace)) : $this->commands;
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$dom->appendChild($xml = $dom->createElement('symfony'));
$xml->appendChild($commandsXML = $dom->createElement('commands'));
if ($namespace) {
$commandsXML->setAttribute('namespace', $namespace);
} else {
$namespacesXML = $dom->createElement('namespaces');
$xml->appendChild($namespacesXML);
}
// add commands by namespace
foreach ($this->sortCommands($commands) as $space => $commands) {
if (!$namespace) {
$namespaceArrayXML = $dom->createElement('namespace');
$namespacesXML->appendChild($namespaceArrayXML);
$namespaceArrayXML->setAttribute('id', $space);
}
foreach ($commands as $name => $command) {
if ($name !== $command->getName()) {
continue;
}
if (!$namespace) {
$commandXML = $dom->createElement('command');
$namespaceArrayXML->appendChild($commandXML);
$commandXML->appendChild($dom->createTextNode($name));
}
$node = $command->asXml(true)->getElementsByTagName('command')->item(0);
$node = $dom->importNode($node, true);
$commandsXML->appendChild($node);
}
}
return $asDom ? $dom : $dom->saveXml();
}
/**
* Renders a caught exception.
*
* @param Exception $e An exception instance
* @param OutputInterface $output An OutputInterface instance
*/
public function renderException($e, $output)
{
$strlen = function ($string) {
if (!function_exists('mb_strlen')) {
return strlen($string);
}
if (false === $encoding = mb_detect_encoding($string)) {
return strlen($string);
}
return mb_strlen($string, $encoding);
};
do {
$title = sprintf(' [%s] ', get_class($e));
$len = $strlen($title);
$width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;
$lines = array();
foreach (preg_split("{\r?\n}", $e->getMessage()) as $line) {
foreach (str_split($line, $width - 4) as $line) {
$lines[] = sprintf(' %s ', $line);
$len = max($strlen($line) + 4, $len);
}
}
$messages = array(str_repeat(' ', $len), $title.str_repeat(' ', max(0, $len - $strlen($title))));
foreach ($lines as $line) {
$messages[] = $line.str_repeat(' ', $len - $strlen($line));
}
$messages[] = str_repeat(' ', $len);
$output->writeln("\n");
foreach ($messages as $message) {
$output->writeln('<error>'.$message.'</error>');
}
$output->writeln("\n");
if (OutputInterface::VERBOSITY_VERBOSE === $output->getVerbosity()) {
$output->writeln('<comment>Exception trace:</comment>');
// exception related properties
$trace = $e->getTrace();
array_unshift($trace, array(
'function' => '',
'file' => $e->getFile() != null ? $e->getFile() : 'n/a',
'line' => $e->getLine() != null ? $e->getLine() : 'n/a',
'args' => array(),
));
for ($i = 0, $count = count($trace); $i < $count; $i++) {
$class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
$type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
$function = $trace[$i]['function'];
$file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
$line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
$output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line));
}
$output->writeln("\n");
}
} while ($e = $e->getPrevious());
if (null !== $this->runningCommand) {
$output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())));
$output->writeln("");
$output->writeln("");
}
}
/**
* Tries to figure out the terminal width in which this application runs
*
* @return int|null
*/
protected function getTerminalWidth()
{
if (defined('PHP_WINDOWS_VERSION_BUILD') && $ansicon = getenv('ANSICON')) {
return preg_replace('{^(\d+)x.*$}', '$1', $ansicon);
}
if (preg_match("{rows.(\d+);.columns.(\d+);}i", exec('stty -a | grep columns'), $match)) {
return $match[2];
}
}
/**
* Tries to figure out the terminal height in which this application runs
*
* @return int|null
*/
protected function getTerminalHeight()
{
if (defined('PHP_WINDOWS_VERSION_BUILD') && $ansicon = getenv('ANSICON')) {
return preg_replace('{^\d+x\d+ \(\d+x(\d+)\)$}', '$1', trim($ansicon));
}
if (preg_match("{rows.(\d+);.columns.(\d+);}i", exec('stty -a | grep columns'), $match)) {
return $match[1];
}
}
/**
* Gets the name of the command based on input.
*
* @param InputInterface $input The input interface
*
* @return string The command name
*/
protected function getCommandName(InputInterface $input)
{
return $input->getFirstArgument('command');
}
/**
* Sorts commands in alphabetical order.
*
* @param array $commands An associative array of commands to sort
*
* @return array A sorted array of commands
*/
private function sortCommands($commands)
{
$namespacedCommands = array();
foreach ($commands as $name => $command) {
$key = $this->extractNamespace($name, 1);
if (!$key) {
$key = '_global';
}
$namespacedCommands[$key][$name] = $command;
}
ksort($namespacedCommands);
foreach ($namespacedCommands as &$commands) {
ksort($commands);
}
return $namespacedCommands;
}
/**
* Returns abbreviated suggestions in string format.
*
* @param array $abbrevs Abbreviated suggestions to convert
*
* @return string A formatted string of abbreviated suggestions
*/
private function getAbbreviationSuggestions($abbrevs)
{
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
}
/**
* Returns the namespace part of the command name.
*
* @param string $name The full name of the command
* @param string $limit The maximum number of parts of the namespace
*
* @return string The namespace of the command
*/
private function extractNamespace($name, $limit = null)
{
$parts = explode(':', $name);
array_pop($parts);
return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\HelperSet;
/**
* Base class for all commands.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Command
{
private $application;
private $name;
private $aliases;
private $definition;
private $help;
private $description;
private $ignoreValidationErrors;
private $applicationDefinitionMerged;
private $code;
private $synopsis;
private $helperSet;
/**
* Constructor.
*
* @param string $name The name of the command
*
* @throws \LogicException When the command name is empty
*
* @api
*/
public function __construct($name = null)
{
$this->definition = new InputDefinition();
$this->ignoreValidationErrors = false;
$this->applicationDefinitionMerged = false;
$this->aliases = array();
if (null !== $name) {
$this->setName($name);
}
$this->configure();
if (!$this->name) {
throw new \LogicException('The command name cannot be empty.');
}
}
/**
* Ignores validation errors.
*
* This is mainly useful for the help command.
*/
public function ignoreValidationErrors()
{
$this->ignoreValidationErrors = true;
}
/**
* Sets the application instance for this command.
*
* @param Application $application An Application instance
*
* @api
*/
public function setApplication(Application $application = null)
{
$this->application = $application;
if ($application) {
$this->setHelperSet($application->getHelperSet());
} else {
$this->helperSet = null;
}
}
/**
* Sets the helper set.
*
* @param HelperSet $helperSet A HelperSet instance
*/
public function setHelperSet(HelperSet $helperSet)
{
$this->helperSet = $helperSet;
}
/**
* Gets the helper set.
*
* @return HelperSet A HelperSet instance
*/
public function getHelperSet()
{
return $this->helperSet;
}
/**
* Gets the application instance for this command.
*
* @return Application An Application instance
*
* @api
*/
public function getApplication()
{
return $this->application;
}
/**
* Configures the current command.
*/
protected function configure()
{
}
/**
* Executes the current command.
*
* This method is not abstract because you can use this class
* as a concrete class. In this case, instead of defining the
* execute() method, you set the code to execute by passing
* a Closure to the setCode() method.
*
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
* @return integer 0 if everything went fine, or an error code
*
* @throws \LogicException When this abstract method is not implemented
* @see setCode()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
throw new \LogicException('You must override the execute() method in the concrete command class.');
}
/**
* Interacts with the user.
*
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*/
protected function interact(InputInterface $input, OutputInterface $output)
{
}
/**
* Initializes the command just after the input has been validated.
*
* This is mainly useful when a lot of commands extends one main command
* where some things need to be initialized based on the input arguments and options.
*
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*/
protected function initialize(InputInterface $input, OutputInterface $output)
{
}
/**
* Runs the command.
*
* The code to execute is either defined directly with the
* setCode() method or by overriding the execute() method
* in a sub-class.
*
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
* @return integer The command exit code
*
* @see setCode()
* @see execute()
*
* @api
*/
public function run(InputInterface $input, OutputInterface $output)
{
// force the creation of the synopsis before the merge with the app definition
$this->getSynopsis();
// add the application arguments and options
$this->mergeApplicationDefinition();
// bind the input against the command specific arguments/options
try {
$input->bind($this->definition);
} catch (\Exception $e) {
if (!$this->ignoreValidationErrors) {
throw $e;
}
}
$this->initialize($input, $output);
if ($input->isInteractive()) {
$this->interact($input, $output);
}
$input->validate();
if ($this->code) {
return call_user_func($this->code, $input, $output);
}
return $this->execute($input, $output);
}
/**
* Sets the code to execute when running this command.
*
* If this method is used, it overrides the code defined
* in the execute() method.
*
* @param \Closure $code A \Closure
*
* @return Command The current instance
*
* @see execute()
*
* @api
*/
public function setCode(\Closure $code)
{
$this->code = $code;
return $this;
}
/**
* Merges the application definition with the command definition.
*/
private function mergeApplicationDefinition()
{
if (null === $this->application || true === $this->applicationDefinitionMerged) {
return;
}
$this->definition->setArguments(array_merge(
$this->application->getDefinition()->getArguments(),
$this->definition->getArguments()
));
$this->definition->addOptions($this->application->getDefinition()->getOptions());
$this->applicationDefinitionMerged = true;
}
/**
* Sets an array of argument and option instances.
*
* @param array|InputDefinition $definition An array of argument and option instances or a definition instance
*
* @return Command The current instance
*
* @api
*/
public function setDefinition($definition)
{
if ($definition instanceof InputDefinition) {
$this->definition = $definition;
} else {
$this->definition->setDefinition($definition);
}
$this->applicationDefinitionMerged = false;
return $this;
}
/**
* Gets the InputDefinition attached to this Command.
*
* @return InputDefinition An InputDefinition instance
*
* @api
*/
public function getDefinition()
{
return $this->definition;
}
/**
* Gets the InputDefinition to be used to create XML and Text representations of this Command.
*
* Can be overridden to provide the original command representation when it would otherwise
* be changed by merging with the application InputDefinition.
*
* @return InputDefinition An InputDefinition instance
*/
protected function getNativeDefinition()
{
return $this->getDefinition();
}
/**
* Adds an argument.
*
* @param string $name The argument name
* @param integer $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
* @param string $description A description text
* @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
*
* @return Command The current instance
*
* @api
*/
public function addArgument($name, $mode = null, $description = '', $default = null)
{
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
return $this;
}
/**
* Adds an option.
*
* @param string $name The option name
* @param string $shortcut The shortcut (can be null)
* @param integer $mode The option mode: One of the InputOption::VALUE_* constants
* @param string $description A description text
* @param mixed $default The default value (must be null for InputOption::VALUE_REQUIRED or InputOption::VALUE_NONE)
*
* @return Command The current instance
*
* @api
*/
public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
{
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
return $this;
}
/**
* Sets the name of the command.
*
* This method can set both the namespace and the name if
* you separate them by a colon (:)
*
* $command->setName('foo:bar');
*
* @param string $name The command name
*
* @return Command The current instance
*
* @throws \InvalidArgumentException When command name given is empty
*
* @api
*/
public function setName($name)
{
$this->validateName($name);
$this->name = $name;
return $this;
}
/**
* Returns the command name.
*
* @return string The command name
*
* @api
*/
public function getName()
{
return $this->name;
}
/**
* Sets the description for the command.
*
* @param string $description The description for the command
*
* @return Command The current instance
*
* @api
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Returns the description for the command.
*
* @return string The description for the command
*
* @api
*/
public function getDescription()
{
return $this->description;
}
/**
* Sets the help for the command.
*
* @param string $help The help for the command
*
* @return Command The current instance
*
* @api
*/
public function setHelp($help)
{
$this->help = $help;
return $this;
}
/**
* Returns the help for the command.
*
* @return string The help for the command
*
* @api
*/
public function getHelp()
{
return $this->help;
}
/**
* Returns the processed help for the command replacing the %command.name% and
* %command.full_name% patterns with the real values dynamically.
*
* @return string The processed help for the command
*/
public function getProcessedHelp()
{
$name = $this->name;
$placeholders = array(
'%command.name%',
'%command.full_name%'
);
$replacements = array(
$name,
$_SERVER['PHP_SELF'].' '.$name
);
return str_replace($placeholders, $replacements, $this->getHelp());
}
/**
* Sets the aliases for the command.
*
* @param array $aliases An array of aliases for the command
*
* @return Command The current instance
*
* @api
*/
public function setAliases($aliases)
{
foreach ($aliases as $alias) {
$this->validateName($alias);
}
$this->aliases = $aliases;
return $this;
}
/**
* Returns the aliases for the command.
*
* @return array An array of aliases for the command
*
* @api
*/
public function getAliases()
{
return $this->aliases;
}
/**
* Returns the synopsis for the command.
*
* @return string The synopsis
*/
public function getSynopsis()
{
if (null === $this->synopsis) {
$this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis()));
}
return $this->synopsis;
}
/**
* Gets a helper instance by name.
*
* @param string $name The helper name
*
* @return mixed The helper value
*
* @throws \InvalidArgumentException if the helper is not defined
*
* @api
*/
public function getHelper($name)
{
return $this->helperSet->get($name);
}
/**
* Returns a text representation of the command.
*
* @return string A string representing the command
*/
public function asText()
{
$messages = array(
'<comment>Usage:</comment>',
' '.$this->getSynopsis(),
'',
);
if ($this->getAliases()) {
$messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
}
$messages[] = $this->getNativeDefinition()->asText();
if ($help = $this->getProcessedHelp()) {
$messages[] = '<comment>Help:</comment>';
$messages[] = ' '.implode("\n ", explode("\n", $help))."\n";
}
return implode("\n", $messages);
}
/**
* Returns an XML representation of the command.
*
* @param Boolean $asDom Whether to return a DOM or an XML string
*
* @return string|DOMDocument An XML string representing the command
*/
public function asXml($asDom = false)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$dom->appendChild($commandXML = $dom->createElement('command'));
$commandXML->setAttribute('id', $this->name);
$commandXML->setAttribute('name', $this->name);
$commandXML->appendChild($usageXML = $dom->createElement('usage'));
$usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
$commandXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $this->getDescription()))));
$commandXML->appendChild($helpXML = $dom->createElement('help'));
$help = $this->help;
$helpXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $help))));
$commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
foreach ($this->getAliases() as $alias) {
$aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
$aliasXML->appendChild($dom->createTextNode($alias));
}
$definition = $this->getNativeDefinition()->asXml(true);
$commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true));
$commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true));
return $asDom ? $dom : $dom->saveXml();
}
private function validateName($name)
{
if (!preg_match('/^[^\:]+(\:[^\:]+)*$/', $name)) {
throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Command\Command;
/**
* HelpCommand displays the help for a given command.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HelpCommand extends Command
{
private $command;
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->ignoreValidationErrors();
$this
->setDefinition(array(
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
))
->setName('help')
->setDescription('Displays help for a command')
->setHelp(<<<EOF
The <info>help</info> command displays help for a given command:
<info>php app/console help list</info>
You can also output the help as XML by using the <comment>--xml</comment> option:
<info>php app/console help --xml list</info>
EOF
);
}
/**
* Sets the command
*
* @param Command $command The command to set
*/
public function setCommand(Command $command)
{
$this->command = $command;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
if (null === $this->command) {
$this->command = $this->getApplication()->get($input->getArgument('command_name'));
}
if ($input->getOption('xml')) {
$output->writeln($this->command->asXml(), OutputInterface::OUTPUT_RAW);
} else {
$output->writeln($this->command->asText());
}
$this->command = null;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputDefinition;
/**
* ListCommand displays the list of all available commands for the application.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ListCommand extends Command
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setDefinition($this->createDefinition())
->setName('list')
->setDescription('Lists commands')
->setHelp(<<<EOF
The <info>list</info> command lists all commands:
<info>php app/console list</info>
You can also display the commands for a specific namespace:
<info>php app/console list test</info>
You can also output the information as XML by using the <comment>--xml</comment> option:
<info>php app/console list --xml</info>
EOF
);
}
/**
* {@inheritdoc}
*/
protected function getNativeDefinition()
{
return $this->createDefinition();
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
if ($input->getOption('xml')) {
$output->writeln($this->getApplication()->asXml($input->getArgument('namespace')), OutputInterface::OUTPUT_RAW);
} else {
$output->writeln($this->getApplication()->asText($input->getArgument('namespace')));
}
}
private function createDefinition()
{
return new InputDefinition(array(
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Formatter;
/**
* Formatter class for console output.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*
* @api
*/
class OutputFormatter implements OutputFormatterInterface
{
/**
* The pattern to phrase the format.
*/
const FORMAT_PATTERN = '#<([a-z][a-z0-9_=;-]+)>(.*?)</\\1?>#is';
private $decorated;
private $styles = array();
/**
* Initializes console output formatter.
*
* @param Boolean $decorated Whether this formatter should actually decorate strings
* @param array $styles Array of "name => FormatterStyle" instances
*
* @api
*/
public function __construct($decorated = null, array $styles = array())
{
$this->decorated = (Boolean) $decorated;
$this->setStyle('error', new OutputFormatterStyle('white', 'red'));
$this->setStyle('info', new OutputFormatterStyle('green'));
$this->setStyle('comment', new OutputFormatterStyle('yellow'));
$this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
foreach ($styles as $name => $style) {
$this->setStyle($name, $style);
}
}
/**
* Sets the decorated flag.
*
* @param Boolean $decorated Whether to decorate the messages or not
*
* @api
*/
public function setDecorated($decorated)
{
$this->decorated = (Boolean) $decorated;
}
/**
* Gets the decorated flag.
*
* @return Boolean true if the output will decorate messages, false otherwise
*
* @api
*/
public function isDecorated()
{
return $this->decorated;
}
/**
* Sets a new style.
*
* @param string $name The style name
* @param OutputFormatterStyleInterface $style The style instance
*
* @api
*/
public function setStyle($name, OutputFormatterStyleInterface $style)
{
$this->styles[strtolower($name)] = $style;
}
/**
* Checks if output formatter has style with specified name.
*
* @param string $name
*
* @return Boolean
*
* @api
*/
public function hasStyle($name)
{
return isset($this->styles[strtolower($name)]);
}
/**
* Gets style options from style with specified name.
*
* @param string $name
*
* @return OutputFormatterStyleInterface
*
* @throws \InvalidArgumentException When style isn't defined
*
* @api
*/
public function getStyle($name)
{
if (!$this->hasStyle($name)) {
throw new \InvalidArgumentException('Undefined style: '.$name);
}
return $this->styles[strtolower($name)];
}
/**
* Formats a message according to the given styles.
*
* @param string $message The message to style
*
* @return string The styled message
*
* @api
*/
public function format($message)
{
return preg_replace_callback(self::FORMAT_PATTERN, array($this, 'replaceStyle'), $message);
}
/**
* Replaces style of the output.
*
* @param array $match
*
* @return string The replaced style
*/
private function replaceStyle($match)
{
if (!$this->isDecorated()) {
return $match[2];
}
if (isset($this->styles[strtolower($match[1])])) {
$style = $this->styles[strtolower($match[1])];
} else {
$style = $this->createStyleFromString($match[1]);
if (false === $style) {
return $match[0];
}
}
return $style->apply($this->format($match[2]));
}
/**
* Tries to create new style instance from string.
*
* @param string $string
*
* @return Symfony\Component\Console\Format\FormatterStyle|Boolean false if string is not format string
*/
private function createStyleFromString($string)
{
if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {
return false;
}
$style = new OutputFormatterStyle();
foreach ($matches as $match) {
array_shift($match);
if ('fg' == $match[0]) {
$style->setForeground($match[1]);
} elseif ('bg' == $match[0]) {
$style->setBackground($match[1]);
} else {
$style->setOption($match[1]);
}
}
return $style;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Formatter;
/**
* Formatter interface for console output.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*
* @api
*/
interface OutputFormatterInterface
{
/**
* Sets the decorated flag.
*
* @param Boolean $decorated Whether to decorate the messages or not
*
* @api
*/
function setDecorated($decorated);
/**
* Gets the decorated flag.
*
* @return Boolean true if the output will decorate messages, false otherwise
*
* @api
*/
function isDecorated();
/**
* Sets a new style.
*
* @param string $name The style name
* @param OutputFormatterStyleInterface $style The style instance
*
* @api
*/
function setStyle($name, OutputFormatterStyleInterface $style);
/**
* Checks if output formatter has style with specified name.
*
* @param string $name
*
* @return Boolean
*
* @api
*/
function hasStyle($name);
/**
* Gets style options from style with specified name.
*
* @param string $name
*
* @return OutputFormatterStyleInterface
*
* @api
*/
function getStyle($name);
/**
* Formats a message according to the given styles.
*
* @param string $message The message to style
*
* @return string The styled message
*
* @api
*/
function format($message);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Formatter;
/**
* Formatter style class for defining styles.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*
* @api
*/
class OutputFormatterStyle implements OutputFormatterStyleInterface
{
static private $availableForegroundColors = array(
'black' => 30,
'red' => 31,
'green' => 32,
'yellow' => 33,
'blue' => 34,
'magenta' => 35,
'cyan' => 36,
'white' => 37
);
static private $availableBackgroundColors = array(
'black' => 40,
'red' => 41,
'green' => 42,
'yellow' => 43,
'blue' => 44,
'magenta' => 45,
'cyan' => 46,
'white' => 47
);
static private $availableOptions = array(
'bold' => 1,
'underscore' => 4,
'blink' => 5,
'reverse' => 7,
'conceal' => 8
);
private $foreground;
private $background;
private $options = array();
/**
* Initializes output formatter style.
*
* @param string $foreground The style foreground color name
* @param string $background The style background color name
* @param array $options The style options
*
* @api
*/
public function __construct($foreground = null, $background = null, array $options = array())
{
if (null !== $foreground) {
$this->setForeground($foreground);
}
if (null !== $background) {
$this->setBackground($background);
}
if (count($options)) {
$this->setOptions($options);
}
}
/**
* Sets style foreground color.
*
* @param string $color The color name
*
* @throws \InvalidArgumentException When the color name isn't defined
*
* @api
*/
public function setForeground($color = null)
{
if (null === $color) {
$this->foreground = null;
return;
}
if (!isset(static::$availableForegroundColors[$color])) {
throw new \InvalidArgumentException(sprintf(
'Invalid foreground color specified: "%s". Expected one of (%s)',
$color,
implode(', ', array_keys(static::$availableForegroundColors))
));
}
$this->foreground = static::$availableForegroundColors[$color];
}
/**
* Sets style background color.
*
* @param string $color The color name
*
* @throws \InvalidArgumentException When the color name isn't defined
*
* @api
*/
public function setBackground($color = null)
{
if (null === $color) {
$this->background = null;
return;
}
if (!isset(static::$availableBackgroundColors[$color])) {
throw new \InvalidArgumentException(sprintf(
'Invalid background color specified: "%s". Expected one of (%s)',
$color,
implode(', ', array_keys(static::$availableBackgroundColors))
));
}
$this->background = static::$availableBackgroundColors[$color];
}
/**
* Sets some specific style option.
*
* @param string $option The option name
*
* @throws \InvalidArgumentException When the option name isn't defined
*
* @api
*/
public function setOption($option)
{
if (!isset(static::$availableOptions[$option])) {
throw new \InvalidArgumentException(sprintf(
'Invalid option specified: "%s". Expected one of (%s)',
$option,
implode(', ', array_keys(static::$availableOptions))
));
}
if (false === array_search(static::$availableOptions[$option], $this->options)) {
$this->options[] = static::$availableOptions[$option];
}
}
/**
* Unsets some specific style option.
*
* @param string $option The option name
*
* @throws \InvalidArgumentException When the option name isn't defined
*
*/
public function unsetOption($option)
{
if (!isset(static::$availableOptions[$option])) {
throw new \InvalidArgumentException(sprintf(
'Invalid option specified: "%s". Expected one of (%s)',
$option,
implode(', ', array_keys(static::$availableOptions))
));
}
$pos = array_search(static::$availableOptions[$option], $this->options);
if (false !== $pos) {
unset($this->options[$pos]);
}
}
/**
* Sets multiple style options at once.
*
* @param array $options
*/
public function setOptions(array $options)
{
$this->options = array();
foreach ($options as $option) {
$this->setOption($option);
}
}
/**
* Applies the style to a given text.
*
* @param string $text The text to style
*
* @return string
*/
public function apply($text)
{
$codes = array();
if (null !== $this->foreground) {
$codes[] = $this->foreground;
}
if (null !== $this->background) {
$codes[] = $this->background;
}
if (count($this->options)) {
$codes = array_merge($codes, $this->options);
}
return sprintf("\033[%sm%s\033[0m", implode(';', $codes), $text);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Formatter;
/**
* Formatter style interface for defining styles.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*
* @api
*/
interface OutputFormatterStyleInterface
{
/**
* Sets style foreground color.
*
* @param string $color The color name
*
* @api
*/
function setForeground($color = null);
/**
* Sets style background color.
*
* @param string $color The color name
*
* @api
*/
function setBackground($color = null);
/**
* Sets some specific style option.
*
* @param string $option The option name
*
* @api
*/
function setOption($option);
/**
* Unsets some specific style option.
*
* @param string $option Theoption name
*/
function unsetOption($option);
/**
* Sets multiple style options at once.
*
* @param array $options
*/
function setOptions(array $options);
/**
* Applies the style to a given text.
*
* @param string $text The text to style
*
* @return string
*/
function apply($text);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Output\OutputInterface;
/**
* The Dialog class provides helpers to interact with the user.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DialogHelper extends Helper
{
private $inputStream;
/**
* Asks a question to the user.
*
* @param OutputInterface $output An Output instance
* @param string|array $question The question to ask
* @param string $default The default answer if none is given by the user
*
* @return string The user answer
*
* @throws \RuntimeException If there is no data to read in the input stream
*/
public function ask(OutputInterface $output, $question, $default = null)
{
$output->write($question);
$ret = fgets($this->inputStream ?: STDIN, 4096);
if (false === $ret) {
throw new \RuntimeException('Aborted');
}
$ret = trim($ret);
return strlen($ret) > 0 ? $ret : $default;
}
/**
* Asks a confirmation to the user.
*
* The question will be asked until the user answers by nothing, yes, or no.
*
* @param OutputInterface $output An Output instance
* @param string|array $question The question to ask
* @param Boolean $default The default answer if the user enters nothing
*
* @return Boolean true if the user has confirmed, false otherwise
*/
public function askConfirmation(OutputInterface $output, $question, $default = true)
{
$answer = 'z';
while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) {
$answer = $this->ask($output, $question);
}
if (false === $default) {
return $answer && 'y' == strtolower($answer[0]);
}
return !$answer || 'y' == strtolower($answer[0]);
}
/**
* Asks for a value and validates the response.
*
* The validator receives the data to validate. It must return the
* validated data when the data is valid and throw an exception
* otherwise.
*
* @param OutputInterface $output An Output instance
* @param string|array $question The question to ask
* @param callback $validator A PHP callback
* @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
* @param string $default The default answer if none is given by the user
*
* @return mixed
*
* @throws \Exception When any of the validators return an error
*/
public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null)
{
$error = null;
while (false === $attempts || $attempts--) {
if (null !== $error) {
$output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
}
$value = $this->ask($output, $question, $default);
try {
return call_user_func($validator, $value);
} catch (\Exception $error) {
}
}
throw $error;
}
/**
* Sets the input stream to read from when interacting with the user.
*
* This is mainly useful for testing purpose.
*
* @param resource $stream The input stream
*/
public function setInputStream($stream)
{
$this->inputStream = $stream;
}
/**
* Returns the helper's canonical name.
*
* @return string The helper name
*/
public function getName()
{
return 'dialog';
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Helper;
/**
* The Formatter class provides helpers to format messages.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FormatterHelper extends Helper
{
/**
* Formats a message within a section.
*
* @param string $section The section name
* @param string $message The message
* @param string $style The style to apply to the section
*
* @return string The format section
*/
public function formatSection($section, $message, $style = 'info')
{
return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
}
/**
* Formats a message as a block of text.
*
* @param string|array $messages The message to write in the block
* @param string $style The style to apply to the whole block
* @param Boolean $large Whether to return a large block
*
* @return string The formatter message
*/
public function formatBlock($messages, $style, $large = false)
{
$messages = (array) $messages;
$len = 0;
$lines = array();
foreach ($messages as $message) {
$lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
$len = max($this->strlen($message) + ($large ? 4 : 2), $len);
}
$messages = $large ? array(str_repeat(' ', $len)) : array();
foreach ($lines as $line) {
$messages[] = $line.str_repeat(' ', $len - $this->strlen($line));
}
if ($large) {
$messages[] = str_repeat(' ', $len);
}
foreach ($messages as &$message) {
$message = sprintf('<%s>%s</%s>', $style, $message, $style);
}
return implode("\n", $messages);
}
/**
* Returns the length of a string, using mb_strlen if it is available.
*
* @param string $string The string to check its length
*
* @return integer The length of the string
*/
private function strlen($string)
{
if (!function_exists('mb_strlen')) {
return strlen($string);
}
if (false === $encoding = mb_detect_encoding($string)) {
return strlen($string);
}
return mb_strlen($string, $encoding);
}
/**
* Returns the helper's canonical name.
*
* @return string The canonical name of the helper
*/
public function getName()
{
return 'formatter';
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Helper;
/**
* Helper is the base class for all helper classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Helper implements HelperInterface
{
protected $helperSet = null;
/**
* Sets the helper set associated with this helper.
*
* @param HelperSet $helperSet A HelperSet instance
*/
public function setHelperSet(HelperSet $helperSet = null)
{
$this->helperSet = $helperSet;
}
/**
* Gets the helper set associated with this helper.
*
* @return HelperSet A HelperSet instance
*/
public function getHelperSet()
{
return $this->helperSet;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Helper;
/**
* HelperInterface is the interface all helpers must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface HelperInterface
{
/**
* Sets the helper set associated with this helper.
*
* @param HelperSet $helperSet A HelperSet instance
*
* @api
*/
function setHelperSet(HelperSet $helperSet = null);
/**
* Gets the helper set associated with this helper.
*
* @return HelperSet A HelperSet instance
*
* @api
*/
function getHelperSet();
/**
* Returns the canonical name of this helper.
*
* @return string The canonical name
*
* @api
*/
function getName();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Command\Command;
/**
* HelperSet represents a set of helpers to be used with a command.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HelperSet
{
private $helpers;
private $command;
/**
* Constructor.
*
* @param Helper[] $helpers An array of helper.
*/
public function __construct(array $helpers = array())
{
$this->helpers = array();
foreach ($helpers as $alias => $helper) {
$this->set($helper, is_int($alias) ? null : $alias);
}
}
/**
* Sets a helper.
*
* @param HelperInterface $helper The helper instance
* @param string $alias An alias
*/
public function set(HelperInterface $helper, $alias = null)
{
$this->helpers[$helper->getName()] = $helper;
if (null !== $alias) {
$this->helpers[$alias] = $helper;
}
$helper->setHelperSet($this);
}
/**
* Returns true if the helper if defined.
*
* @param string $name The helper name
*
* @return Boolean true if the helper is defined, false otherwise
*/
public function has($name)
{
return isset($this->helpers[$name]);
}
/**
* Gets a helper value.
*
* @param string $name The helper name
*
* @return HelperInterface The helper instance
*
* @throws \InvalidArgumentException if the helper is not defined
*/
public function get($name)
{
if (!$this->has($name)) {
throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
}
return $this->helpers[$name];
}
/**
* Sets the command associated with this helper set.
*
* @param Command $command A Command instance
*/
public function setCommand(Command $command = null)
{
$this->command = $command;
}
/**
* Gets the command associated with this helper set.
*
* @return Command A Command instance
*/
public function getCommand()
{
return $this->command;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Input;
/**
* ArgvInput represents an input coming from the CLI arguments.
*
* Usage:
*
* $input = new ArgvInput();
*
* By default, the `$_SERVER['argv']` array is used for the input values.
*
* This can be overridden by explicitly passing the input values in the constructor:
*
* $input = new ArgvInput($_SERVER['argv']);
*
* If you pass it yourself, don't forget that the first element of the array
* is the name of the running application.
*
* When passing an argument to the constructor, be sure that it respects
* the same rules as the argv one. It's almost always better to use the
* `StringInput` when you want to provide your own input.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
* @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
*
* @api
*/
class ArgvInput extends Input
{
private $tokens;
private $parsed;
/**
* Constructor.
*
* @param array $argv An array of parameters from the CLI (in the argv format)
* @param InputDefinition $definition A InputDefinition instance
*
* @api
*/
public function __construct(array $argv = null, InputDefinition $definition = null)
{
if (null === $argv) {
$argv = $_SERVER['argv'];
}
// strip the application name
array_shift($argv);
$this->tokens = $argv;
parent::__construct($definition);
}
protected function setTokens(array $tokens)
{
$this->tokens = $tokens;
}
/**
* Processes command line arguments.
*/
protected function parse()
{
$this->parsed = $this->tokens;
while (null !== $token = array_shift($this->parsed)) {
if (0 === strpos($token, '--')) {
$this->parseLongOption($token);
} elseif ('-' === $token[0]) {
$this->parseShortOption($token);
} else {
$this->parseArgument($token);
}
}
}
/**
* Parses a short option.
*
* @param string $token The current token.
*/
private function parseShortOption($token)
{
$name = substr($token, 1);
if (strlen($name) > 1) {
if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
// an option with a value (with no space)
$this->addShortOption($name[0], substr($name, 1));
} else {
$this->parseShortOptionSet($name);
}
} else {
$this->addShortOption($name, null);
}
}
/**
* Parses a short option set.
*
* @param string $name The current token
*
* @throws \RuntimeException When option given doesn't exist
*/
private function parseShortOptionSet($name)
{
$len = strlen($name);
for ($i = 0; $i < $len; $i++) {
if (!$this->definition->hasShortcut($name[$i])) {
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
}
$option = $this->definition->getOptionForShortcut($name[$i]);
if ($option->acceptValue()) {
$this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
break;
} else {
$this->addLongOption($option->getName(), true);
}
}
}
/**
* Parses a long option.
*
* @param string $token The current token
*/
private function parseLongOption($token)
{
$name = substr($token, 2);
if (false !== $pos = strpos($name, '=')) {
$this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
} else {
$this->addLongOption($name, null);
}
}
/**
* Parses an argument.
*
* @param string $token The current token
*
* @throws \RuntimeException When too many arguments are given
*/
private function parseArgument($token)
{
$c = count($this->arguments);
// if input is expecting another argument, add it
if ($this->definition->hasArgument($c)) {
$arg = $this->definition->getArgument($c);
$this->arguments[$arg->getName()] = $arg->isArray()? array($token) : $token;
// if last argument isArray(), append token to last argument
} elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
$arg = $this->definition->getArgument($c - 1);
$this->arguments[$arg->getName()][] = $token;
// unexpected argument
} else {
throw new \RuntimeException('Too many arguments.');
}
}
/**
* Adds a short option value.
*
* @param string $shortcut The short option key
* @param mixed $value The value for the option
*
* @throws \RuntimeException When option given doesn't exist
*/
private function addShortOption($shortcut, $value)
{
if (!$this->definition->hasShortcut($shortcut)) {
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
}
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
}
/**
* Adds a long option value.
*
* @param string $name The long option key
* @param mixed $value The value for the option
*
* @throws \RuntimeException When option given doesn't exist
*/
private function addLongOption($name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
}
$option = $this->definition->getOption($name);
if (null === $value && $option->acceptValue()) {
// if option accepts an optional or mandatory argument
// let's see if there is one provided
$next = array_shift($this->parsed);
if ('-' !== $next[0]) {
$value = $next;
} else {
array_unshift($this->parsed, $next);
}
}
if (null === $value) {
if ($option->isValueRequired()) {
throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
}
$value = $option->isValueOptional() ? $option->getDefault() : true;
}
if ($option->isArray()) {
$this->options[$name][] = $value;
} else {
$this->options[$name] = $value;
}
}
/**
* Returns the first argument from the raw parameters (not parsed).
*
* @return string The value of the first argument or null otherwise
*/
public function getFirstArgument()
{
foreach ($this->tokens as $token) {
if ($token && '-' === $token[0]) {
continue;
}
return $token;
}
}
/**
* Returns true if the raw parameters (not parsed) contain a value.
*
* This method is to be used to introspect the input parameters
* before they have been validated. It must be used carefully.
*
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
*
* @return Boolean true if the value is contained in the raw parameters
*/
public function hasParameterOption($values)
{
$values = (array) $values;
foreach ($this->tokens as $v) {
if (in_array($v, $values)) {
return true;
}
}
return false;
}
/**
* Returns the value of a raw option (not parsed).
*
* This method is to be used to introspect the input parameters
* before they have been validated. It must be used carefully.
*
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
* @param mixed $default The default value to return if no result is found
*
* @return mixed The option value
*/
public function getParameterOption($values, $default = false)
{
$values = (array) $values;
$tokens = $this->tokens;
while ($token = array_shift($tokens)) {
foreach ($values as $value) {
if (0 === strpos($token, $value)) {
if (false !== $pos = strpos($token, '=')) {
return substr($token, $pos + 1);
}
return array_shift($tokens);
}
}
}
return $default;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Input;
/**
* ArrayInput represents an input provided as an array.
*
* Usage:
*
* $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar'));
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ArrayInput extends Input
{
private $parameters;
/**
* Constructor.
*
* @param array $parameters An array of parameters
* @param InputDefinition $definition A InputDefinition instance
*
* @api
*/
public function __construct(array $parameters, InputDefinition $definition = null)
{
$this->parameters = $parameters;
parent::__construct($definition);
}
/**
* Returns the first argument from the raw parameters (not parsed).
*
* @return string The value of the first argument or null otherwise
*/
public function getFirstArgument()
{
foreach ($this->parameters as $key => $value) {
if ($key && '-' === $key[0]) {
continue;
}
return $value;
}
}
/**
* Returns true if the raw parameters (not parsed) contain a value.
*
* This method is to be used to introspect the input parameters
* before they have been validated. It must be used carefully.
*
* @param string|array $values The values to look for in the raw parameters (can be an array)
*
* @return Boolean true if the value is contained in the raw parameters
*/
public function hasParameterOption($values)
{
$values = (array) $values;
foreach ($this->parameters as $k => $v) {
if (!is_int($k)) {
$v = $k;
}
if (in_array($v, $values)) {
return true;
}
}
return false;
}
/**
* Returns the value of a raw option (not parsed).
*
* This method is to be used to introspect the input parameters
* before they have been validated. It must be used carefully.
*
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
* @param mixed $default The default value to return if no result is found
*
* @return mixed The option value
*/
public function getParameterOption($values, $default = false)
{
$values = (array) $values;
foreach ($this->parameters as $k => $v) {
if (is_int($k) && in_array($v, $values)) {
return true;
} elseif (in_array($k, $values)) {
return $v;
}
}
return $default;
}
/**
* Processes command line arguments.
*/
protected function parse()
{
foreach ($this->parameters as $key => $value) {
if (0 === strpos($key, '--')) {
$this->addLongOption(substr($key, 2), $value);
} elseif ('-' === $key[0]) {
$this->addShortOption(substr($key, 1), $value);
} else {
$this->addArgument($key, $value);
}
}
}
/**
* Adds a short option value.
*
* @param string $shortcut The short option key
* @param mixed $value The value for the option
*
* @throws \InvalidArgumentException When option given doesn't exist
*/
private function addShortOption($shortcut, $value)
{
if (!$this->definition->hasShortcut($shortcut)) {
throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
}
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
}
/**
* Adds a long option value.
*
* @param string $name The long option key
* @param mixed $value The value for the option
*
* @throws \InvalidArgumentException When option given doesn't exist
* @throws \InvalidArgumentException When a required value is missing
*/
private function addLongOption($name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
}
$option = $this->definition->getOption($name);
if (null === $value) {
if ($option->isValueRequired()) {
throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name));
}
$value = $option->isValueOptional() ? $option->getDefault() : true;
}
$this->options[$name] = $value;
}
/**
* Adds an argument value.
*
* @param string $name The argument name
* @param mixed $value The value for the argument
*
* @throws \InvalidArgumentException When argument given doesn't exist
*/
private function addArgument($name, $value)
{
if (!$this->definition->hasArgument($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
$this->arguments[$name] = $value;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Input;
/**
* Input is the base class for all concrete Input classes.
*
* Three concrete classes are provided by default:
*
* * `ArgvInput`: The input comes from the CLI arguments (argv)
* * `StringInput`: The input is provided as a string
* * `ArrayInput`: The input is provided as an array
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Input implements InputInterface
{
protected $definition;
protected $options;
protected $arguments;
protected $interactive = true;
/**
* Constructor.
*
* @param InputDefinition $definition A InputDefinition instance
*/
public function __construct(InputDefinition $definition = null)
{
if (null === $definition) {
$this->definition = new InputDefinition();
} else {
$this->bind($definition);
$this->validate();
}
}
/**
* Binds the current Input instance with the given arguments and options.
*
* @param InputDefinition $definition A InputDefinition instance
*/
public function bind(InputDefinition $definition)
{
$this->arguments = array();
$this->options = array();
$this->definition = $definition;
$this->parse();
}
/**
* Processes command line arguments.
*/
abstract protected function parse();
/**
* Validates the input.
*
* @throws \RuntimeException When not enough arguments are given
*/
public function validate()
{
if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) {
throw new \RuntimeException('Not enough arguments.');
}
}
/**
* Checks if the input is interactive.
*
* @return Boolean Returns true if the input is interactive
*/
public function isInteractive()
{
return $this->interactive;
}
/**
* Sets the input interactivity.
*
* @param Boolean $interactive If the input should be interactive
*/
public function setInteractive($interactive)
{
$this->interactive = (Boolean) $interactive;
}
/**
* Returns the argument values.
*
* @return array An array of argument values
*/
public function getArguments()
{
return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
}
/**
* Returns the argument value for a given argument name.
*
* @param string $name The argument name
*
* @return mixed The argument value
*
* @throws \InvalidArgumentException When argument given doesn't exist
*/
public function getArgument($name)
{
if (!$this->definition->hasArgument($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
}
/**
* Sets an argument value by name.
*
* @param string $name The argument name
* @param string $value The argument value
*
* @throws \InvalidArgumentException When argument given doesn't exist
*/
public function setArgument($name, $value)
{
if (!$this->definition->hasArgument($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
$this->arguments[$name] = $value;
}
/**
* Returns true if an InputArgument object exists by name or position.
*
* @param string|integer $name The InputArgument name or position
*
* @return Boolean true if the InputArgument object exists, false otherwise
*/
public function hasArgument($name)
{
return $this->definition->hasArgument($name);
}
/**
* Returns the options values.
*
* @return array An array of option values
*/
public function getOptions()
{
return array_merge($this->definition->getOptionDefaults(), $this->options);
}
/**
* Returns the option value for a given option name.
*
* @param string $name The option name
*
* @return mixed The option value
*
* @throws \InvalidArgumentException When option given doesn't exist
*/
public function getOption($name)
{
if (!$this->definition->hasOption($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
}
return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
}
/**
* Sets an option value by name.
*
* @param string $name The option name
* @param string $value The option value
*
* @throws \InvalidArgumentException When option given doesn't exist
*/
public function setOption($name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
}
$this->options[$name] = $value;
}
/**
* Returns true if an InputOption object exists by name.
*
* @param string $name The InputOption name
*
* @return Boolean true if the InputOption object exists, false otherwise
*/
public function hasOption($name)
{
return $this->definition->hasOption($name);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Input;
/**
* Represents a command line argument.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class InputArgument
{
const REQUIRED = 1;
const OPTIONAL = 2;
const IS_ARRAY = 4;
private $name;
private $mode;
private $default;
private $description;
/**
* Constructor.
*
* @param string $name The argument name
* @param integer $mode The argument mode: self::REQUIRED or self::OPTIONAL
* @param string $description A description text
* @param mixed $default The default value (for self::OPTIONAL mode only)
*
* @throws \InvalidArgumentException When argument mode is not valid
*
* @api
*/
public function __construct($name, $mode = null, $description = '', $default = null)
{
if (null === $mode) {
$mode = self::OPTIONAL;
} elseif (is_string($mode) || $mode > 7) {
throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
}
$this->name = $name;
$this->mode = $mode;
$this->description = $description;
$this->setDefault($default);
}
/**
* Returns the argument name.
*
* @return string The argument name
*/
public function getName()
{
return $this->name;
}
/**
* Returns true if the argument is required.
*
* @return Boolean true if parameter mode is self::REQUIRED, false otherwise
*/
public function isRequired()
{
return self::REQUIRED === (self::REQUIRED & $this->mode);
}
/**
* Returns true if the argument can take multiple values.
*
* @return Boolean true if mode is self::IS_ARRAY, false otherwise
*/
public function isArray()
{
return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
}
/**
* Sets the default value.
*
* @param mixed $default The default value
*
* @throws \LogicException When incorrect default value is given
*/
public function setDefault($default = null)
{
if (self::REQUIRED === $this->mode && null !== $default) {
throw new \LogicException('Cannot set a default value except for Parameter::OPTIONAL mode.');
}
if ($this->isArray()) {
if (null === $default) {
$default = array();
} elseif (!is_array($default)) {
throw new \LogicException('A default value for an array argument must be an array.');
}
}
$this->default = $default;
}
/**
* Returns the default value.
*
* @return mixed The default value
*/
public function getDefault()
{
return $this->default;
}
/**
* Returns the description text.
*
* @return string The description text
*/
public function getDescription()
{
return $this->description;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Input;
/**
* A InputDefinition represents a set of valid command line arguments and options.
*
* Usage:
*
* $definition = new InputDefinition(array(
* new InputArgument('name', InputArgument::REQUIRED),
* new InputOption('foo', 'f', InputOption::VALUE_REQUIRED),
* ));
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class InputDefinition
{
private $arguments;
private $requiredCount;
private $hasAnArrayArgument = false;
private $hasOptional;
private $options;
private $shortcuts;
/**
* Constructor.
*
* @param array $definition An array of InputArgument and InputOption instance
*
* @api
*/
public function __construct(array $definition = array())
{
$this->setDefinition($definition);
}
/**
* Sets the definition of the input.
*
* @param array $definition The definition array
*
* @api
*/
public function setDefinition(array $definition)
{
$arguments = array();
$options = array();
foreach ($definition as $item) {
if ($item instanceof InputOption) {
$options[] = $item;
} else {
$arguments[] = $item;
}
}
$this->setArguments($arguments);
$this->setOptions($options);
}
/**
* Sets the InputArgument objects.
*
* @param array $arguments An array of InputArgument objects
*
* @api
*/
public function setArguments($arguments = array())
{
$this->arguments = array();
$this->requiredCount = 0;
$this->hasOptional = false;
$this->hasAnArrayArgument = false;
$this->addArguments($arguments);
}
/**
* Adds an array of InputArgument objects.
*
* @param InputArgument[] $arguments An array of InputArgument objects
*
* @api
*/
public function addArguments($arguments = array())
{
if (null !== $arguments) {
foreach ($arguments as $argument) {
$this->addArgument($argument);
}
}
}
/**
* Adds an InputArgument object.
*
* @param InputArgument $argument An InputArgument object
*
* @throws \LogicException When incorrect argument is given
*
* @api
*/
public function addArgument(InputArgument $argument)
{
if (isset($this->arguments[$argument->getName()])) {
throw new \LogicException(sprintf('An argument with name "%s" already exist.', $argument->getName()));
}
if ($this->hasAnArrayArgument) {
throw new \LogicException('Cannot add an argument after an array argument.');
}
if ($argument->isRequired() && $this->hasOptional) {
throw new \LogicException('Cannot add a required argument after an optional one.');
}
if ($argument->isArray()) {
$this->hasAnArrayArgument = true;
}
if ($argument->isRequired()) {
++$this->requiredCount;
} else {
$this->hasOptional = true;
}
$this->arguments[$argument->getName()] = $argument;
}
/**
* Returns an InputArgument by name or by position.
*
* @param string|integer $name The InputArgument name or position
*
* @return InputArgument An InputArgument object
*
* @throws \InvalidArgumentException When argument given doesn't exist
*
* @api
*/
public function getArgument($name)
{
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
if (!$this->hasArgument($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
return $arguments[$name];
}
/**
* Returns true if an InputArgument object exists by name or position.
*
* @param string|integer $name The InputArgument name or position
*
* @return Boolean true if the InputArgument object exists, false otherwise
*
* @api
*/
public function hasArgument($name)
{
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
return isset($arguments[$name]);
}
/**
* Gets the array of InputArgument objects.
*
* @return array An array of InputArgument objects
*
* @api
*/
public function getArguments()
{
return $this->arguments;
}
/**
* Returns the number of InputArguments.
*
* @return integer The number of InputArguments
*/
public function getArgumentCount()
{
return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
}
/**
* Returns the number of required InputArguments.
*
* @return integer The number of required InputArguments
*/
public function getArgumentRequiredCount()
{
return $this->requiredCount;
}
/**
* Gets the default values.
*
* @return array An array of default values
*/
public function getArgumentDefaults()
{
$values = array();
foreach ($this->arguments as $argument) {
$values[$argument->getName()] = $argument->getDefault();
}
return $values;
}
/**
* Sets the InputOption objects.
*
* @param array $options An array of InputOption objects
*
* @api
*/
public function setOptions($options = array())
{
$this->options = array();
$this->shortcuts = array();
$this->addOptions($options);
}
/**
* Adds an array of InputOption objects.
*
* @param InputOption[] $options An array of InputOption objects
*
* @api
*/
public function addOptions($options = array())
{
foreach ($options as $option) {
$this->addOption($option);
}
}
/**
* Adds an InputOption object.
*
* @param InputOption $option An InputOption object
*
* @throws \LogicException When option given already exist
*
* @api
*/
public function addOption(InputOption $option)
{
if (isset($this->options[$option->getName()])) {
throw new \LogicException(sprintf('An option named "%s" already exist.', $option->getName()));
} elseif (isset($this->shortcuts[$option->getShortcut()])) {
throw new \LogicException(sprintf('An option with shortcut "%s" already exist.', $option->getShortcut()));
}
$this->options[$option->getName()] = $option;
if ($option->getShortcut()) {
$this->shortcuts[$option->getShortcut()] = $option->getName();
}
}
/**
* Returns an InputOption by name.
*
* @param string $name The InputOption name
*
* @return InputOption A InputOption object
*
* @api
*/
public function getOption($name)
{
if (!$this->hasOption($name)) {
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
}
return $this->options[$name];
}
/**
* Returns true if an InputOption object exists by name.
*
* @param string $name The InputOption name
*
* @return Boolean true if the InputOption object exists, false otherwise
*
* @api
*/
public function hasOption($name)
{
return isset($this->options[$name]);
}
/**
* Gets the array of InputOption objects.
*
* @return array An array of InputOption objects
*
* @api
*/
public function getOptions()
{
return $this->options;
}
/**
* Returns true if an InputOption object exists by shortcut.
*
* @param string $name The InputOption shortcut
*
* @return Boolean true if the InputOption object exists, false otherwise
*/
public function hasShortcut($name)
{
return isset($this->shortcuts[$name]);
}
/**
* Gets an InputOption by shortcut.
*
* @param string $shortcut the Shortcut name
*
* @return InputOption An InputOption object
*/
public function getOptionForShortcut($shortcut)
{
return $this->getOption($this->shortcutToName($shortcut));
}
/**
* Gets an array of default values.
*
* @return array An array of all default values
*/
public function getOptionDefaults()
{
$values = array();
foreach ($this->options as $option) {
$values[$option->getName()] = $option->getDefault();
}
return $values;
}
/**
* Returns the InputOption name given a shortcut.
*
* @param string $shortcut The shortcut
*
* @return string The InputOption name
*
* @throws \InvalidArgumentException When option given does not exist
*/
private function shortcutToName($shortcut)
{
if (!isset($this->shortcuts[$shortcut])) {
throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
}
return $this->shortcuts[$shortcut];
}
/**
* Gets the synopsis.
*
* @return string The synopsis
*/
public function getSynopsis()
{
$elements = array();
foreach ($this->getOptions() as $option) {
$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
$elements[] = sprintf('['.($option->isValueRequired() ? '%s--%s="..."' : ($option->isValueOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName());
}
foreach ($this->getArguments() as $argument) {
$elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
if ($argument->isArray()) {
$elements[] = sprintf('... [%sN]', $argument->getName());
}
}
return implode(' ', $elements);
}
/**
* Returns a textual representation of the InputDefinition.
*
* @return string A string representing the InputDefinition
*/
public function asText()
{
// find the largest option or argument name
$max = 0;
foreach ($this->getOptions() as $option) {
$nameLength = strlen($option->getName()) + 2;
if ($option->getShortcut()) {
$nameLength += strlen($option->getShortcut()) + 3;
}
$max = max($max, $nameLength);
}
foreach ($this->getArguments() as $argument) {
$max = max($max, strlen($argument->getName()));
}
++$max;
$text = array();
if ($this->getArguments()) {
$text[] = '<comment>Arguments:</comment>';
foreach ($this->getArguments() as $argument) {
if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
$default = sprintf('<comment> (default: %s)</comment>', is_bool($argument->getDefault()) || is_array($argument->getDefault()) ? str_replace("\n", '', var_export($argument->getDefault(), true)): $argument->getDefault());
} else {
$default = '';
}
$description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $argument->getDescription());
$text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $description, $default);
}
$text[] = '';
}
if ($this->getOptions()) {
$text[] = '<comment>Options:</comment>';
foreach ($this->getOptions() as $option) {
if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) {
$default = sprintf('<comment> (default: %s)</comment>', is_bool($option->getDefault()) || is_array($option->getDefault()) ? str_replace("\n", '', var_export($option->getDefault(), true)): $option->getDefault());
} else {
$default = '';
}
$multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
$description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $option->getDescription());
$optionMax = $max - strlen($option->getName()) - 2;
$text[] = sprintf(" <info>%s</info> %-${optionMax}s%s%s%s",
'--'.$option->getName(),
$option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '',
$description,
$default,
$multiple
);
}
$text[] = '';
}
return implode("\n", $text);
}
/**
* Returns an XML representation of the InputDefinition.
*
* @param Boolean $asDom Whether to return a DOM or an XML string
*
* @return string|DOMDocument An XML string representing the InputDefinition
*/
public function asXml($asDom = false)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$dom->appendChild($definitionXML = $dom->createElement('definition'));
$definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
foreach ($this->getArguments() as $argument) {
$argumentsXML->appendChild($argumentXML = $dom->createElement('argument'));
$argumentXML->setAttribute('name', $argument->getName());
$argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
$argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
$argumentXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
$argumentXML->appendChild($defaultsXML = $dom->createElement('defaults'));
$defaults = is_array($argument->getDefault()) ? $argument->getDefault() : (is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array()));
foreach ($defaults as $default) {
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
$defaultXML->appendChild($dom->createTextNode($default));
}
}
$definitionXML->appendChild($optionsXML = $dom->createElement('options'));
foreach ($this->getOptions() as $option) {
$optionsXML->appendChild($optionXML = $dom->createElement('option'));
$optionXML->setAttribute('name', '--'.$option->getName());
$optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
$optionXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
$optionXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
$optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
$optionXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
if ($option->acceptValue()) {
$optionXML->appendChild($defaultsXML = $dom->createElement('defaults'));
$defaults = is_array($option->getDefault()) ? $option->getDefault() : (is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array()));
foreach ($defaults as $default) {
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
$defaultXML->appendChild($dom->createTextNode($default));
}
}
}
return $asDom ? $dom : $dom->saveXml();
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Input;
/**
* InputInterface is the interface implemented by all input classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface InputInterface
{
/**
* Returns the first argument from the raw parameters (not parsed).
*
* @return string The value of the first argument or null otherwise
*/
function getFirstArgument();
/**
* Returns true if the raw parameters (not parsed) contain a value.
*
* This method is to be used to introspect the input parameters
* before they have been validated. It must be used carefully.
*
* @param string|array $values The values to look for in the raw parameters (can be an array)
*
* @return Boolean true if the value is contained in the raw parameters
*/
function hasParameterOption($values);
/**
* Returns the value of a raw option (not parsed).
*
* This method is to be used to introspect the input parameters
* before they have been validated. It must be used carefully.
*
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
* @param mixed $default The default value to return if no result is found
*
* @return mixed The option value
*/
function getParameterOption($values, $default = false);
/**
* Binds the current Input instance with the given arguments and options.
*
* @param InputDefinition $definition A InputDefinition instance
*/
function bind(InputDefinition $definition);
/**
* Validates if arguments given are correct.
*
* Throws an exception when not enough arguments are given.
*
* @throws \RuntimeException
*/
function validate();
/**
* Returns all the given arguments merged with the default values.
*
* @return array
*/
function getArguments();
/**
* Gets argument by name.
*
* @param string $name The name of the argument
*
* @return mixed
*/
function getArgument($name);
/**
* Returns all the given options merged with the default values.
*
* @return array
*/
function getOptions();
/**
* Gets an option by name.
*
* @param string $name The name of the option
*
* @return mixed
*/
function getOption($name);
/**
* Is this input means interactive?
*
* @return Boolean
*/
function isInteractive();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Input;
/**
* Represents a command line option.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class InputOption
{
const VALUE_NONE = 1;
const VALUE_REQUIRED = 2;
const VALUE_OPTIONAL = 4;
const VALUE_IS_ARRAY = 8;
private $name;
private $shortcut;
private $mode;
private $default;
private $description;
/**
* Constructor.
*
* @param string $name The option name
* @param string $shortcut The shortcut (can be null)
* @param integer $mode The option mode: One of the VALUE_* constants
* @param string $description A description text
* @param mixed $default The default value (must be null for self::VALUE_REQUIRED or self::VALUE_NONE)
*
* @throws \InvalidArgumentException If option mode is invalid or incompatible
*
* @api
*/
public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
{
if (0 === strpos($name, '--')) {
$name = substr($name, 2);
}
if (empty($shortcut)) {
$shortcut = null;
}
if (null !== $shortcut) {
if ('-' === $shortcut[0]) {
$shortcut = substr($shortcut, 1);
}
}
if (null === $mode) {
$mode = self::VALUE_NONE;
} elseif (!is_int($mode) || $mode > 15) {
throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
}
$this->name = $name;
$this->shortcut = $shortcut;
$this->mode = $mode;
$this->description = $description;
if ($this->isArray() && !$this->acceptValue()) {
throw new \InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
}
$this->setDefault($default);
}
/**
* Returns the option shortcut.
*
* @return string The shortcut
*/
public function getShortcut()
{
return $this->shortcut;
}
/**
* Returns the option name.
*
* @return string The name
*/
public function getName()
{
return $this->name;
}
/**
* Returns true if the option accepts a value.
*
* @return Boolean true if value mode is not self::VALUE_NONE, false otherwise
*/
public function acceptValue()
{
return $this->isValueRequired() || $this->isValueOptional();
}
/**
* Returns true if the option requires a value.
*
* @return Boolean true if value mode is self::VALUE_REQUIRED, false otherwise
*/
public function isValueRequired()
{
return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
}
/**
* Returns true if the option takes an optional value.
*
* @return Boolean true if value mode is self::VALUE_OPTIONAL, false otherwise
*/
public function isValueOptional()
{
return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
}
/**
* Returns true if the option can take multiple values.
*
* @return Boolean true if mode is self::VALUE_IS_ARRAY, false otherwise
*/
public function isArray()
{
return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
}
/**
* Sets the default value.
*
* @param mixed $default The default value
*
* @throws \LogicException When incorrect default value is given
*/
public function setDefault($default = null)
{
if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
throw new \LogicException('Cannot set a default value when using Option::VALUE_NONE mode.');
}
if ($this->isArray()) {
if (null === $default) {
$default = array();
} elseif (!is_array($default)) {
throw new \LogicException('A default value for an array option must be an array.');
}
}
$this->default = $this->acceptValue() ? $default : false;
}
/**
* Returns the default value.
*
* @return mixed The default value
*/
public function getDefault()
{
return $this->default;
}
/**
* Returns the description text.
*
* @return string The description text
*/
public function getDescription()
{
return $this->description;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Input;
/**
* StringInput represents an input provided as a string.
*
* Usage:
*
* $input = new StringInput('foo --bar="foobar"');
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class StringInput extends ArgvInput
{
const REGEX_STRING = '([^ ]+?)(?: |(?<!\\\\)"|(?<!\\\\)\'|$)';
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
/**
* Constructor.
*
* @param string $input An array of parameters from the CLI (in the argv format)
* @param InputDefinition $definition A InputDefinition instance
*
* @api
*/
public function __construct($input, InputDefinition $definition = null)
{
parent::__construct(array(), $definition);
$this->setTokens($this->tokenize($input));
}
/**
* Tokenizes a string.
*
* @param string $input The input to tokenize
*
* @return array An array of tokens
*
* @throws \InvalidArgumentException When unable to parse input (should never happen)
*/
private function tokenize($input)
{
$input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input);
$tokens = array();
$length = strlen($input);
$cursor = 0;
while ($cursor < $length) {
if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
} elseif (preg_match('/([^="\' ]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
$tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2)));
} elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
$tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
} elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
$tokens[] = stripcslashes($match[1]);
} else {
// should never happen
// @codeCoverageIgnoreStart
throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
// @codeCoverageIgnoreEnd
}
$cursor += strlen($match[0]);
}
return $tokens;
}
}
Copyright (c) 2004-2012 Fabien Potencier
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.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Output;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
* ConsoleOutput is the default class for all CLI output. It uses STDOUT.
*
* This class is a convenient wrapper around `StreamOutput`.
*
* $output = new ConsoleOutput();
*
* This is equivalent to:
*
* $output = new StreamOutput(fopen('php://stdout', 'w'));
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ConsoleOutput extends StreamOutput
{
/**
* Constructor.
*
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL,
* self::VERBOSITY_VERBOSE)
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
* @param OutputFormatter $formatter Output formatter instance
*
* @api
*/
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
{
$outputStream = 'php://stdout';
if (!$this->hasStdoutSupport()) {
$outputStream = 'php://output';
}
parent::__construct(fopen($outputStream, 'w'), $verbosity, $decorated, $formatter);
}
/**
* Returns true if current environment supports writing console output to
* STDOUT.
*
* IBM iSeries (OS400) exhibits character-encoding issues when writing to
* STDOUT and doesn't properly convert ASCII to EBCDIC, resulting in garbage
* output.
*
* @return boolean
*/
protected function hasStdoutSupport()
{
return ('OS400' != php_uname('s'));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Output;
/**
* NullOutput suppresses all output.
*
* $output = new NullOutput();
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class NullOutput extends Output
{
/**
* Writes a message to the output.
*
* @param string $message A message to write to the output
* @param Boolean $newline Whether to add a newline or not
*/
public function doWrite($message, $newline)
{
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Output;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Formatter\OutputFormatter;
/**
* Base class for output classes.
*
* There are three levels of verbosity:
*
* * normal: no option passed (normal output - information)
* * verbose: -v (more output - debug)
* * quiet: -q (no output)
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
abstract class Output implements OutputInterface
{
private $verbosity;
private $formatter;
/**
* Constructor.
*
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
* @param OutputFormatterInterface $formatter Output formatter instance
*
* @api
*/
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
{
if (null === $formatter) {
$formatter = new OutputFormatter();
}
$this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
$this->formatter = $formatter;
$this->formatter->setDecorated((Boolean) $decorated);
}
/**
* Sets output formatter.
*
* @param OutputFormatterInterface $formatter
*
* @api
*/
public function setFormatter(OutputFormatterInterface $formatter)
{
$this->formatter = $formatter;
}
/**
* Returns current output formatter instance.
*
* @return OutputFormatterInterface
*
* @api
*/
public function getFormatter()
{
return $this->formatter;
}
/**
* Sets the decorated flag.
*
* @param Boolean $decorated Whether to decorate the messages or not
*
* @api
*/
public function setDecorated($decorated)
{
$this->formatter->setDecorated((Boolean) $decorated);
}
/**
* Gets the decorated flag.
*
* @return Boolean true if the output will decorate messages, false otherwise
*
* @api
*/
public function isDecorated()
{
return $this->formatter->isDecorated();
}
/**
* Sets the verbosity of the output.
*
* @param integer $level The level of verbosity
*
* @api
*/
public function setVerbosity($level)
{
$this->verbosity = (int) $level;
}
/**
* Gets the current verbosity of the output.
*
* @return integer The current level of verbosity
*
* @api
*/
public function getVerbosity()
{
return $this->verbosity;
}
/**
* Writes a message to the output and adds a newline at the end.
*
* @param string|array $messages The message as an array of lines of a single string
* @param integer $type The type of output
*
* @api
*/
public function writeln($messages, $type = 0)
{
$this->write($messages, true, $type);
}
/**
* Writes a message to the output.
*
* @param string|array $messages The message as an array of lines of a single string
* @param Boolean $newline Whether to add a newline or not
* @param integer $type The type of output
*
* @throws \InvalidArgumentException When unknown output type is given
*
* @api
*/
public function write($messages, $newline = false, $type = 0)
{
if (self::VERBOSITY_QUIET === $this->verbosity) {
return;
}
$messages = (array) $messages;
foreach ($messages as $message) {
switch ($type) {
case OutputInterface::OUTPUT_NORMAL:
$message = $this->formatter->format($message);
break;
case OutputInterface::OUTPUT_RAW:
break;
case OutputInterface::OUTPUT_PLAIN:
$message = strip_tags($this->formatter->format($message));
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
}
$this->doWrite($message, $newline);
}
}
/**
* Writes a message to the output.
*
* @param string $message A message to write to the output
* @param Boolean $newline Whether to add a newline or not
*/
abstract public function doWrite($message, $newline);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Output;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
* OutputInterface is the interface implemented by all Output classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface OutputInterface
{
const VERBOSITY_QUIET = 0;
const VERBOSITY_NORMAL = 1;
const VERBOSITY_VERBOSE = 2;
const OUTPUT_NORMAL = 0;
const OUTPUT_RAW = 1;
const OUTPUT_PLAIN = 2;
/**
* Writes a message to the output.
*
* @param string|array $messages The message as an array of lines of a single string
* @param Boolean $newline Whether to add a newline or not
* @param integer $type The type of output
*
* @throws \InvalidArgumentException When unknown output type is given
*
* @api
*/
function write($messages, $newline = false, $type = 0);
/**
* Writes a message to the output and adds a newline at the end.
*
* @param string|array $messages The message as an array of lines of a single string
* @param integer $type The type of output
*
* @api
*/
function writeln($messages, $type = 0);
/**
* Sets the verbosity of the output.
*
* @param integer $level The level of verbosity
*
* @api
*/
function setVerbosity($level);
/**
* Gets the current verbosity of the output.
*
* @return integer The current level of verbosity
*
* @api
*/
function getVerbosity();
/**
* Sets the decorated flag.
*
* @param Boolean $decorated Whether to decorate the messages or not
*
* @api
*/
function setDecorated($decorated);
/**
* Gets the decorated flag.
*
* @return Boolean true if the output will decorate messages, false otherwise
*
* @api
*/
function isDecorated();
/**
* Sets output formatter.
*
* @param OutputFormatterInterface $formatter
*
* @api
*/
function setFormatter(OutputFormatterInterface $formatter);
/**
* Returns current output formatter instance.
*
* @return OutputFormatterInterface
*
* @api
*/
function getFormatter();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Output;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
* StreamOutput writes the output to a given stream.
*
* Usage:
*
* $output = new StreamOutput(fopen('php://stdout', 'w'));
*
* As `StreamOutput` can use any stream, you can also use a file:
*
* $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class StreamOutput extends Output
{
private $stream;
/**
* Constructor.
*
* @param mixed $stream A stream resource
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL,
* self::VERBOSITY_VERBOSE)
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
* @param OutputFormatter $formatter Output formatter instance
*
* @throws \InvalidArgumentException When first argument is not a real stream
*
* @api
*/
public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
{
if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
}
$this->stream = $stream;
if (null === $decorated) {
$decorated = $this->hasColorSupport($decorated);
}
parent::__construct($verbosity, $decorated, $formatter);
}
/**
* Gets the stream attached to this StreamOutput instance.
*
* @return resource A stream resource
*/
public function getStream()
{
return $this->stream;
}
/**
* Writes a message to the output.
*
* @param string $message A message to write to the output
* @param Boolean $newline Whether to add a newline or not
*
* @throws \RuntimeException When unable to write output (should never happen)
*/
public function doWrite($message, $newline)
{
if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) {
// @codeCoverageIgnoreStart
// should never happen
throw new \RuntimeException('Unable to write output.');
// @codeCoverageIgnoreEnd
}
fflush($this->stream);
}
/**
* Returns true if the stream supports colorization.
*
* Colorization is disabled if not supported by the stream:
*
* - windows without ansicon
* - non tty consoles
*
* @return Boolean true if the stream supports colorization, false otherwise
*/
protected function hasColorSupport()
{
// @codeCoverageIgnoreStart
if (DIRECTORY_SEPARATOR == '\\') {
return false !== getenv('ANSICON');
}
return function_exists('posix_isatty') && @posix_isatty($this->stream);
// @codeCoverageIgnoreEnd
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\ConsoleOutput;
/**
* A Shell wraps an Application to add shell capabilities to it.
*
* This class only works with a PHP compiled with readline support
* (either --with-readline or --with-libedit)
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Shell
{
private $application;
private $history;
private $output;
/**
* Constructor.
*
* If there is no readline support for the current PHP executable
* a \RuntimeException exception is thrown.
*
* @param Application $application An application instance
*
* @throws \RuntimeException When Readline extension is not enabled
*/
public function __construct(Application $application)
{
if (!function_exists('readline')) {
throw new \RuntimeException('Unable to start the shell as the Readline extension is not enabled.');
}
$this->application = $application;
$this->history = getenv('HOME').'/.history_'.$application->getName();
$this->output = new ConsoleOutput();
}
/**
* Runs the shell.
*/
public function run()
{
$this->application->setAutoExit(false);
$this->application->setCatchExceptions(true);
readline_read_history($this->history);
readline_completion_function(array($this, 'autocompleter'));
$this->output->writeln($this->getHeader());
while (true) {
$command = readline($this->application->getName().' > ');
if (false === $command) {
$this->output->writeln("\n");
break;
}
readline_add_history($command);
readline_write_history($this->history);
if (0 !== $ret = $this->application->run(new StringInput($command), $this->output)) {
$this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
}
}
}
/**
* Tries to return autocompletion for the current entered text.
*
* @param string $text The last segment of the entered text
* @param integer $position The current position
*
* @return array An array of possibilities for the entered text
*/
private function autocompleter($text, $position)
{
$info = readline_info();
$text = substr($info['line_buffer'], 0, $info['end']);
if ($info['point'] !== $info['end']) {
return true;
}
// task name?
if (false === strpos($text, ' ') || !$text) {
return array_keys($this->application->all());
}
// options and arguments?
try {
$command = $this->application->find(substr($text, 0, strpos($text, ' ')));
} catch (\Exception $e) {
return true;
}
$list = array('--help');
foreach ($command->getDefinition()->getOptions() as $option) {
$list[] = '--'.$option->getName();
}
return $list;
}
/**
* Returns the shell header.
*
* @return string The header string
*/
protected function getHeader()
{
return <<<EOF
Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
At the prompt, type <comment>help</comment> for some help,
or <comment>list</comment> to get a list of available commands.
To exit the shell, type <comment>^D</comment>.
EOF;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Tester;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\StreamOutput;
/**
* Eases the testing of console applications.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ApplicationTester
{
private $application;
private $input;
private $output;
/**
* Constructor.
*
* @param Application $application An Application instance to test.
*/
public function __construct(Application $application)
{
$this->application = $application;
}
/**
* Executes the application.
*
* Available options:
*
* * interactive: Sets the input interactive flag
* * decorated: Sets the output decorated flag
* * verbosity: Sets the output verbosity flag
*
* @param array $input An array of arguments and options
* @param array $options An array of options
*
* @return integer The command exit code
*/
public function run(array $input, $options = array())
{
$this->input = new ArrayInput($input);
if (isset($options['interactive'])) {
$this->input->setInteractive($options['interactive']);
}
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
if (isset($options['decorated'])) {
$this->output->setDecorated($options['decorated']);
}
if (isset($options['verbosity'])) {
$this->output->setVerbosity($options['verbosity']);
}
return $this->application->run($this->input, $this->output);
}
/**
* Gets the display returned by the last execution of the application.
*
* @return string The display
*/
public function getDisplay()
{
rewind($this->output->getStream());
return stream_get_contents($this->output->getStream());
}
/**
* Gets the input instance used by the last execution of the application.
*
* @return InputInterface The current input instance
*/
public function getInput()
{
return $this->input;
}
/**
* Gets the output instance used by the last execution of the application.
*
* @return OutputInterface The current output instance
*/
public function getOutput()
{
return $this->output;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Tester;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\StreamOutput;
/**
* Eases the testing of console commands.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class CommandTester
{
private $command;
private $input;
private $output;
/**
* Constructor.
*
* @param Command $command A Command instance to test.
*/
public function __construct(Command $command)
{
$this->command = $command;
}
/**
* Executes the command.
*
* Available options:
*
* * interactive: Sets the input interactive flag
* * decorated: Sets the output decorated flag
* * verbosity: Sets the output verbosity flag
*
* @param array $input An array of arguments and options
* @param array $options An array of options
*
* @return integer The command exit code
*/
public function execute(array $input, array $options = array())
{
$this->input = new ArrayInput($input);
if (isset($options['interactive'])) {
$this->input->setInteractive($options['interactive']);
}
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
if (isset($options['decorated'])) {
$this->output->setDecorated($options['decorated']);
}
if (isset($options['verbosity'])) {
$this->output->setVerbosity($options['verbosity']);
}
return $this->command->run($this->input, $this->output);
}
/**
* Gets the display returned by the last execution of the command.
*
* @return string The display
*/
public function getDisplay()
{
rewind($this->output->getStream());
return stream_get_contents($this->output->getStream());
}
/**
* Gets the input instance used by the last execution of the command.
*
* @return InputInterface The current input instance
*/
public function getInput()
{
return $this->input;
}
/**
* Gets the output instance used by the last execution of the command.
*
* @return OutputInterface The current output instance
*/
public function getOutput()
{
return $this->output;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* @api
*/
class Alias
{
private $id;
private $public;
/**
* Constructor.
*
* @param string $id Alias identifier
* @param Boolean $public If this alias is public
*
* @api
*/
public function __construct($id, $public = true)
{
$this->id = strtolower($id);
$this->public = $public;
}
/**
* Checks if this DI Alias should be public or not.
*
* @return Boolean
*
* @api
*/
public function isPublic()
{
return $this->public;
}
/**
* Sets if this Alias is public.
*
* @param Boolean $boolean If this Alias should be public
*
* @api
*/
public function setPublic($boolean)
{
$this->public = (Boolean) $boolean;
}
/**
* Returns the Id of this alias.
*
* @return string The alias id
*
* @api
*/
public function __toString()
{
return $this->id;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Run this pass before passes that need to know more about the relation of
* your services.
*
* This class will populate the ServiceReferenceGraph with information. You can
* retrieve the graph in other passes from the compiler.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class AnalyzeServiceReferencesPass implements RepeatablePassInterface
{
private $graph;
private $container;
private $currentId;
private $currentDefinition;
private $repeatedPass;
private $onlyConstructorArguments;
/**
* Constructor.
*
* @param Boolean $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
*/
public function __construct($onlyConstructorArguments = false)
{
$this->onlyConstructorArguments = (Boolean) $onlyConstructorArguments;
}
/**
* {@inheritDoc}
*/
public function setRepeatedPass(RepeatedPass $repeatedPass)
{
$this->repeatedPass = $repeatedPass;
}
/**
* Processes a ContainerBuilder object to populate the service reference graph.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$this->container = $container;
$this->graph = $container->getCompiler()->getServiceReferenceGraph();
$this->graph->clear();
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition->isSynthetic() || $definition->isAbstract()) {
continue;
}
$this->currentId = $id;
$this->currentDefinition = $definition;
$this->processArguments($definition->getArguments());
if (!$this->onlyConstructorArguments) {
$this->processArguments($definition->getMethodCalls());
$this->processArguments($definition->getProperties());
if ($definition->getConfigurator()) {
$this->processArguments(array($definition->getConfigurator()));
}
}
}
foreach ($container->getAliases() as $id => $alias) {
$this->graph->connect($id, $alias, (string) $alias, $this->getDefinition((string) $alias), null);
}
}
/**
* Processes service definitions for arguments to find relationships for the service graph.
*
* @param array $arguments An array of Reference or Definition objects relating to service definitions
*/
private function processArguments(array $arguments)
{
foreach ($arguments as $argument) {
if (is_array($argument)) {
$this->processArguments($argument);
} elseif ($argument instanceof Reference) {
$this->graph->connect(
$this->currentId,
$this->currentDefinition,
$this->getDefinitionId((string) $argument),
$this->getDefinition((string) $argument),
$argument
);
} elseif ($argument instanceof Definition) {
$this->processArguments($argument->getArguments());
$this->processArguments($argument->getMethodCalls());
$this->processArguments($argument->getProperties());
}
}
}
/**
* Returns a service definition given the full name or an alias.
*
* @param string $id A full id or alias for a service definition.
*
* @return Definition The definition related to the supplied id
*/
private function getDefinition($id)
{
$id = $this->getDefinitionId($id);
return null === $id ? null : $this->container->getDefinition($id);
}
private function getDefinitionId($id)
{
while ($this->container->hasAlias($id)) {
$id = (string) $this->container->getAlias($id);
}
if (!$this->container->hasDefinition($id)) {
return null;
}
return $id;
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Checks your services for circular references
*
* References from method calls are ignored since we might be able to resolve
* these references depending on the order in which services are called.
*
* Circular reference from method calls will only be detected at run-time.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class CheckCircularReferencesPass implements CompilerPassInterface
{
private $currentId;
private $currentPath;
/**
* Checks the ContainerBuilder object for circular references.
*
* @param ContainerBuilder $container The ContainerBuilder instances
*/
public function process(ContainerBuilder $container)
{
$graph = $container->getCompiler()->getServiceReferenceGraph();
foreach ($graph->getNodes() as $id => $node) {
$this->currentId = $id;
$this->currentPath = array($id);
$this->checkOutEdges($node->getOutEdges());
}
}
/**
* Checks for circular references.
*
* @param array $edges An array of Nodes
*
* @throws \RuntimeException When a circular reference is found.
*/
private function checkOutEdges(array $edges)
{
foreach ($edges as $edge) {
$node = $edge->getDestNode();
$this->currentPath[] = $id = $node->getId();
if ($this->currentId === $id) {
throw new ServiceCircularReferenceException($this->currentId, $this->currentPath);
}
$this->checkOutEdges($node->getOutEdges());
array_pop($this->currentPath);
}
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* This pass validates each definition individually only taking the information
* into account which is contained in the definition itself.
*
* Later passes can rely on the following, and specifically do not need to
* perform these checks themselves:
*
* - non synthetic, non abstract services always have a class set
* - synthetic services are always public
* - synthetic services are always of non-prototype scope
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class CheckDefinitionValidityPass implements CompilerPassInterface
{
/**
* Processes the ContainerBuilder to validate the Definition.
*
* @param ContainerBuilder $container
*
* @throws \RuntimeException When the Definition is invalid
*/
public function process(ContainerBuilder $container)
{
foreach ($container->getDefinitions() as $id => $definition) {
// synthetic service is public
if ($definition->isSynthetic() && !$definition->isPublic()) {
throw new \RuntimeException(sprintf(
'A synthetic service ("%s") must be public.',
$id
));
}
// synthetic service has non-prototype scope
if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
throw new \RuntimeException(sprintf(
'A synthetic service ("%s") cannot be of scope "prototype".',
$id
));
}
// non-synthetic, non-abstract service has class
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) {
if ($definition->getFactoryClass() || $definition->getFactoryService()) {
throw new \RuntimeException(sprintf(
'Please add the class to service "%s" even if it is constructed by a factory '
.'since we might need to add method calls based on compile-time checks.',
$id
));
}
throw new \RuntimeException(sprintf(
'The definition for "%s" has no class. If you intend to inject '
.'this service dynamically at runtime, please mark it as synthetic=true. '
.'If this is an abstract definition solely used by child definitions, '
.'please add abstract=true, otherwise specify a class to get rid of this error.',
$id
));
}
}
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Checks that all references are pointing to a valid service.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class CheckExceptionOnInvalidReferenceBehaviorPass implements CompilerPassInterface
{
private $container;
private $sourceId;
public function process(ContainerBuilder $container)
{
$this->container = $container;
foreach ($container->getDefinitions() as $id => $definition) {
$this->sourceId = $id;
$this->processDefinition($definition);
}
}
private function processDefinition(Definition $definition)
{
$this->processReferences($definition->getArguments());
$this->processReferences($definition->getMethodCalls());
$this->processReferences($definition->getProperties());
}
private function processReferences(array $arguments)
{
foreach ($arguments as $argument) {
if (is_array($argument)) {
$this->processReferences($argument);
} elseif ($argument instanceof Definition) {
$this->processDefinition($argument);
} elseif ($argument instanceof Reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $argument->getInvalidBehavior()) {
$destId = (string) $argument;
if (!$this->container->has($destId)) {
throw new ServiceNotFoundException($destId, $this->sourceId);
}
}
}
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Exception\ScopeWideningInjectionException;
use Symfony\Component\DependencyInjection\Exception\ScopeCrossingInjectionException;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Checks the validity of references
*
* The following checks are performed by this pass:
* - target definitions are not abstract
* - target definitions are of equal or wider scope
* - target definitions are in the same scope hierarchy
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class CheckReferenceValidityPass implements CompilerPassInterface
{
private $container;
private $currentId;
private $currentDefinition;
private $currentScope;
private $currentScopeAncestors;
private $currentScopeChildren;
/**
* Processes the ContainerBuilder to validate References.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$this->container = $container;
$children = $this->container->getScopeChildren();
$ancestors = array();
$scopes = $this->container->getScopes();
foreach ($scopes as $name => $parent) {
$ancestors[$name] = array($parent);
while (isset($scopes[$parent])) {
$ancestors[$name][] = $parent = $scopes[$parent];
}
}
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition->isSynthetic() || $definition->isAbstract()) {
continue;
}
$this->currentId = $id;
$this->currentDefinition = $definition;
$this->currentScope = $scope = $definition->getScope();
if (ContainerInterface::SCOPE_CONTAINER === $scope) {
$this->currentScopeChildren = array_keys($scopes);
$this->currentScopeAncestors = array();
} elseif (ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
$this->currentScopeChildren = $children[$scope];
$this->currentScopeAncestors = $ancestors[$scope];
}
$this->validateReferences($definition->getArguments());
$this->validateReferences($definition->getMethodCalls());
$this->validateReferences($definition->getProperties());
}
}
/**
* Validates an array of References.
*
* @param array $arguments An array of Reference objects
*
* @throws \RuntimeException when there is a reference to an abstract definition.
*/
private function validateReferences(array $arguments)
{
foreach ($arguments as $argument) {
if (is_array($argument)) {
$this->validateReferences($argument);
} elseif ($argument instanceof Reference) {
$targetDefinition = $this->getDefinition((string) $argument);
if (null !== $targetDefinition && $targetDefinition->isAbstract()) {
throw new \RuntimeException(sprintf(
'The definition "%s" has a reference to an abstract definition "%s". '
.'Abstract definitions cannot be the target of references.',
$this->currentId,
$argument
));
}
$this->validateScope($argument, $targetDefinition);
}
}
}
/**
* Validates the scope of a single Reference.
*
* @param Reference $reference
* @param Definition $definition
*
* @throws \RuntimeException when there is an issue with the Reference scope
*/
private function validateScope(Reference $reference, Definition $definition = null)
{
if (ContainerInterface::SCOPE_PROTOTYPE === $this->currentScope) {
return;
}
if (!$reference->isStrict()) {
return;
}
if (null === $definition) {
return;
}
if ($this->currentScope === $scope = $definition->getScope()) {
return;
}
$id = (string) $reference;
if (in_array($scope, $this->currentScopeChildren, true)) {
throw new ScopeWideningInjectionException($this->currentId, $this->currentScope, $id, $scope);
}
if (!in_array($scope, $this->currentScopeAncestors, true)) {
throw new ScopeCrossingInjectionException($this->currentId, $this->currentScope, $id, $scope);
}
}
/**
* Returns the Definition given an id.
*
* @param string $id Definition identifier
*
* @return Definition
*/
private function getDefinition($id)
{
if (!$this->container->hasDefinition($id)) {
return null;
}
return $this->container->getDefinition($id);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
/**
* This class is used to remove circular dependencies between individual passes.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
class Compiler
{
private $passConfig;
private $log;
private $loggingFormatter;
private $serviceReferenceGraph;
/**
* Constructor.
*/
public function __construct()
{
$this->passConfig = new PassConfig();
$this->serviceReferenceGraph = new ServiceReferenceGraph();
$this->loggingFormatter = new LoggingFormatter();
$this->log = array();
}
/**
* Returns the PassConfig.
*
* @return PassConfig The PassConfig instance
*
* @api
*/
public function getPassConfig()
{
return $this->passConfig;
}
/**
* Returns the ServiceReferenceGraph.
*
* @return ServiceReferenceGraph The ServiceReferenceGraph instance
*
* @api
*/
public function getServiceReferenceGraph()
{
return $this->serviceReferenceGraph;
}
/**
* Returns the logging formatter which can be used by compilation passes.
*
* @return LoggingFormatter
*/
public function getLoggingFormatter()
{
return $this->loggingFormatter;
}
/**
* Adds a pass to the PassConfig.
*
* @param CompilerPassInterface $pass A compiler pass
* @param string $type The type of the pass
*
* @api
*/
public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
{
$this->passConfig->addPass($pass, $type);
}
/**
* Adds a log message.
*
* @param string $string The log message
*/
public function addLogMessage($string)
{
$this->log[] = $string;
}
/**
* Returns the log.
*
* @return array Log array
*/
public function getLog()
{
return $this->log;
}
/**
* Run the Compiler and process all Passes.
*
* @param ContainerBuilder $container
*
* @api
*/
public function compile(ContainerBuilder $container)
{
foreach ($this->passConfig->getPasses() as $pass) {
$pass->process($container);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Interface that must be implemented by compilation passes
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
interface CompilerPassInterface
{
/**
* You can modify the container here before it is dumped to PHP code.
*
* @param ContainerBuilder $container
*
* @return void
*
* @api
*/
function process(ContainerBuilder $container);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Inline service definitions where this is possible.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class InlineServiceDefinitionsPass implements RepeatablePassInterface
{
private $repeatedPass;
private $graph;
private $compiler;
private $formatter;
private $currentId;
/**
* {@inheritDoc}
*/
public function setRepeatedPass(RepeatedPass $repeatedPass)
{
$this->repeatedPass = $repeatedPass;
}
/**
* Processes the ContainerBuilder for inline service definitions.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter();
$this->graph = $this->compiler->getServiceReferenceGraph();
foreach ($container->getDefinitions() as $id => $definition) {
$this->currentId = $id;
$definition->setArguments(
$this->inlineArguments($container, $definition->getArguments())
);
$definition->setMethodCalls(
$this->inlineArguments($container, $definition->getMethodCalls())
);
$definition->setProperties(
$this->inlineArguments($container, $definition->getProperties())
);
}
}
/**
* Processes inline arguments.
*
* @param ContainerBuilder $container The ContainerBuilder
* @param array $arguments An array of arguments
*/
private function inlineArguments(ContainerBuilder $container, array $arguments)
{
foreach ($arguments as $k => $argument) {
if (is_array($argument)) {
$arguments[$k] = $this->inlineArguments($container, $argument);
} elseif ($argument instanceof Reference) {
if (!$container->hasDefinition($id = (string) $argument)) {
continue;
}
if ($this->isInlinableDefinition($container, $id, $definition = $container->getDefinition($id))) {
$this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId));
if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) {
$arguments[$k] = $definition;
} else {
$arguments[$k] = clone $definition;
}
}
} elseif ($argument instanceof Definition) {
$argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
$argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
$argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
}
}
return $arguments;
}
/**
* Checks if the definition is inlineable.
*
* @param ContainerBuilder $container
* @param string $id
* @param Definition $definition
*
* @return Boolean If the definition is inlineable
*/
private function isInlinableDefinition(ContainerBuilder $container, $id, Definition $definition)
{
if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
return true;
}
if ($definition->isPublic()) {
return false;
}
if (!$this->graph->hasNode($id)) {
return true;
}
$ids = array();
foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
$ids[] = $edge->getSourceNode()->getId();
}
if (count(array_unique($ids)) > 1) {
return false;
}
return $container->getDefinition(reset($ids))->getScope() === $definition->getScope();
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
/**
* Used to format logging messages during the compilation.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class LoggingFormatter
{
public function formatRemoveService(CompilerPassInterface $pass, $id, $reason)
{
return $this->format($pass, sprintf('Removed service "%s"; reason: %s', $id, $reason));
}
public function formatInlineService(CompilerPassInterface $pass, $id, $target)
{
return $this->format($pass, sprintf('Inlined service "%s" to "%s".', $id, $target));
}
public function formatUpdateReference(CompilerPassInterface $pass, $serviceId, $oldDestId, $newDestId)
{
return $this->format($pass, sprintf('Changed reference of service "%s" previously pointing to "%s" to "%s".', $serviceId, $oldDestId, $newDestId));
}
public function formatResolveInheritance(CompilerPassInterface $pass, $childId, $parentId)
{
return $this->format($pass, sprintf('Resolving inheritance for "%s" (parent: %s).', $childId, $parentId));
}
public function format(CompilerPassInterface $pass, $message)
{
return sprintf('%s: %s', get_class($pass), $message);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Merges extension configs into the container builder
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class MergeExtensionConfigurationPass implements CompilerPassInterface
{
/**
* {@inheritDoc}
*/
public function process(ContainerBuilder $container)
{
$parameters = $container->getParameterBag()->all();
$definitions = $container->getDefinitions();
$aliases = $container->getAliases();
foreach ($container->getExtensions() as $name => $extension) {
if (!$config = $container->getExtensionConfig($name)) {
// this extension was not called
continue;
}
$config = $container->getParameterBag()->resolveValue($config);
$tmpContainer = new ContainerBuilder($container->getParameterBag());
$tmpContainer->addObjectResource($extension);
$extension->load($config, $tmpContainer);
$container->merge($tmpContainer);
}
$container->addDefinitions($definitions);
$container->addAliases($aliases);
$container->getParameterBag()->add($parameters);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
/**
* Compiler Pass Configuration
*
* This class has a default configuration embedded.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
class PassConfig
{
const TYPE_AFTER_REMOVING = 'afterRemoving';
const TYPE_BEFORE_OPTIMIZATION = 'beforeOptimization';
const TYPE_BEFORE_REMOVING = 'beforeRemoving';
const TYPE_OPTIMIZE = 'optimization';
const TYPE_REMOVE = 'removing';
private $mergePass;
private $afterRemovingPasses;
private $beforeOptimizationPasses;
private $beforeRemovingPasses;
private $optimizationPasses;
private $removingPasses;
/**
* Constructor.
*/
public function __construct()
{
$this->mergePass = new MergeExtensionConfigurationPass();
$this->afterRemovingPasses = array();
$this->beforeOptimizationPasses = array();
$this->beforeRemovingPasses = array();
$this->optimizationPasses = array(
new ResolveDefinitionTemplatesPass(),
new ResolveParameterPlaceHoldersPass(),
new CheckDefinitionValidityPass(),
new ResolveReferencesToAliasesPass(),
new ResolveInvalidReferencesPass(),
new AnalyzeServiceReferencesPass(true),
new CheckCircularReferencesPass(),
new CheckReferenceValidityPass(),
);
$this->removingPasses = array(
new RemovePrivateAliasesPass(),
new RemoveAbstractDefinitionsPass(),
new ReplaceAliasByActualDefinitionPass(),
new RepeatedPass(array(
new AnalyzeServiceReferencesPass(),
new InlineServiceDefinitionsPass(),
new AnalyzeServiceReferencesPass(),
new RemoveUnusedDefinitionsPass(),
)),
new CheckExceptionOnInvalidReferenceBehaviorPass(),
);
}
/**
* Returns all passes in order to be processed.
*
* @return array An array of all passes to process
*
* @api
*/
public function getPasses()
{
return array_merge(
array($this->mergePass),
$this->beforeOptimizationPasses,
$this->optimizationPasses,
$this->beforeRemovingPasses,
$this->removingPasses,
$this->afterRemovingPasses
);
}
/**
* Adds a pass.
*
* @param CompilerPassInterface $pass A Compiler pass
* @param string $type The pass type
*
* @throws \InvalidArgumentException when a pass type doesn't exist
*
* @api
*/
public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION)
{
$property = $type.'Passes';
if (!isset($this->$property)) {
throw new \InvalidArgumentException(sprintf('Invalid type "%s".', $type));
}
$passes = &$this->$property;
$passes[] = $pass;
}
/**
* Gets all passes for the AfterRemoving pass.
*
* @return array An array of passes
*
* @api
*/
public function getAfterRemovingPasses()
{
return $this->afterRemovingPasses;
}
/**
* Gets all passes for the BeforeOptimization pass.
*
* @return array An array of passes
*
* @api
*/
public function getBeforeOptimizationPasses()
{
return $this->beforeOptimizationPasses;
}
/**
* Gets all passes for the BeforeRemoving pass.
*
* @return array An array of passes
*
* @api
*/
public function getBeforeRemovingPasses()
{
return $this->beforeRemovingPasses;
}
/**
* Gets all passes for the Optimization pass.
*
* @return array An array of passes
*
* @api
*/
public function getOptimizationPasses()
{
return $this->optimizationPasses;
}
/**
* Gets all passes for the Removing pass.
*
* @return array An array of passes
*
* @api
*/
public function getRemovingPasses()
{
return $this->removingPasses;
}
/**
* Gets all passes for the Merge pass.
*
* @return array An array of passes
*
* @api
*/
public function getMergePass()
{
return $this->mergePass;
}
/**
* Sets the Merge Pass.
*
* @param CompilerPassInterface $pass The merge pass
*
* @api
*/
public function setMergePass(CompilerPassInterface $pass)
{
$this->mergePass = $pass;
}
/**
* Sets the AfterRemoving passes.
*
* @param array $passes An array of passes
*
* @api
*/
public function setAfterRemovingPasses(array $passes)
{
$this->afterRemovingPasses = $passes;
}
/**
* Sets the BeforeOptimization passes.
*
* @param array $passes An array of passes
*
* @api
*/
public function setBeforeOptimizationPasses(array $passes)
{
$this->beforeOptimizationPasses = $passes;
}
/**
* Sets the BeforeRemoving passes.
*
* @param array $passes An array of passes
*
* @api
*/
public function setBeforeRemovingPasses(array $passes)
{
$this->beforeRemovingPasses = $passes;
}
/**
* Sets the Optimization passes.
*
* @param array $passes An array of passes
*
* @api
*/
public function setOptimizationPasses(array $passes)
{
$this->optimizationPasses = $passes;
}
/**
* Sets the Removing passes.
*
* @param array $passes An array of passes
*
* @api
*/
public function setRemovingPasses(array $passes)
{
$this->removingPasses = $passes;
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Removes abstract Definitions
*
*/
class RemoveAbstractDefinitionsPass implements CompilerPassInterface
{
/**
* Removes abstract definitions from the ContainerBuilder
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$compiler = $container->getCompiler();
$formatter = $compiler->getLoggingFormatter();
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition->isAbstract()) {
$container->removeDefinition($id);
$compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'abstract'));
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Remove private aliases from the container. They were only used to establish
* dependencies between services, and these dependencies have been resolved in
* one of the previous passes.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RemovePrivateAliasesPass implements CompilerPassInterface
{
/**
* Removes private aliases from the ContainerBuilder
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$compiler = $container->getCompiler();
$formatter = $compiler->getLoggingFormatter();
foreach ($container->getAliases() as $id => $alias) {
if ($alias->isPublic()) {
continue;
}
$container->removeAlias($id);
$compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'private alias'));
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Removes unused service definitions from the container.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RemoveUnusedDefinitionsPass implements RepeatablePassInterface
{
private $repeatedPass;
/**
* {@inheritDoc}
*/
public function setRepeatedPass(RepeatedPass $repeatedPass)
{
$this->repeatedPass = $repeatedPass;
}
/**
* Processes the ContainerBuilder to remove unused definitions.
*
* @param ContainerBuilder $container
*
* @return void
*/
public function process(ContainerBuilder $container)
{
$compiler = $container->getCompiler();
$formatter = $compiler->getLoggingFormatter();
$graph = $compiler->getServiceReferenceGraph();
$hasChanged = false;
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition->isPublic()) {
continue;
}
if ($graph->hasNode($id)) {
$edges = $graph->getNode($id)->getInEdges();
$referencingAliases = array();
$sourceIds = array();
foreach ($edges as $edge) {
$node = $edge->getSourceNode();
$sourceIds[] = $node->getId();
if ($node->isAlias()) {
$referencingAlias[] = $node->getValue();
}
}
$isReferenced = (count(array_unique($sourceIds)) - count($referencingAliases)) > 0;
} else {
$referencingAliases = array();
$isReferenced = false;
}
if (1 === count($referencingAliases) && false === $isReferenced) {
$container->setDefinition((string) reset($referencingAliases), $definition);
$definition->setPublic(true);
$container->removeDefinition($id);
$compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'replaces alias '.reset($referencingAliases)));
} elseif (0 === count($referencingAliases) && false === $isReferenced) {
$container->removeDefinition($id);
$compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'unused'));
$hasChanged = true;
}
}
if ($hasChanged) {
$this->repeatedPass->setRepeat();
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
/**
* Interface that must be implemented by passes that are run as part of an
* RepeatedPass.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface RepeatablePassInterface extends CompilerPassInterface
{
/**
* Sets the RepeatedPass interface.
*
* @param RepeatedPass $repeatedPass
*/
function setRepeatedPass(RepeatedPass $repeatedPass);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* A pass that might be run repeatedly.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RepeatedPass implements CompilerPassInterface
{
private $repeat;
private $passes;
/**
* Constructor.
*
* @param array $passes An array of RepeatablePassInterface objects
*/
public function __construct(array $passes)
{
foreach ($passes as $pass) {
if (!$pass instanceof RepeatablePassInterface) {
throw new \InvalidArgumentException('$passes must be an array of RepeatablePassInterface.');
}
$pass->setRepeatedPass($this);
}
$this->passes = $passes;
}
/**
* Process the repeatable passes that run more than once.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$compiler = $container->getCompiler();
$this->repeat = false;
foreach ($this->passes as $pass) {
$pass->process($container);
}
if ($this->repeat) {
$this->process($container);
}
}
/**
* Sets if the pass should repeat
*/
public function setRepeat()
{
$this->repeat = true;
}
/**
* Returns the passes
*
* @return array An array of RepeatablePassInterface objects
*/
public function getPasses()
{
return $this->passes;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Replaces aliases with actual service definitions, effectively removing these
* aliases.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
{
private $compiler;
private $formatter;
private $sourceId;
/**
* Process the Container to replace aliases with service definitions.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter();
foreach ($container->getAliases() as $id => $alias) {
$aliasId = (string) $alias;
$definition = $container->getDefinition($aliasId);
if ($definition->isPublic()) {
continue;
}
$definition->setPublic(true);
$container->setDefinition($id, $definition);
$container->removeDefinition($aliasId);
$this->updateReferences($container, $aliasId, $id);
// we have to restart the process due to concurrent modification of
// the container
$this->process($container);
break;
}
}
/**
* Updates references to remove aliases.
*
* @param ContainerBuilder $container The container
* @param string $currentId The alias identifier being replaced
* @param string $newId The id of the service the alias points to
*/
private function updateReferences($container, $currentId, $newId)
{
foreach ($container->getAliases() as $id => $alias) {
if ($currentId === (string) $alias) {
$container->setAlias($id, $newId);
}
}
foreach ($container->getDefinitions() as $id => $definition) {
$this->sourceId = $id;
$definition->setArguments(
$this->updateArgumentReferences($definition->getArguments(), $currentId, $newId)
);
$definition->setMethodCalls(
$this->updateArgumentReferences($definition->getMethodCalls(), $currentId, $newId)
);
$definition->setProperties(
$this->updateArgumentReferences($definition->getProperties(), $currentId, $newId)
);
}
}
/**
* Updates argument references.
*
* @param array $arguments An array of Arguments
* @param string $currentId The alias identifier
* @param string $newId The identifier the alias points to
*/
private function updateArgumentReferences(array $arguments, $currentId, $newId)
{
foreach ($arguments as $k => $argument) {
if (is_array($argument)) {
$arguments[$k] = $this->updateArgumentReferences($argument, $currentId, $newId);
} elseif ($argument instanceof Reference) {
if ($currentId === (string) $argument) {
$arguments[$k] = new Reference($newId, $argument->getInvalidBehavior());
$this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $this->sourceId, $currentId, $newId));
}
}
}
return $arguments;
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* This replaces all DefinitionDecorator instances with their equivalent fully
* merged Definition instance.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ResolveDefinitionTemplatesPass implements CompilerPassInterface
{
private $container;
private $compiler;
private $formatter;
/**
* Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$this->container = $container;
$this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter();
foreach (array_keys($container->getDefinitions()) as $id) {
// yes, we are specifically fetching the definition from the
// container to ensure we are not operating on stale data
$definition = $container->getDefinition($id);
if (!$definition instanceof DefinitionDecorator || $definition->isAbstract()) {
continue;
}
$this->resolveDefinition($id, $definition);
}
}
/**
* Resolves the definition
*
* @param string $id The definition identifier
* @param DefinitionDecorator $definition
*
* @return Definition
*/
private function resolveDefinition($id, DefinitionDecorator $definition)
{
if (!$this->container->hasDefinition($parent = $definition->getParent())) {
throw new \RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $id));
}
$parentDef = $this->container->getDefinition($parent);
if ($parentDef instanceof DefinitionDecorator) {
$parentDef = $this->resolveDefinition($parent, $parentDef);
}
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $id, $parent));
$def = new Definition();
// merge in parent definition
// purposely ignored attributes: scope, abstract, tags
$def->setClass($parentDef->getClass());
$def->setArguments($parentDef->getArguments());
$def->setMethodCalls($parentDef->getMethodCalls());
$def->setProperties($parentDef->getProperties());
$def->setFactoryClass($parentDef->getFactoryClass());
$def->setFactoryMethod($parentDef->getFactoryMethod());
$def->setFactoryService($parentDef->getFactoryService());
$def->setConfigurator($parentDef->getConfigurator());
$def->setFile($parentDef->getFile());
$def->setPublic($parentDef->isPublic());
// overwrite with values specified in the decorator
$changes = $definition->getChanges();
if (isset($changes['class'])) {
$def->setClass($definition->getClass());
}
if (isset($changes['factory_class'])) {
$def->setFactoryClass($definition->getFactoryClass());
}
if (isset($changes['factory_method'])) {
$def->setFactoryMethod($definition->getFactoryMethod());
}
if (isset($changes['factory_service'])) {
$def->setFactoryService($definition->getFactoryService());
}
if (isset($changes['configurator'])) {
$def->setConfigurator($definition->getConfigurator());
}
if (isset($changes['file'])) {
$def->setFile($definition->getFile());
}
if (isset($changes['public'])) {
$def->setPublic($definition->isPublic());
}
// merge arguments
foreach ($definition->getArguments() as $k => $v) {
if (is_numeric($k)) {
$def->addArgument($v);
continue;
}
if (0 !== strpos($k, 'index_')) {
throw new \RuntimeException(sprintf('Invalid argument key "%s" found.', $k));
}
$index = (integer) substr($k, strlen('index_'));
$def->replaceArgument($index, $v);
}
// merge properties
foreach ($definition->getProperties() as $k => $v) {
$def->setProperty($k, $v);
}
// append method calls
if (count($calls = $definition->getMethodCalls()) > 0) {
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
}
// these attributes are always taken from the child
$def->setAbstract($definition->isAbstract());
$def->setScope($definition->getScope());
$def->setTags($definition->getTags());
// set new definition on container
$this->container->setDefinition($id, $def);
return $def;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Emulates the invalid behavior if the reference is not found within the
* container.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ResolveInvalidReferencesPass implements CompilerPassInterface
{
private $container;
/**
* Process the ContainerBuilder to resolve invalid references.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$this->container = $container;
foreach ($container->getDefinitions() as $definition) {
if ($definition->isSynthetic() || $definition->isAbstract()) {
continue;
}
$definition->setArguments(
$this->processArguments($definition->getArguments())
);
$calls = array();
foreach ($definition->getMethodCalls() as $call) {
try {
$calls[] = array($call[0], $this->processArguments($call[1], true));
} catch (\RuntimeException $ignore) {
// this call is simply removed
}
}
$definition->setMethodCalls($calls);
$properties = array();
foreach ($definition->getProperties() as $name => $value) {
try {
$value = $this->processArguments(array($value), true);
$properties[$name] = reset($value);
} catch (\RuntimeException $ignore) {
// ignore property
}
}
$definition->setProperties($properties);
}
}
/**
* Processes arguments to determine invalid references.
*
* @param array $arguments An array of Reference objects
* @param Boolean $inMethodCall
*/
private function processArguments(array $arguments, $inMethodCall = false)
{
foreach ($arguments as $k => $argument) {
if (is_array($argument)) {
$arguments[$k] = $this->processArguments($argument, $inMethodCall);
} elseif ($argument instanceof Reference) {
$id = (string) $argument;
$invalidBehavior = $argument->getInvalidBehavior();
$exists = $this->container->has($id);
// resolve invalid behavior
if ($exists && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
$arguments[$k] = new Reference($id);
} elseif (!$exists && ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) {
$arguments[$k] = null;
} elseif (!$exists && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) {
if ($inMethodCall) {
throw new \RuntimeException('Method shouldn\'t be called.');
}
$arguments[$k] = null;
}
}
}
return $arguments;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
/**
* Resolves all parameter placeholders "%somevalue%" to their real values.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ResolveParameterPlaceHoldersPass implements CompilerPassInterface
{
private $parameterBag;
/**
* Processes the ContainerBuilder to resolve parameter placeholders.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$parameterBag = $container->getParameterBag();
foreach ($container->getDefinitions() as $id => $definition) {
try {
$definition->setClass($parameterBag->resolveValue($definition->getClass()));
$definition->setFile($parameterBag->resolveValue($definition->getFile()));
$definition->setArguments($parameterBag->resolveValue($definition->getArguments()));
$calls = array();
foreach ($definition->getMethodCalls() as $name => $arguments) {
$calls[$parameterBag->resolveValue($name)] = $parameterBag->resolveValue($arguments);
}
$definition->setMethodCalls($calls);
$definition->setProperties($parameterBag->resolveValue($definition->getProperties()));
} catch (ParameterNotFoundException $e) {
$e->setSourceId($id);
throw $e;
}
}
$aliases = array();
foreach ($container->getAliases() as $name => $target) {
$aliases[$parameterBag->resolveValue($name)] = $parameterBag->resolveValue($target);
}
$container->setAliases($aliases);
$parameterBag->resolve();
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Replaces all references to aliases with references to the actual service.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ResolveReferencesToAliasesPass implements CompilerPassInterface
{
private $container;
/**
* Processes the ContainerBuilder to replace references to aliases with actual service references.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
$this->container = $container;
foreach ($container->getDefinitions() as $definition) {
if ($definition->isSynthetic() || $definition->isAbstract()) {
continue;
}
$definition->setArguments($this->processArguments($definition->getArguments()));
$definition->setMethodCalls($this->processArguments($definition->getMethodCalls()));
$definition->setProperties($this->processArguments($definition->getProperties()));
}
foreach ($container->getAliases() as $id => $alias) {
$aliasId = (string) $alias;
if ($aliasId !== $defId = $this->getDefinitionId($aliasId)) {
$container->setAlias($id, new Alias($defId, $alias->isPublic()));
}
}
}
/**
* Processes the arguments to replace aliases.
*
* @param array $arguments An array of References
*
* @return array An array of References
*/
private function processArguments(array $arguments)
{
foreach ($arguments as $k => $argument) {
if (is_array($argument)) {
$arguments[$k] = $this->processArguments($argument);
} elseif ($argument instanceof Reference) {
$defId = $this->getDefinitionId($id = (string) $argument);
if ($defId !== $id) {
$arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict());
}
}
}
return $arguments;
}
/**
* Resolves an alias into a definition id.
*
* @param string $id The definition or alias id to resolve
*
* @return string The definition id with aliases resolved
*/
private function getDefinitionId($id)
{
while ($this->container->hasAlias($id)) {
$id = (string) $this->container->getAlias($id);
}
return $id;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
/**
* This is a directed graph of your services.
*
* This information can be used by your compiler passes instead of collecting
* it themselves which improves performance quite a lot.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ServiceReferenceGraph
{
private $nodes;
/**
* Constructor.
*/
public function __construct()
{
$this->nodes = array();
}
/**
* Checks if the graph has a specific node.
*
* @param string $id Id to check
*/
public function hasNode($id)
{
return isset($this->nodes[$id]);
}
/**
* Gets a node by identifier.
*
* @param string $id The id to retrieve
*
* @return ServiceReferenceGraphNode The node matching the supplied identifier
*
* @throws \InvalidArgumentException
*/
public function getNode($id)
{
if (!isset($this->nodes[$id])) {
throw new \InvalidArgumentException(sprintf('There is no node with id "%s".', $id));
}
return $this->nodes[$id];
}
/**
* Returns all nodes.
*
* @return array An array of all ServiceReferenceGraphNode objects
*/
public function getNodes()
{
return $this->nodes;
}
/**
* Clears all nodes.
*/
public function clear()
{
$this->nodes = array();
}
/**
* Connects 2 nodes together in the Graph.
*
* @param string $sourceId
* @param string $sourceValue
* @param string $destId
* @param string $destValue
* @param string $reference
*/
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null)
{
$sourceNode = $this->createNode($sourceId, $sourceValue);
$destNode = $this->createNode($destId, $destValue);
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference);
$sourceNode->addOutEdge($edge);
$destNode->addInEdge($edge);
}
/**
* Creates a graph node.
*
* @param string $id
* @param string $value
*
* @return ServiceReferenceGraphNode
*/
private function createNode($id, $value)
{
if (isset($this->nodes[$id]) && $this->nodes[$id]->getValue() === $value) {
return $this->nodes[$id];
}
return $this->nodes[$id] = new ServiceReferenceGraphNode($id, $value);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
/**
* Represents an edge in your service graph.
*
* Value is typically a reference.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ServiceReferenceGraphEdge
{
private $sourceNode;
private $destNode;
private $value;
/**
* Constructor.
*
* @param ServiceReferenceGraphNode $sourceNode
* @param ServiceReferenceGraphNode $destNode
* @param string $value
*/
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null)
{
$this->sourceNode = $sourceNode;
$this->destNode = $destNode;
$this->value = $value;
}
/**
* Returns the value of the edge
*
* @return ServiceReferenceGraphNode
*/
public function getValue()
{
return $this->value;
}
/**
* Returns the source node
*
* @return ServiceReferenceGraphNode
*/
public function getSourceNode()
{
return $this->sourceNode;
}
/**
* Returns the destination node
*
* @return ServiceReferenceGraphNode
*/
public function getDestNode()
{
return $this->destNode;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Alias;
/**
* Represents a node in your service graph.
*
* Value is typically a definition, or an alias.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ServiceReferenceGraphNode
{
private $id;
private $inEdges;
private $outEdges;
private $value;
/**
* Constructor.
*
* @param string $id The node identifier
* @param mixed $value The node value
*/
public function __construct($id, $value)
{
$this->id = $id;
$this->value = $value;
$this->inEdges = array();
$this->outEdges = array();
}
/**
* Adds an in edge to this node.
*
* @param ServiceReferenceGraphEdge $edge
*/
public function addInEdge(ServiceReferenceGraphEdge $edge)
{
$this->inEdges[] = $edge;
}
/**
* Adds an out edge to this node.
*
* @param ServiceReferenceGraphEdge $edge
*/
public function addOutEdge(ServiceReferenceGraphEdge $edge)
{
$this->outEdges[] = $edge;
}
/**
* Checks if the value of this node is an Alias.
*
* @return Boolean True if the value is an Alias instance
*/
public function isAlias()
{
return $this->value instanceof Alias;
}
/**
* Checks if the value of this node is a Definition.
*
* @return Boolean True if the value is a Definition instance
*/
public function isDefinition()
{
return $this->value instanceof Definition;
}
/**
* Returns the identifier.
*
* @return string
*/
public function getId()
{
return $this->id;
}
/**
* Returns the in edges.
*
* @return array The in ServiceReferenceGraphEdge array
*/
public function getInEdges()
{
return $this->inEdges;
}
/**
* Returns the out edges.
*
* @return array The out ServiceReferenceGraphEdge array
*/
public function getOutEdges()
{
return $this->outEdges;
}
/**
* Returns the value of this Node
*
* @return mixed The value
*/
public function getValue()
{
return $this->value;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**
* Container is a dependency injection container.
*
* It gives access to object instances (services).
*
* Services and parameters are simple key/pair stores.
*
* Parameter and service keys are case insensitive.
*
* A service id can contain lowercased letters, digits, underscores, and dots.
* Underscores are used to separate words, and dots to group services
* under namespaces:
*
* <ul>
* <li>request</li>
* <li>mysql_session_storage</li>
* <li>symfony.mysql_session_storage</li>
* </ul>
*
* A service can also be defined by creating a method named
* getXXXService(), where XXX is the camelized version of the id:
*
* <ul>
* <li>request -> getRequestService()</li>
* <li>mysql_session_storage -> getMysqlSessionStorageService()</li>
* <li>symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()</li>
* </ul>
*
* The container can have three possible behaviors when a service does not exist:
*
* * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default)
* * NULL_ON_INVALID_REFERENCE: Returns null
* * IGNORE_ON_INVALID_REFERENCE: Ignores the wrapping command asking for the reference
* (for instance, ignore a setter if the service does not exist)
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
class Container implements ContainerInterface
{
protected $parameterBag;
protected $services;
protected $scopes;
protected $scopeChildren;
protected $scopedServices;
protected $scopeStacks;
protected $loading = array();
/**
* Constructor.
*
* @param ParameterBagInterface $parameterBag A ParameterBagInterface instance
*
* @api
*/
public function __construct(ParameterBagInterface $parameterBag = null)
{
$this->parameterBag = null === $parameterBag ? new ParameterBag() : $parameterBag;
$this->services = array();
$this->scopes = array();
$this->scopeChildren = array();
$this->scopedServices = array();
$this->scopeStacks = array();
$this->set('service_container', $this);
}
/**
* Compiles the container.
*
* This method does two things:
*
* * Parameter values are resolved;
* * The parameter bag is frozen.
*
* @api
*/
public function compile()
{
$this->parameterBag->resolve();
$this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
}
/**
* Returns true if the container parameter bag are frozen.
*
* @return Boolean true if the container parameter bag are frozen, false otherwise
*
* @api
*/
public function isFrozen()
{
return $this->parameterBag instanceof FrozenParameterBag;
}
/**
* Gets the service container parameter bag.
*
* @return ParameterBagInterface A ParameterBagInterface instance
*
* @api
*/
public function getParameterBag()
{
return $this->parameterBag;
}
/**
* Gets a parameter.
*
* @param string $name The parameter name
*
* @return mixed The parameter value
*
* @throws \InvalidArgumentException if the parameter is not defined
*
* @api
*/
public function getParameter($name)
{
return $this->parameterBag->get($name);
}
/**
* Checks if a parameter exists.
*
* @param string $name The parameter name
*
* @return Boolean The presence of parameter in container
*
* @api
*/
public function hasParameter($name)
{
return $this->parameterBag->has($name);
}
/**
* Sets a parameter.
*
* @param string $name The parameter name
* @param mixed $value The parameter value
*
* @api
*/
public function setParameter($name, $value)
{
$this->parameterBag->set($name, $value);
}
/**
* Sets a service.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope of the service
*
* @api
*/
public function set($id, $service, $scope = self::SCOPE_CONTAINER)
{
if (self::SCOPE_PROTOTYPE === $scope) {
throw new \InvalidArgumentException('You cannot set services of scope "prototype".');
}
$id = strtolower($id);
if (self::SCOPE_CONTAINER !== $scope) {
if (!isset($this->scopedServices[$scope])) {
throw new \RuntimeException('You cannot set services of inactive scopes.');
}
$this->scopedServices[$scope][$id] = $service;
}
$this->services[$id] = $service;
}
/**
* Returns true if the given service is defined.
*
* @param string $id The service identifier
*
* @return Boolean true if the service is defined, false otherwise
*
* @api
*/
public function has($id)
{
$id = strtolower($id);
return isset($this->services[$id]) || method_exists($this, 'get'.strtr($id, array('_' => '', '.' => '_')).'Service');
}
/**
* Gets a service.
*
* If a service is both defined through a set() method and
* with a set*Service() method, the former has always precedence.
*
* @param string $id The service identifier
* @param integer $invalidBehavior The behavior when the service does not exist
*
* @return object The associated service
*
* @throws \InvalidArgumentException if the service is not defined
*
* @see Reference
*
* @api
*/
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
{
$id = strtolower($id);
if (isset($this->services[$id])) {
return $this->services[$id];
}
if (isset($this->loading[$id])) {
throw new ServiceCircularReferenceException($id, array_keys($this->loading));
}
if (method_exists($this, $method = 'get'.strtr($id, array('_' => '', '.' => '_')).'Service')) {
$this->loading[$id] = true;
try {
$service = $this->$method();
} catch (\Exception $e) {
unset($this->loading[$id]);
throw $e;
}
unset($this->loading[$id]);
return $service;
}
if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
throw new ServiceNotFoundException($id);
}
}
/**
* Gets all service ids.
*
* @return array An array of all defined service ids
*/
public function getServiceIds()
{
$ids = array();
$r = new \ReflectionClass($this);
foreach ($r->getMethods() as $method) {
if (preg_match('/^get(.+)Service$/', $method->getName(), $match)) {
$ids[] = self::underscore($match[1]);
}
}
return array_unique(array_merge($ids, array_keys($this->services)));
}
/**
* This is called when you enter a scope
*
* @param string $name
*
* @return void
*
* @api
*/
public function enterScope($name)
{
if (!isset($this->scopes[$name])) {
throw new \InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
}
if (self::SCOPE_CONTAINER !== $this->scopes[$name] && !isset($this->scopedServices[$this->scopes[$name]])) {
throw new \RuntimeException(sprintf('The parent scope "%s" must be active when entering this scope.', $this->scopes[$name]));
}
// check if a scope of this name is already active, if so we need to
// remove all services of this scope, and those of any of its child
// scopes from the global services map
if (isset($this->scopedServices[$name])) {
$services = array($this->services, $name => $this->scopedServices[$name]);
unset($this->scopedServices[$name]);
foreach ($this->scopeChildren[$name] as $child) {
$services[$child] = $this->scopedServices[$child];
unset($this->scopedServices[$child]);
}
// update global map
$this->services = call_user_func_array('array_diff_key', $services);
array_shift($services);
// add stack entry for this scope so we can restore the removed services later
if (!isset($this->scopeStacks[$name])) {
$this->scopeStacks[$name] = new \SplStack();
}
$this->scopeStacks[$name]->push($services);
}
$this->scopedServices[$name] = array();
}
/**
* This is called to leave the current scope, and move back to the parent
* scope.
*
* @param string $name The name of the scope to leave
*
* @return void
*
* @throws \InvalidArgumentException if the scope is not active
*
* @api
*/
public function leaveScope($name)
{
if (!isset($this->scopedServices[$name])) {
throw new \InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
}
// remove all services of this scope, or any of its child scopes from
// the global service map
$services = array($this->services, $this->scopedServices[$name]);
unset($this->scopedServices[$name]);
foreach ($this->scopeChildren[$name] as $child) {
if (!isset($this->scopedServices[$child])) {
continue;
}
$services[] = $this->scopedServices[$child];
unset($this->scopedServices[$child]);
}
$this->services = call_user_func_array('array_diff_key', $services);
// check if we need to restore services of a previous scope of this type
if (isset($this->scopeStacks[$name]) && count($this->scopeStacks[$name]) > 0) {
$services = $this->scopeStacks[$name]->pop();
$this->scopedServices += $services;
array_unshift($services, $this->services);
$this->services = call_user_func_array('array_merge', $services);
}
}
/**
* Adds a scope to the container.
*
* @param ScopeInterface $scope
*
* @return void
*
* @api
*/
public function addScope(ScopeInterface $scope)
{
$name = $scope->getName();
$parentScope = $scope->getParentName();
if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
throw new \InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
}
if (isset($this->scopes[$name])) {
throw new \InvalidArgumentException(sprintf('A scope with name "%s" already exists.', $name));
}
if (self::SCOPE_CONTAINER !== $parentScope && !isset($this->scopes[$parentScope])) {
throw new \InvalidArgumentException(sprintf('The parent scope "%s" does not exist, or is invalid.', $parentScope));
}
$this->scopes[$name] = $parentScope;
$this->scopeChildren[$name] = array();
// normalize the child relations
while ($parentScope !== self::SCOPE_CONTAINER) {
$this->scopeChildren[$parentScope][] = $name;
$parentScope = $this->scopes[$parentScope];
}
}
/**
* Returns whether this container has a certain scope
*
* @param string $name The name of the scope
*
* @return Boolean
*
* @api
*/
public function hasScope($name)
{
return isset($this->scopes[$name]);
}
/**
* Returns whether this scope is currently active
*
* This does not actually check if the passed scope actually exists.
*
* @param string $name
*
* @return Boolean
*
* @api
*/
public function isScopeActive($name)
{
return isset($this->scopedServices[$name]);
}
/**
* Camelizes a string.
*
* @param string $id A string to camelize
*
* @return string The camelized string
*/
static public function camelize($id)
{
return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $id);
}
/**
* A string to underscore.
*
* @param string $id The string to underscore
*
* @return string The underscored string
*/
static public function underscore($id)
{
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($id, '_', '.')));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* A simple implementation of ContainerAwareInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ContainerAware implements ContainerAwareInterface
{
/**
* @var ContainerInterface
*
* @api
*/
protected $container;
/**
* Sets the Container associated with this Controller.
*
* @param ContainerInterface $container A ContainerInterface instance
*
* @api
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* ContainerAwareInterface should be implemented by classes that depends on a Container.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface ContainerAwareInterface
{
/**
* Sets the Container.
*
* @param ContainerInterface $container A ContainerInterface instance
*
* @api
*/
function setContainer(ContainerInterface $container = null);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* ContainerBuilder is a DI container that provides an API to easily describe services.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ContainerBuilder extends Container implements TaggedContainerInterface
{
private $extensions = array();
private $extensionsByNs = array();
private $definitions = array();
private $aliases = array();
private $resources = array();
private $extensionConfigs = array();
private $injectors = array();
private $compiler;
/**
* Registers an extension.
*
* @param ExtensionInterface $extension An extension instance
*
* @api
*/
public function registerExtension(ExtensionInterface $extension)
{
$this->extensions[$extension->getAlias()] = $extension;
if (false !== $extension->getNamespace()) {
$this->extensionsByNs[$extension->getNamespace()] = $extension;
}
}
/**
* Returns an extension by alias or namespace.
*
* @param string $name An alias or a namespace
*
* @return ExtensionInterface An extension instance
*
* @api
*/
public function getExtension($name)
{
if (isset($this->extensions[$name])) {
return $this->extensions[$name];
}
if (isset($this->extensionsByNs[$name])) {
return $this->extensionsByNs[$name];
}
throw new \LogicException(sprintf('Container extension "%s" is not registered', $name));
}
/**
* Returns all registered extensions.
*
* @return array An array of ExtensionInterface
*
* @api
*/
public function getExtensions()
{
return $this->extensions;
}
/**
* Checks if we have an extension.
*
* @param string $name The name of the extension
*
* @return Boolean If the extension exists
*
* @api
*/
public function hasExtension($name)
{
return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
}
/**
* Returns an array of resources loaded to build this configuration.
*
* @return ResourceInterface[] An array of resources
*
* @api
*/
public function getResources()
{
return array_unique($this->resources);
}
/**
* Adds a resource for this configuration.
*
* @param ResourceInterface $resource A resource instance
*
* @return ContainerBuilder The current instance
*
* @api
*/
public function addResource(ResourceInterface $resource)
{
$this->resources[] = $resource;
return $this;
}
/**
* Adds the object class hierarchy as resources.
*
* @param object $object An object instance
*
* @api
*/
public function addObjectResource($object)
{
$parent = new \ReflectionObject($object);
do {
$this->addResource(new FileResource($parent->getFileName()));
} while ($parent = $parent->getParentClass());
}
/**
* Loads the configuration for an extension.
*
* @param string $extension The extension alias or namespace
* @param array $values An array of values that customizes the extension
*
* @return ContainerBuilder The current instance
*
* @api
*/
public function loadFromExtension($extension, array $values = array())
{
if (true === $this->isFrozen()) {
throw new \LogicException('Cannot load from an extension on a frozen container.');
}
$namespace = $this->getExtension($extension)->getAlias();
$this->extensionConfigs[$namespace][] = $values;
return $this;
}
/**
* Adds a compiler pass.
*
* @param CompilerPassInterface $pass A compiler pass
* @param string $type The type of compiler pass
*
* @api
*/
public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
{
if (null === $this->compiler) {
$this->compiler = new Compiler();
}
$this->compiler->addPass($pass, $type);
$this->addObjectResource($pass);
}
/**
* Returns the compiler pass config which can then be modified.
*
* @return PassConfig The compiler pass config
*
* @api
*/
public function getCompilerPassConfig()
{
if (null === $this->compiler) {
$this->compiler = new Compiler();
}
return $this->compiler->getPassConfig();
}
/**
* Returns the compiler.
*
* @return Compiler The compiler
*
* @api
*/
public function getCompiler()
{
if (null === $this->compiler) {
$this->compiler = new Compiler();
}
return $this->compiler;
}
/**
* Returns all Scopes.
*
* @return array An array of scopes
*
* @api
*/
public function getScopes()
{
return $this->scopes;
}
/**
* Returns all Scope children.
*
* @return array An array of scope children.
*
* @api
*/
public function getScopeChildren()
{
return $this->scopeChildren;
}
/**
* Sets a service.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope
*
* @throws BadMethodCallException
*
* @api
*/
public function set($id, $service, $scope = self::SCOPE_CONTAINER)
{
if ($this->isFrozen()) {
throw new \BadMethodCallException('Setting service on a frozen container is not allowed');
}
$id = strtolower($id);
unset($this->definitions[$id], $this->aliases[$id]);
parent::set($id, $service, $scope);
}
/**
* Removes a service definition.
*
* @param string $id The service identifier
*
* @api
*/
public function removeDefinition($id)
{
unset($this->definitions[strtolower($id)]);
}
/**
* Returns true if the given service is defined.
*
* @param string $id The service identifier
*
* @return Boolean true if the service is defined, false otherwise
*
* @api
*/
public function has($id)
{
$id = strtolower($id);
return isset($this->definitions[$id]) || isset($this->aliases[$id]) || parent::has($id);
}
/**
* Gets a service.
*
* @param string $id The service identifier
* @param integer $invalidBehavior The behavior when the service does not exist
*
* @return object The associated service
*
* @throws \InvalidArgumentException if the service is not defined
* @throws \LogicException if the service has a circular reference to itself
*
* @see Reference
*
* @api
*/
public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
{
$id = strtolower($id);
try {
return parent::get($id, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
} catch (\InvalidArgumentException $e) {
if (isset($this->loading[$id])) {
throw new \LogicException(sprintf('The service "%s" has a circular reference to itself.', $id), 0, $e);
}
if (!$this->hasDefinition($id) && isset($this->aliases[$id])) {
return $this->get($this->aliases[$id]);
}
try {
$definition = $this->getDefinition($id);
} catch (\InvalidArgumentException $e) {
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return null;
}
throw $e;
}
$this->loading[$id] = true;
$service = $this->createService($definition, $id);
unset($this->loading[$id]);
return $service;
}
}
/**
* Merges a ContainerBuilder with the current ContainerBuilder configuration.
*
* Service definitions overrides the current defined ones.
*
* But for parameters, they are overridden by the current ones. It allows
* the parameters passed to the container constructor to have precedence
* over the loaded ones.
*
* $container = new ContainerBuilder(array('foo' => 'bar'));
* $loader = new LoaderXXX($container);
* $loader->load('resource_name');
* $container->register('foo', new stdClass());
*
* In the above example, even if the loaded resource defines a foo
* parameter, the value will still be 'bar' as defined in the ContainerBuilder
* constructor.
*
* @param ContainerBuilder $container The ContainerBuilder instance to merge.
*
* @throws \LogicException when this ContainerBuilder is frozen
*
* @api
*/
public function merge(ContainerBuilder $container)
{
if (true === $this->isFrozen()) {
throw new \LogicException('Cannot merge on a frozen container.');
}
$this->addDefinitions($container->getDefinitions());
$this->addAliases($container->getAliases());
$this->getParameterBag()->add($container->getParameterBag()->all());
foreach ($container->getResources() as $resource) {
$this->addResource($resource);
}
foreach ($this->extensions as $name => $extension) {
if (!isset($this->extensionConfigs[$name])) {
$this->extensionConfigs[$name] = array();
}
$this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
}
}
/**
* Returns the configuration array for the given extension.
*
* @param string $name The name of the extension
*
* @return array An array of configuration
*
* @api
*/
public function getExtensionConfig($name)
{
if (!isset($this->extensionConfigs[$name])) {
$this->extensionConfigs[$name] = array();
}
return $this->extensionConfigs[$name];
}
/**
* Compiles the container.
*
* This method passes the container to compiler
* passes whose job is to manipulate and optimize
* the container.
*
* The main compiler passes roughly do four things:
*
* * The extension configurations are merged;
* * Parameter values are resolved;
* * The parameter bag is frozen;
* * Extension loading is disabled.
*
* @api
*/
public function compile()
{
if (null === $this->compiler) {
$this->compiler = new Compiler();
}
foreach ($this->compiler->getPassConfig()->getPasses() as $pass) {
$this->addObjectResource($pass);
}
$this->compiler->compile($this);
$this->extensionConfigs = array();
parent::compile();
}
/**
* Gets all service ids.
*
* @return array An array of all defined service ids
*/
public function getServiceIds()
{
return array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliases), parent::getServiceIds()));
}
/**
* Adds the service aliases.
*
* @param array $aliases An array of aliases
*
* @api
*/
public function addAliases(array $aliases)
{
foreach ($aliases as $alias => $id) {
$this->setAlias($alias, $id);
}
}
/**
* Sets the service aliases.
*
* @param array $aliases An array of service definitions
*
* @api
*/
public function setAliases(array $aliases)
{
$this->aliases = array();
$this->addAliases($aliases);
}
/**
* Sets an alias for an existing service.
*
* @param string $alias The alias to create
* @param mixed $id The service to alias
*
* @api
*/
public function setAlias($alias, $id)
{
$alias = strtolower($alias);
if (is_string($id)) {
$id = new Alias($id);
} elseif (!$id instanceof Alias) {
throw new \InvalidArgumentException('$id must be a string, or an Alias object.');
}
if ($alias === strtolower($id)) {
throw new \InvalidArgumentException('An alias can not reference itself, got a circular reference on "'.$alias.'".');
}
unset($this->definitions[$alias]);
$this->aliases[$alias] = $id;
}
/**
* Removes an alias.
*
* @param string $alias The alias to remove
*
* @api
*/
public function removeAlias($alias)
{
unset($this->aliases[strtolower($alias)]);
}
/**
* Returns true if an alias exists under the given identifier.
*
* @param string $id The service identifier
*
* @return Boolean true if the alias exists, false otherwise
*
* @api
*/
public function hasAlias($id)
{
return isset($this->aliases[strtolower($id)]);
}
/**
* Gets all defined aliases.
*
* @return array An array of aliases
*
* @api
*/
public function getAliases()
{
return $this->aliases;
}
/**
* Gets an alias.
*
* @param string $id The service identifier
*
* @return string The aliased service identifier
*
* @throws \InvalidArgumentException if the alias does not exist
*
* @api
*/
public function getAlias($id)
{
$id = strtolower($id);
if (!$this->hasAlias($id)) {
throw new \InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
}
return $this->aliases[$id];
}
/**
* Registers a service definition.
*
* This methods allows for simple registration of service definition
* with a fluid interface.
*
* @param string $id The service identifier
* @param string $class The service class
*
* @return Definition A Definition instance
*
* @api
*/
public function register($id, $class = null)
{
return $this->setDefinition(strtolower($id), new Definition($class));
}
/**
* Adds the service definitions.
*
* @param Definition[] $definitions An array of service definitions
*
* @api
*/
public function addDefinitions(array $definitions)
{
foreach ($definitions as $id => $definition) {
$this->setDefinition($id, $definition);
}
}
/**
* Sets the service definitions.
*
* @param array $definitions An array of service definitions
*
* @api
*/
public function setDefinitions(array $definitions)
{
$this->definitions = array();
$this->addDefinitions($definitions);
}
/**
* Gets all service definitions.
*
* @return array An array of Definition instances
*
* @api
*/
public function getDefinitions()
{
return $this->definitions;
}
/**
* Sets a service definition.
*
* @param string $id The service identifier
* @param Definition $definition A Definition instance
*
* @throws BadMethodCallException
*
* @api
*/
public function setDefinition($id, Definition $definition)
{
if ($this->isFrozen()) {
throw new \BadMethodCallException('Adding definition to a frozen container is not allowed');
}
$id = strtolower($id);
unset($this->aliases[$id]);
return $this->definitions[$id] = $definition;
}
/**
* Returns true if a service definition exists under the given identifier.
*
* @param string $id The service identifier
*
* @return Boolean true if the service definition exists, false otherwise
*
* @api
*/
public function hasDefinition($id)
{
return array_key_exists(strtolower($id), $this->definitions);
}
/**
* Gets a service definition.
*
* @param string $id The service identifier
*
* @return Definition A Definition instance
*
* @throws \InvalidArgumentException if the service definition does not exist
*
* @api
*/
public function getDefinition($id)
{
$id = strtolower($id);
if (!$this->hasDefinition($id)) {
throw new \InvalidArgumentException(sprintf('The service definition "%s" does not exist.', $id));
}
return $this->definitions[$id];
}
/**
* Gets a service definition by id or alias.
*
* The method "unaliases" recursively to return a Definition instance.
*
* @param string $id The service identifier or alias
*
* @return Definition A Definition instance
*
* @throws \InvalidArgumentException if the service definition does not exist
*
* @api
*/
public function findDefinition($id)
{
while ($this->hasAlias($id)) {
$id = (string) $this->getAlias($id);
}
return $this->getDefinition($id);
}
/**
* Creates a service for a service definition.
*
* @param Definition $definition A service definition instance
* @param string $id The service identifier
*
* @return object The service described by the service definition
*
* @throws \InvalidArgumentException When configure callable is not callable
*/
private function createService(Definition $definition, $id)
{
if (null !== $definition->getFile()) {
require_once $this->getParameterBag()->resolveValue($definition->getFile());
}
$arguments = $this->resolveServices($this->getParameterBag()->resolveValue($definition->getArguments()));
if (null !== $definition->getFactoryMethod()) {
if (null !== $definition->getFactoryClass()) {
$factory = $this->getParameterBag()->resolveValue($definition->getFactoryClass());
} elseif (null !== $definition->getFactoryService()) {
$factory = $this->get($this->getParameterBag()->resolveValue($definition->getFactoryService()));
} else {
throw new \RuntimeException('Cannot create service from factory method without a factory service or factory class.');
}
$service = call_user_func_array(array($factory, $definition->getFactoryMethod()), $arguments);
} else {
$r = new \ReflectionClass($this->getParameterBag()->resolveValue($definition->getClass()));
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
}
if (self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
throw new \RuntimeException('You tried to create a service of an inactive scope.');
}
$this->services[$lowerId = strtolower($id)] = $service;
if (self::SCOPE_CONTAINER !== $scope) {
$this->scopedServices[$scope][$lowerId] = $service;
}
}
foreach ($definition->getMethodCalls() as $call) {
$services = self::getServiceConditionals($call[1]);
$ok = true;
foreach ($services as $s) {
if (!$this->has($s)) {
$ok = false;
break;
}
}
if ($ok) {
call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->resolveValue($call[1])));
}
}
$properties = $this->resolveServices($this->getParameterBag()->resolveValue($definition->getProperties()));
foreach ($properties as $name => $value) {
$service->$name = $value;
}
if ($callable = $definition->getConfigurator()) {
if (is_array($callable) && is_object($callable[0]) && $callable[0] instanceof Reference) {
$callable[0] = $this->get((string) $callable[0]);
} elseif (is_array($callable)) {
$callable[0] = $this->getParameterBag()->resolveValue($callable[0]);
}
if (!is_callable($callable)) {
throw new \InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service)));
}
call_user_func($callable, $service);
}
return $service;
}
/**
* Replaces service references by the real service instance.
*
* @param mixed $value A value
*
* @return mixed The same value with all service references replaced by the real service instances
*/
public function resolveServices($value)
{
if (is_array($value)) {
foreach ($value as &$v) {
$v = $this->resolveServices($v);
}
} elseif (is_object($value) && $value instanceof Reference) {
$value = $this->get((string) $value, $value->getInvalidBehavior());
} elseif (is_object($value) && $value instanceof Definition) {
$value = $this->createService($value, null);
}
return $value;
}
/**
* Returns service ids for a given tag.
*
* @param string $name The tag name
*
* @return array An array of tags
*
* @api
*/
public function findTaggedServiceIds($name)
{
$tags = array();
foreach ($this->getDefinitions() as $id => $definition) {
if ($definition->getTag($name)) {
$tags[$id] = $definition->getTag($name);
}
}
return $tags;
}
/**
* Returns the Service Conditionals.
*
* @param mixed $value An array of conditionals to return.
*
* @return array An array of Service conditionals
*/
static public function getServiceConditionals($value)
{
$services = array();
if (is_array($value)) {
foreach ($value as $v) {
$services = array_unique(array_merge($services, self::getServiceConditionals($v)));
}
} elseif (is_object($value) && $value instanceof Reference && $value->getInvalidBehavior() === ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
$services[] = (string) $value;
}
return $services;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* ContainerInterface is the interface implemented by service container classes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
interface ContainerInterface
{
const EXCEPTION_ON_INVALID_REFERENCE = 1;
const NULL_ON_INVALID_REFERENCE = 2;
const IGNORE_ON_INVALID_REFERENCE = 3;
const SCOPE_CONTAINER = 'container';
const SCOPE_PROTOTYPE = 'prototype';
/**
* Sets a service.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope of the service
*
* @api
*/
function set($id, $service, $scope = self::SCOPE_CONTAINER);
/**
* Gets a service.
*
* @param string $id The service identifier
* @param int $invalidBehavior The behavior when the service does not exist
*
* @return object The associated service
*
* @throws \InvalidArgumentException if the service is not defined
*
* @see Reference
*
* @api
*/
function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE);
/**
* Returns true if the given service is defined.
*
* @param string $id The service identifier
*
* @return Boolean true if the service is defined, false otherwise
*
* @api
*/
function has($id);
/**
* Gets a parameter.
*
* @param string $name The parameter name
*
* @return mixed The parameter value
*
* @throws \InvalidArgumentException if the parameter is not defined
*
* @api
*/
function getParameter($name);
/**
* Checks if a parameter exists.
*
* @param string $name The parameter name
*
* @return Boolean The presence of parameter in container
*
* @api
*/
function hasParameter($name);
/**
* Sets a parameter.
*
* @param string $name The parameter name
* @param mixed $value The parameter value
*
* @api
*/
function setParameter($name, $value);
/**
* Enters the given scope
*
* @param string $name
*
* @return void
*
* @api
*/
function enterScope($name);
/**
* Leaves the current scope, and re-enters the parent scope
*
* @param string $name
*
* @return void
*
* @api
*/
function leaveScope($name);
/**
* Adds a scope to the container
*
* @param ScopeInterface $scope
*
* @return void
*
* @api
*/
function addScope(ScopeInterface $scope);
/**
* Whether this container has the given scope
*
* @param string $name
*
* @return Boolean
*
* @api
*/
function hasScope($name);
/**
* Determines whether the given scope is currently active.
*
* It does however not check if the scope actually exists.
*
* @param string $name
*
* @return Boolean
*
* @api
*/
function isScopeActive($name);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
/**
* Definition represents a service definition.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Definition
{
private $class;
private $file;
private $factoryClass;
private $factoryMethod;
private $factoryService;
private $scope;
private $properties;
private $calls;
private $configurator;
private $tags;
private $public;
private $synthetic;
private $abstract;
protected $arguments;
/**
* Constructor.
*
* @param string $class The service class
* @param array $arguments An array of arguments to pass to the service constructor
*
* @api
*/
public function __construct($class = null, array $arguments = array())
{
$this->class = $class;
$this->arguments = $arguments;
$this->calls = array();
$this->scope = ContainerInterface::SCOPE_CONTAINER;
$this->tags = array();
$this->public = true;
$this->synthetic = false;
$this->abstract = false;
$this->properties = array();
}
/**
* Sets the name of the class that acts as a factory using the factory method,
* which will be invoked statically.
*
* @param string $factoryClass The factory class name
*
* @return Definition The current instance
*
* @api
*/
public function setFactoryClass($factoryClass)
{
$this->factoryClass = $factoryClass;
return $this;
}
/**
* Gets the factory class.
*
* @return string The factory class name
*
* @api
*/
public function getFactoryClass()
{
return $this->factoryClass;
}
/**
* Sets the factory method able to create an instance of this class.
*
* @param string $factoryMethod The factory method name
*
* @return Definition The current instance
*
* @api
*/
public function setFactoryMethod($factoryMethod)
{
$this->factoryMethod = $factoryMethod;
return $this;
}
/**
* Gets the factory method.
*
* @return string The factory method name
*
* @api
*/
public function getFactoryMethod()
{
return $this->factoryMethod;
}
/**
* Sets the name of the service that acts as a factory using the factory method.
*
* @param string $factoryService The factory service id
*
* @return Definition The current instance
*
* @api
*/
public function setFactoryService($factoryService)
{
$this->factoryService = $factoryService;
return $this;
}
/**
* Gets the factory service id.
*
* @return string The factory service id
*
* @api
*/
public function getFactoryService()
{
return $this->factoryService;
}
/**
* Sets the service class.
*
* @param string $class The service class
*
* @return Definition The current instance
*
* @api
*/
public function setClass($class)
{
$this->class = $class;
return $this;
}
/**
* Sets the service class.
*
* @return string The service class
*
* @api
*/
public function getClass()
{
return $this->class;
}
/**
* Sets the arguments to pass to the service constructor/factory method.
*
* @param array $arguments An array of arguments
*
* @return Definition The current instance
*
* @api
*/
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
return $this;
}
/**
* @api
*/
public function setProperties(array $properties)
{
$this->properties = $properties;
return $this;
}
/**
* @api
*/
public function getProperties()
{
return $this->properties;
}
/**
* @api
*/
public function setProperty($name, $value)
{
$this->properties[$name] = $value;
return $this;
}
/**
* Adds an argument to pass to the service constructor/factory method.
*
* @param mixed $argument An argument
*
* @return Definition The current instance
*
* @api
*/
public function addArgument($argument)
{
$this->arguments[] = $argument;
return $this;
}
/**
* Sets a specific argument
*
* @param integer $index
* @param mixed $argument
*
* @return Definition The current instance
*
* @api
*/
public function replaceArgument($index, $argument)
{
if ($index < 0 || $index > count($this->arguments) - 1) {
throw new \OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, count($this->arguments) - 1));
}
$this->arguments[$index] = $argument;
return $this;
}
/**
* Gets the arguments to pass to the service constructor/factory method.
*
* @return array The array of arguments
*
* @api
*/
public function getArguments()
{
return $this->arguments;
}
/**
* Gets an argument to pass to the service constructor/factory method.
*
* @param integer $index
*
* @return mixed The argument value
*
* @api
*/
public function getArgument($index)
{
if ($index < 0 || $index > count($this->arguments) - 1) {
throw new \OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, count($this->arguments) - 1));
}
return $this->arguments[$index];
}
/**
* Sets the methods to call after service initialization.
*
* @param array $calls An array of method calls
*
* @return Definition The current instance
*
* @api
*/
public function setMethodCalls(array $calls = array())
{
$this->calls = array();
foreach ($calls as $call) {
$this->addMethodCall($call[0], $call[1]);
}
return $this;
}
/**
* Adds a method to call after service initialization.
*
* @param string $method The method name to call
* @param array $arguments An array of arguments to pass to the method call
*
* @return Definition The current instance
*
* @throws InvalidArgumentException on empty $method param
*
* @api
*/
public function addMethodCall($method, array $arguments = array())
{
if (empty($method)) {
throw new InvalidArgumentException(sprintf('Method name cannot be empty.'));
}
$this->calls[] = array($method, $arguments);
return $this;
}
/**
* Removes a method to call after service initialization.
*
* @param string $method The method name to remove
*
* @return Definition The current instance
*
* @api
*/
public function removeMethodCall($method)
{
foreach ($this->calls as $i => $call) {
if ($call[0] === $method) {
unset($this->calls[$i]);
break;
}
}
return $this;
}
/**
* Check if the current definition has a given method to call after service initialization.
*
* @param string $method The method name to search for
*
* @return Boolean
*
* @api
*/
public function hasMethodCall($method)
{
foreach ($this->calls as $call) {
if ($call[0] === $method) {
return true;
}
}
return false;
}
/**
* Gets the methods to call after service initialization.
*
* @return array An array of method calls
*
* @api
*/
public function getMethodCalls()
{
return $this->calls;
}
/**
* Sets tags for this definition
*
* @param array $tags
*
* @return Definition the current instance
*
* @api
*/
public function setTags(array $tags)
{
$this->tags = $tags;
return $this;
}
/**
* Returns all tags.
*
* @return array An array of tags
*
* @api
*/
public function getTags()
{
return $this->tags;
}
/**
* Gets a tag by name.
*
* @param string $name The tag name
*
* @return array An array of attributes
*
* @api
*/
public function getTag($name)
{
return isset($this->tags[$name]) ? $this->tags[$name] : array();
}
/**
* Adds a tag for this definition.
*
* @param string $name The tag name
* @param array $attributes An array of attributes
*
* @return Definition The current instance
*
* @api
*/
public function addTag($name, array $attributes = array())
{
$this->tags[$name][] = $attributes;
return $this;
}
/**
* Whether this definition has a tag with the given name
*
* @param string $name
*
* @return Boolean
*
* @api
*/
public function hasTag($name)
{
return isset($this->tags[$name]);
}
/**
* Clears the tags for this definition.
*
* @return Definition The current instance
*
* @api
*/
public function clearTags()
{
$this->tags = array();
return $this;
}
/**
* Sets a file to require before creating the service.
*
* @param string $file A full pathname to include
*
* @return Definition The current instance
*
* @api
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Gets the file to require before creating the service.
*
* @return string The full pathname to include
*
* @api
*/
public function getFile()
{
return $this->file;
}
/**
* Sets the scope of the service
*
* @param string $scope Whether the service must be shared or not
*
* @return Definition The current instance
*
* @api
*/
public function setScope($scope)
{
$this->scope = $scope;
return $this;
}
/**
* Returns the scope of the service
*
* @return string
*
* @api
*/
public function getScope()
{
return $this->scope;
}
/**
* Sets the visibility of this service.
*
* @param Boolean $boolean
*
* @return Definition The current instance
*
* @api
*/
public function setPublic($boolean)
{
$this->public = (Boolean) $boolean;
return $this;
}
/**
* Whether this service is public facing
*
* @return Boolean
*
* @api
*/
public function isPublic()
{
return $this->public;
}
/**
* Sets whether this definition is synthetic, that is not constructed by the
* container, but dynamically injected.
*
* @param Boolean $boolean
*
* @return Definition the current instance
*
* @api
*/
public function setSynthetic($boolean)
{
$this->synthetic = (Boolean) $boolean;
return $this;
}
/**
* Whether this definition is synthetic, that is not constructed by the
* container, but dynamically injected.
*
* @return Boolean
*
* @api
*/
public function isSynthetic()
{
return $this->synthetic;
}
/**
* Whether this definition is abstract, that means it merely serves as a
* template for other definitions.
*
* @param Boolean $boolean
*
* @return Definition the current instance
*
* @api
*/
public function setAbstract($boolean)
{
$this->abstract = (Boolean) $boolean;
return $this;
}
/**
* Whether this definition is abstract, that means it merely serves as a
* template for other definitions.
*
* @return Boolean
*
* @api
*/
public function isAbstract()
{
return $this->abstract;
}
/**
* Sets a configurator to call after the service is fully initialized.
*
* @param mixed $callable A PHP callable
*
* @return Definition The current instance
*
* @api
*/
public function setConfigurator($callable)
{
$this->configurator = $callable;
return $this;
}
/**
* Gets the configurator to call after the service is fully initialized.
*
* @return mixed The PHP callable to call
*
* @api
*/
public function getConfigurator()
{
return $this->configurator;
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection;
/**
* This definition decorates another definition.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
class DefinitionDecorator extends Definition
{
private $parent;
private $changes;
/**
* Constructor.
*
* @param Definition $parent The Definition instance to decorate.
*
* @api
*/
public function __construct($parent)
{
parent::__construct();
$this->parent = $parent;
$this->changes = array();
}
/**
* Returns the Definition being decorated.
*
* @return Definition
*
* @api
*/
public function getParent()
{
return $this->parent;
}
/**
* Returns all changes tracked for the Definition object.
*
* @return array An array of changes for this Definition
*
* @api
*/
public function getChanges()
{
return $this->changes;
}
/**
* {@inheritDoc}
*
* @api
*/
public function setClass($class)
{
$this->changes['class'] = true;
return parent::setClass($class);
}
/**
* {@inheritDoc}
*
* @api
*/
public function setFactoryClass($class)
{
$this->changes['factory_class'] = true;
return parent::setFactoryClass($class);
}
/**
* {@inheritDoc}
*
* @api
*/
public function setFactoryMethod($method)
{
$this->changes['factory_method'] = true;
return parent::setFactoryMethod($method);
}
/**
* {@inheritDoc}
*
* @api
*/
public function setFactoryService($service)
{
$this->changes['factory_service'] = true;
return parent::setFactoryService($service);
}
/**
* {@inheritDoc}
*
* @api
*/
public function setConfigurator($callable)
{
$this->changes['configurator'] = true;
return parent::setConfigurator($callable);
}
/**
* {@inheritDoc}
*
* @api
*/
public function setFile($file)
{
$this->changes['file'] = true;
return parent::setFile($file);
}
/**
* {@inheritDoc}
*
* @api
*/
public function setPublic($boolean)
{
$this->changes['public'] = true;
return parent::setPublic($boolean);
}
/**
* Gets an argument to pass to the service constructor/factory method.
*
* If replaceArgument() has been used to replace an argument, this method
* will return the replacement value.
*
* @param integer $index
*
* @return mixed The argument value
*
* @api
*/
public function getArgument($index)
{
if (array_key_exists('index_'.$index, $this->arguments)) {
return $this->arguments['index_'.$index];
}
$lastIndex = count(array_filter(array_keys($this->arguments), 'is_int')) - 1;
if ($index < 0 || $index > $lastIndex) {
throw new \OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, $lastIndex));
}
return $this->arguments[$index];
}
/**
* You should always use this method when overwriting existing arguments
* of the parent definition.
*
* If you directly call setArguments() keep in mind that you must follow
* certain conventions when you want to overwrite the arguments of the
* parent definition, otherwise your arguments will only be appended.
*
* @param integer $index
* @param mixed $value
*
* @return DefinitionDecorator the current instance
* @throws \InvalidArgumentException when $index isn't an integer
*
* @api
*/
public function replaceArgument($index, $value)
{
if (!is_int($index)) {
throw new \InvalidArgumentException('$index must be an integer.');
}
$this->arguments['index_'.$index] = $value;
return $this;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Dumper is the abstract class for all built-in dumpers.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
abstract class Dumper implements DumperInterface
{
protected $container;
/**
* Constructor.
*
* @param ContainerBuilder $container The service container to dump
*
* @api
*/
public function __construct(ContainerBuilder $container)
{
$this->container = $container;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Dumper;
/**
* DumperInterface is the interface implemented by service container dumper classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface DumperInterface
{
/**
* Dumps the service container.
*
* @param array $options An array of options
*
* @return string The representation of the service container
*
* @api
*/
function dump(array $options = array());
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* GraphvizDumper dumps a service container as a graphviz file.
*
* You can convert the generated dot file with the dot utility (http://www.graphviz.org/):
*
* dot -Tpng container.dot > foo.png
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class GraphvizDumper extends Dumper
{
private $nodes;
private $edges;
private $options = array(
'graph' => array('ratio' => 'compress'),
'node' => array('fontsize' => 11, 'fontname' => 'Arial', 'shape' => 'record'),
'edge' => array('fontsize' => 9, 'fontname' => 'Arial', 'color' => 'grey', 'arrowhead' => 'open', 'arrowsize' => 0.5),
'node.instance' => array('fillcolor' => '#9999ff', 'style' => 'filled'),
'node.definition' => array('fillcolor' => '#eeeeee'),
'node.missing' => array('fillcolor' => '#ff9999', 'style' => 'filled'),
);
/**
* Dumps the service container as a graphviz graph.
*
* Available options:
*
* * graph: The default options for the whole graph
* * node: The default options for nodes
* * edge: The default options for edges
* * node.instance: The default options for services that are defined directly by object instances
* * node.definition: The default options for services that are defined via service definition instances
* * node.missing: The default options for missing services
*
* @param array $options An array of options
*
* @return string The dot representation of the service container
*/
public function dump(array $options = array())
{
foreach (array('graph', 'node', 'edge', 'node.instance', 'node.definition', 'node.missing') as $key) {
if (isset($options[$key])) {
$this->options[$key] = array_merge($this->options[$key], $options[$key]);
}
}
$this->nodes = $this->findNodes();
$this->edges = array();
foreach ($this->container->getDefinitions() as $id => $definition) {
$this->edges[$id] = array_merge(
$this->findEdges($id, $definition->getArguments(), true, ''),
$this->findEdges($id, $definition->getProperties(), false, '')
);
foreach ($definition->getMethodCalls() as $call) {
$this->edges[$id] = array_merge(
$this->edges[$id],
$this->findEdges($id, $call[1], false, $call[0].'()')
);
}
}
return $this->startDot().$this->addNodes().$this->addEdges().$this->endDot();
}
/**
* Returns all nodes.
*
* @return string A string representation of all nodes
*/
private function addNodes()
{
$code = '';
foreach ($this->nodes as $id => $node) {
$aliases = $this->getAliases($id);
$code .= sprintf(" node_%s [label=\"%s\\n%s\\n\", shape=%s%s];\n", $this->dotize($id), $id.($aliases ? ' ('.implode(', ', $aliases).')' : ''), $node['class'], $this->options['node']['shape'], $this->addAttributes($node['attributes']));
}
return $code;
}
/**
* Returns all edges.
*
* @return string A string representation of all edges
*/
private function addEdges()
{
$code = '';
foreach ($this->edges as $id => $edges) {
foreach ($edges as $edge) {
$code .= sprintf(" node_%s -> node_%s [label=\"%s\" style=\"%s\"];\n", $this->dotize($id), $this->dotize($edge['to']), $edge['name'], $edge['required'] ? 'filled' : 'dashed');
}
}
return $code;
}
/**
* Finds all edges belonging to a specific service id.
*
* @param string $id The service id used to find edges
* @param array $arguments An array of arguments
* @param Boolean $required
* @param string $name
*
* @return array An array of edges
*/
private function findEdges($id, $arguments, $required, $name)
{
$edges = array();
foreach ($arguments as $argument) {
if (is_object($argument) && $argument instanceof Parameter) {
$argument = $this->container->hasParameter($argument) ? $this->container->getParameter($argument) : null;
} elseif (is_string($argument) && preg_match('/^%([^%]+)%$/', $argument, $match)) {
$argument = $this->container->hasParameter($match[1]) ? $this->container->getParameter($match[1]) : null;
}
if ($argument instanceof Reference) {
if (!$this->container->has((string) $argument)) {
$this->nodes[(string) $argument] = array('name' => $name, 'required' => $required, 'class' => '', 'attributes' => $this->options['node.missing']);
}
$edges[] = array('name' => $name, 'required' => $required, 'to' => $argument);
} elseif (is_array($argument)) {
$edges = array_merge($edges, $this->findEdges($id, $argument, $required, $name));
}
}
return $edges;
}
/**
* Finds all nodes.
*
* @return array An array of all nodes
*/
private function findNodes()
{
$nodes = array();
$container = clone $this->container;
foreach ($container->getDefinitions() as $id => $definition) {
$nodes[$id] = array('class' => str_replace('\\', '\\\\', $this->container->getParameterBag()->resolveValue($definition->getClass())), 'attributes' => array_merge($this->options['node.definition'], array('style' => ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope() ? 'filled' : 'dotted')));
$container->setDefinition($id, new Definition('stdClass'));
}
foreach ($container->getServiceIds() as $id) {
$service = $container->get($id);
if (in_array($id, array_keys($container->getAliases()))) {
continue;
}
if (!$container->hasDefinition($id)) {
$nodes[$id] = array('class' => str_replace('\\', '\\\\', get_class($service)), 'attributes' => $this->options['node.instance']);
}
}
return $nodes;
}
/**
* Returns the start dot.
*
* @return string The string representation of a start dot
*/
private function startDot()
{
return sprintf("digraph sc {\n %s\n node [%s];\n edge [%s];\n\n",
$this->addOptions($this->options['graph']),
$this->addOptions($this->options['node']),
$this->addOptions($this->options['edge'])
);
}
/**
* Returns the end dot.
*
* @return string
*/
private function endDot()
{
return "}\n";
}
/**
* Adds attributes
*
* @param array $attributes An array of attributes
*
* @return string A comma separated list of attributes
*/
private function addAttributes($attributes)
{
$code = array();
foreach ($attributes as $k => $v) {
$code[] = sprintf('%s="%s"', $k, $v);
}
return $code ? ', '.implode(', ', $code) : '';
}
/**
* Adds options
*
* @param array $options An array of options
*
* @return string A space separated list of options
*/
private function addOptions($options)
{
$code = array();
foreach ($options as $k => $v) {
$code[] = sprintf('%s="%s"', $k, $v);
}
return implode(' ', $code);
}
/**
* Dotizes an identifier.
*
* @param string $id The identifier to dotize
*
* @return string A dotized string
*/
private function dotize($id)
{
return strtolower(preg_replace('/[^\w]/i', '_', $id));
}
/**
* Compiles an array of aliases for a specified service id.
*
* @param string $id A service id
*
* @return array An array of aliases
*/
private function getAliases($id)
{
$aliases = array();
foreach ($this->container->getAliases() as $alias => $origin) {
if ($id == $origin) {
$aliases[] = $alias;
}
}
return $aliases;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Variable;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
/**
* PhpDumper dumps a service container as a PHP class.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
class PhpDumper extends Dumper
{
/**
* Characters that might appear in the generated variable name as first character
* @var string
*/
const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';
/**
* Characters that might appear in the generated variable name as any but the first character
* @var string
*/
const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';
private $inlinedDefinitions;
private $definitionVariables;
private $referenceVariables;
private $variableCount;
private $reservedVariables = array('instance', 'class');
/**
* {@inheritDoc}
*
* @api
*/
public function __construct(ContainerBuilder $container)
{
parent::__construct($container);
$this->inlinedDefinitions = new \SplObjectStorage;
}
/**
* Dumps the service container as a PHP class.
*
* Available options:
*
* * class: The class name
* * base_class: The base class name
*
* @param array $options An array of options
*
* @return string A PHP class representing of the service container
*
* @api
*/
public function dump(array $options = array())
{
$options = array_merge(array(
'class' => 'ProjectServiceContainer',
'base_class' => 'Container',
), $options);
$code = $this->startClass($options['class'], $options['base_class']);
if ($this->container->isFrozen()) {
$code .= $this->addFrozenConstructor();
} else {
$code .= $this->addConstructor();
}
$code .=
$this->addServices().
$this->addDefaultParametersMethod().
$this->endClass()
;
return $code;
}
/**
* Generates Service local temp variables.
*
* @param string $cId
* @param string $definition
*
* @return string
*/
private function addServiceLocalTempVariables($cId, $definition)
{
static $template = " \$%s = %s;\n";
$localDefinitions = array_merge(
array($definition),
$this->getInlinedDefinitions($definition)
);
$calls = $behavior = array();
foreach ($localDefinitions as $iDefinition) {
$this->getServiceCallsFromArguments($iDefinition->getArguments(), $calls, $behavior);
$this->getServiceCallsFromArguments($iDefinition->getMethodCalls(), $calls, $behavior);
$this->getServiceCallsFromArguments($iDefinition->getProperties(), $calls, $behavior);
}
$code = '';
foreach ($calls as $id => $callCount) {
if ('service_container' === $id || $id === $cId) {
continue;
}
if ($callCount > 1) {
$name = $this->getNextVariableName();
$this->referenceVariables[$id] = new Variable($name);
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id]) {
$code .= sprintf($template, $name, $this->getServiceCall($id));
} else {
$code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)));
}
}
}
if ('' !== $code) {
$code .= "\n";
}
return $code;
}
/**
* Generates the require_once statement for service includes.
*
* @param string $id The service id
* @param Definition $definition
*
* @return string
*/
private function addServiceInclude($id, $definition)
{
$template = " require_once %s;\n";
$code = '';
if (null !== $file = $definition->getFile()) {
$code .= sprintf($template, $this->dumpValue($file));
}
foreach ($this->getInlinedDefinitions($definition) as $definition) {
if (null !== $file = $definition->getFile()) {
$code .= sprintf($template, $this->dumpValue($file));
}
}
if ('' !== $code) {
$code .= "\n";
}
return $code;
}
/**
* Generates the inline definition of a service.
*
* @param string $id
* @param Definition $definition
*
* @return string
*/
private function addServiceInlinedDefinitions($id, $definition)
{
$code = '';
$variableMap = $this->definitionVariables;
$nbOccurrences = new \SplObjectStorage();
$processed = new \SplObjectStorage();
$inlinedDefinitions = $this->getInlinedDefinitions($definition);
foreach ($inlinedDefinitions as $definition) {
if (false === $nbOccurrences->contains($definition)) {
$nbOccurrences->offsetSet($definition, 1);
} else {
$i = $nbOccurrences->offsetGet($definition);
$nbOccurrences->offsetSet($definition, $i+1);
}
}
foreach ($inlinedDefinitions as $sDefinition) {
if ($processed->contains($sDefinition)) {
continue;
}
$processed->offsetSet($sDefinition);
$class = $this->dumpValue($sDefinition->getClass());
if ($nbOccurrences->offsetGet($sDefinition) > 1 || count($sDefinition->getMethodCalls()) > 0 || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) {
$name = $this->getNextVariableName();
$variableMap->offsetSet($sDefinition, new Variable($name));
// a construct like:
// $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a);
// this is an indication for a wrong implementation, you can circumvent this problem
// by setting up your service structure like this:
// $b = new ServiceB();
// $a = new ServiceA(ServiceB $b);
// $b->setServiceA(ServiceA $a);
if ($this->hasReference($id, $sDefinition->getArguments())) {
throw new ServiceCircularReferenceException($id, array($id));
}
$arguments = array();
foreach ($sDefinition->getArguments() as $argument) {
$arguments[] = $this->dumpValue($argument);
}
if (null !== $sDefinition->getFactoryMethod()) {
if (null !== $sDefinition->getFactoryClass()) {
$code .= sprintf(" \$%s = call_user_func(array(%s, '%s')%s);\n", $name, $this->dumpValue($sDefinition->getFactoryClass()), $sDefinition->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
} elseif (null !== $sDefinition->getFactoryService()) {
$code .= sprintf(" \$%s = %s->%s(%s);\n", $name, $this->getServiceCall($sDefinition->getFactoryService()), $sDefinition->getFactoryMethod(), implode(', ', $arguments));
} else {
throw new \RuntimeException('Factory service or factory class must be defined in service definition for '.$id);
}
} elseif (false !== strpos($class, '$')) {
$code .= sprintf(" \$class = %s;\n \$%s = new \$class(%s);\n", $class, $name, implode(', ', $arguments));
} else {
$code .= sprintf(" \$%s = new \\%s(%s);\n", $name, substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
}
if (!$this->hasReference($id, $sDefinition->getMethodCalls()) && !$this->hasReference($id, $sDefinition->getProperties())) {
$code .= $this->addServiceMethodCalls(null, $sDefinition, $name);
$code .= $this->addServiceProperties(null, $sDefinition, $name);
$code .= $this->addServiceConfigurator(null, $sDefinition, $name);
}
$code .= "\n";
}
}
return $code;
}
/**
* Adds the service return statement.
*
* @param string $id Service id
* @param Definition $definition
*
* @return string
*/
private function addServiceReturn($id, $definition)
{
if ($this->isSimpleInstance($id, $definition)) {
return " }\n";
}
return "\n return \$instance;\n }\n";
}
/**
* Generates the service instance.
*
* @param string $id
* @param Definition $definition
*
* @return string
*
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
private function addServiceInstance($id, $definition)
{
$class = $this->dumpValue($definition->getClass());
if (0 === strpos($class, "'") && !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
throw new \InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
}
$arguments = array();
foreach ($definition->getArguments() as $value) {
$arguments[] = $this->dumpValue($value);
}
$simple = $this->isSimpleInstance($id, $definition);
$instantiation = '';
if (ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) {
$instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
} elseif (ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
$instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
} elseif (!$simple) {
$instantiation = '$instance';
}
$return = '';
if ($simple) {
$return = 'return ';
} else {
$instantiation .= ' = ';
}
if (null !== $definition->getFactoryMethod()) {
if (null !== $definition->getFactoryClass()) {
$code = sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass()), $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : '');
} elseif (null !== $definition->getFactoryService()) {
$code = sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments));
} else {
throw new \RuntimeException('Factory method requires a factory service or factory class in service definition for '.$id);
}
} elseif (false !== strpos($class, '$')) {
$code = sprintf(" \$class = %s;\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments));
} else {
$code = sprintf(" $return{$instantiation}new \\%s(%s);\n", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
}
if (!$simple) {
$code .= "\n";
}
return $code;
}
/**
* Checks if the definition is a simple instance.
*
* @param string $id
* @param Definition $definition
*
* @return Boolean
*/
private function isSimpleInstance($id, $definition)
{
foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
continue;
}
if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator()) {
return false;
}
}
return true;
}
/**
* Adds method calls to a service definition.
*
* @param string $id
* @param Definition $definition
* @param string $variableName
*
* @return string
*/
private function addServiceMethodCalls($id, $definition, $variableName = 'instance')
{
$calls = '';
foreach ($definition->getMethodCalls() as $call) {
$arguments = array();
foreach ($call[1] as $value) {
$arguments[] = $this->dumpValue($value);
}
$calls .= $this->wrapServiceConditionals($call[1], sprintf(" \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments)));
}
return $calls;
}
private function addServiceProperties($id, $definition, $variableName = 'instance')
{
$code = '';
foreach ($definition->getProperties() as $name => $value) {
$code .= sprintf(" \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
}
return $code;
}
/**
* Generates the inline definition setup.
*
* @param string $id
* @param Definition $definition
* @return string
*/
private function addServiceInlinedDefinitionsSetup($id, $definition)
{
$this->referenceVariables[$id] = new Variable('instance');
$code = '';
$processed = new \SplObjectStorage();
foreach ($this->getInlinedDefinitions($definition) as $iDefinition) {
if ($processed->contains($iDefinition)) {
continue;
}
$processed->offsetSet($iDefinition);
if (!$this->hasReference($id, $iDefinition->getMethodCalls())) {
continue;
}
if ($iDefinition->getMethodCalls()) {
$code .= $this->addServiceMethodCalls(null, $iDefinition, (string) $this->definitionVariables->offsetGet($iDefinition));
}
if ($iDefinition->getConfigurator()) {
$code .= $this->addServiceConfigurator(null, $iDefinition, (string) $this->definitionVariables->offsetGet($iDefinition));
}
}
if ('' !== $code) {
$code .= "\n";
}
return $code;
}
/**
* Adds configurator definition
*
* @param string $id
* @param Definition $definition
* @param string $variableName
*
* @return string
*/
private function addServiceConfigurator($id, $definition, $variableName = 'instance')
{
if (!$callable = $definition->getConfigurator()) {
return '';
}
if (is_array($callable)) {
if (is_object($callable[0]) && $callable[0] instanceof Reference) {
return sprintf(" %s->%s(\$%s);\n", $this->getServiceCall((string) $callable[0]), $callable[1], $variableName);
}
return sprintf(" call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
}
return sprintf(" %s(\$%s);\n", $callable, $variableName);
}
/**
* Adds a service
*
* @param string $id
* @param Definition $definition
*
* @return string
*/
private function addService($id, $definition)
{
$name = Container::camelize($id);
$this->definitionVariables = new \SplObjectStorage();
$this->referenceVariables = array();
$this->variableCount = 0;
$return = '';
if ($definition->isSynthetic()) {
$return = sprintf('@throws \RuntimeException always since this service is expected to be injected dynamically');
} elseif ($class = $definition->getClass()) {
$return = sprintf("@return %s A %s instance.", 0 === strpos($class, '%') ? 'Object' : $class, $class);
} elseif ($definition->getFactoryClass()) {
$return = sprintf('@return Object An instance returned by %s::%s().', $definition->getFactoryClass(), $definition->getFactoryMethod());
} elseif ($definition->getFactoryService()) {
$return = sprintf('@return Object An instance returned by %s::%s().', $definition->getFactoryService(), $definition->getFactoryMethod());
}
$doc = '';
if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) {
$doc .= <<<EOF
*
* This service is shared.
* This method always returns the same instance of the service.
EOF;
}
if (!$definition->isPublic()) {
$doc .= <<<EOF
*
* This service is private.
* If you want to be able to request this service from the container directly,
* make it public, otherwise you might end up with broken code.
EOF;
}
$code = <<<EOF
/**
* Gets the '$id' service.$doc
*
* $return
*/
protected function get{$name}Service()
{
EOF;
$scope = $definition->getScope();
if (ContainerInterface::SCOPE_CONTAINER !== $scope && ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
$code .= <<<EOF
if (!isset(\$this->scopedServices['$scope'])) {
throw new InactiveScopeException('$id', '$scope');
}
EOF;
}
if ($definition->isSynthetic()) {
$code .= sprintf(" throw new \RuntimeException('You have requested a synthetic service (\"%s\"). The DIC does not know how to construct this service.');\n }\n", $id);
} else {
$code .=
$this->addServiceInclude($id, $definition).
$this->addServiceLocalTempVariables($id, $definition).
$this->addServiceInlinedDefinitions($id, $definition).
$this->addServiceInstance($id, $definition).
$this->addServiceInlinedDefinitionsSetup($id, $definition).
$this->addServiceMethodCalls($id, $definition).
$this->addServiceProperties($id, $definition).
$this->addServiceConfigurator($id, $definition).
$this->addServiceReturn($id, $definition)
;
}
$this->definitionVariables = null;
$this->referenceVariables = null;
return $code;
}
/**
* Adds a service alias.
*
* @param string $alias
* @param string $id
*
* @return string
*/
private function addServiceAlias($alias, $id)
{
$name = Container::camelize($alias);
$type = 'Object';
if ($this->container->hasDefinition($id)) {
$class = $this->container->getDefinition($id)->getClass();
$type = 0 === strpos($class, '%') ? 'Object' : $class;
}
return <<<EOF
/**
* Gets the $alias service alias.
*
* @return $type An instance of the $id service
*/
protected function get{$name}Service()
{
return {$this->getServiceCall($id)};
}
EOF;
}
/**
* Adds multiple services
*
* @return string
*/
private function addServices()
{
$publicServices = $privateServices = $aliasServices = '';
$definitions = $this->container->getDefinitions();
ksort($definitions);
foreach ($definitions as $id => $definition) {
if ($definition->isPublic()) {
$publicServices .= $this->addService($id, $definition);
} else {
$privateServices .= $this->addService($id, $definition);
}
}
$aliases = $this->container->getAliases();
ksort($aliases);
foreach ($aliases as $alias => $id) {
$aliasServices .= $this->addServiceAlias($alias, $id);
}
return $publicServices.$aliasServices.$privateServices;
}
/**
* Adds the class headers.
*
* @param string $class Class name
* @param string $baseClass The name of the base class
*
* @return string
*/
private function startClass($class, $baseClass)
{
$bagClass = $this->container->isFrozen() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';
return <<<EOF
<?php
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
$bagClass
/**
* $class
*
* This class has been auto-generated
* by the Symfony Dependency Injection Component.
*/
class $class extends $baseClass
{
EOF;
}
/**
* Adds the constructor.
*
* @return string
*/
private function addConstructor()
{
$arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null;
$code = <<<EOF
/**
* Constructor.
*/
public function __construct()
{
parent::__construct($arguments);
EOF;
if (count($scopes = $this->container->getScopes()) > 0) {
$code .= "\n";
$code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n";
$code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
}
$code .= <<<EOF
}
EOF;
return $code;
}
/**
* Adds the constructor for a frozen container.
*
* @return string
*/
private function addFrozenConstructor()
{
$code = <<<EOF
/**
* Constructor.
*/
public function __construct()
{
\$this->parameters = \$this->getDefaultParameters();
\$this->services =
\$this->scopedServices =
\$this->scopeStacks = array();
\$this->set('service_container', \$this);
EOF;
$code .= "\n";
if (count($scopes = $this->container->getScopes()) > 0) {
$code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n";
$code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
} else {
$code .= " \$this->scopes = array();\n";
$code .= " \$this->scopeChildren = array();\n";
}
$code .= <<<EOF
}
EOF;
return $code;
}
/**
* Adds default parameters method.
*
* @return string
*/
private function addDefaultParametersMethod()
{
if (!$this->container->getParameterBag()->all()) {
return '';
}
$parameters = $this->exportParameters($this->container->getParameterBag()->all());
$code = '';
if ($this->container->isFrozen()) {
$code .= <<<EOF
/**
* {@inheritdoc}
*/
public function getParameter(\$name)
{
\$name = strtolower(\$name);
if (!array_key_exists(\$name, \$this->parameters)) {
throw new \InvalidArgumentException(sprintf('The parameter "%s" must be defined.', \$name));
}
return \$this->parameters[\$name];
}
/**
* {@inheritdoc}
*/
public function hasParameter(\$name)
{
return array_key_exists(strtolower(\$name), \$this->parameters);
}
/**
* {@inheritdoc}
*/
public function setParameter(\$name, \$value)
{
throw new \LogicException('Impossible to call set() on a frozen ParameterBag.');
}
/**
* {@inheritDoc}
*/
public function getParameterBag()
{
if (null === \$this->parameterBag) {
\$this->parameterBag = new FrozenParameterBag(\$this->parameters);
}
return \$this->parameterBag;
}
EOF;
}
$code .= <<<EOF
/**
* Gets the default parameters.
*
* @return array An array of the default parameters
*/
protected function getDefaultParameters()
{
return $parameters;
}
EOF;
return $code;
}
/**
* Exports parameters.
*
* @param array $parameters
* @param string $path
* @param integer $indent
*
* @return string
*/
private function exportParameters($parameters, $path = '', $indent = 12)
{
$php = array();
foreach ($parameters as $key => $value) {
if (is_array($value)) {
$value = $this->exportParameters($value, $path.'/'.$key, $indent + 4);
} elseif ($value instanceof Variable) {
throw new \InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
} elseif ($value instanceof Definition) {
throw new \InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain service definitions. Definition for "%s" found in "%s".', $value->getClass(), $path.'/'.$key));
} elseif ($value instanceof Reference) {
throw new \InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain references to other services (reference to service "%s" found in "%s").', $value, $path.'/'.$key));
} else {
$value = var_export($value, true);
}
$php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), var_export($key, true), $value);
}
return sprintf("array(\n%s\n%s)", implode("\n", $php), str_repeat(' ', $indent - 4));
}
/**
* Ends the class definition.
*
* @return string
*/
private function endClass()
{
return <<<EOF
}
EOF;
}
/**
* Wraps the service conditionals.
*
* @param string $value
* @param string $code
*
* @return string
*/
private function wrapServiceConditionals($value, $code)
{
if (!$services = ContainerBuilder::getServiceConditionals($value)) {
return $code;
}
$conditions = array();
foreach ($services as $service) {
$conditions[] = sprintf("\$this->has('%s')", $service);
}
// re-indent the wrapped code
$code = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code)));
return sprintf(" if (%s) {\n%s }\n", implode(' && ', $conditions), $code);
}
/**
* Builds service calls from arguments
*
* @param array $arguments
* @param string &$calls By reference
* @param string &$behavior By reference
*
* @return void
*/
private function getServiceCallsFromArguments(array $arguments, array &$calls, array &$behavior)
{
foreach ($arguments as $argument) {
if (is_array($argument)) {
$this->getServiceCallsFromArguments($argument, $calls, $behavior);
} elseif ($argument instanceof Reference) {
$id = (string) $argument;
if (!isset($calls[$id])) {
$calls[$id] = 0;
}
if (!isset($behavior[$id])) {
$behavior[$id] = $argument->getInvalidBehavior();
} elseif (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $behavior[$id]) {
$behavior[$id] = $argument->getInvalidBehavior();
}
$calls[$id] += 1;
}
}
}
/**
* Returns the inline definition
*
* @param Definition $definition
*
* @return array
*/
private function getInlinedDefinitions(Definition $definition)
{
if (false === $this->inlinedDefinitions->contains($definition)) {
$definitions = array_merge(
$this->getDefinitionsFromArguments($definition->getArguments()),
$this->getDefinitionsFromArguments($definition->getMethodCalls()),
$this->getDefinitionsFromArguments($definition->getProperties())
);
$this->inlinedDefinitions->offsetSet($definition, $definitions);
return $definitions;
}
return $this->inlinedDefinitions->offsetGet($definition);
}
/**
* Gets the definition from arguments
*
* @param array $arguments
*
* @return array
*/
private function getDefinitionsFromArguments(array $arguments)
{
$definitions = array();
foreach ($arguments as $argument) {
if (is_array($argument)) {
$definitions = array_merge($definitions, $this->getDefinitionsFromArguments($argument));
} elseif ($argument instanceof Definition) {
$definitions = array_merge(
$definitions,
$this->getInlinedDefinitions($argument),
array($argument)
);
}
}
return $definitions;
}
/**
* Checks if a service id has a reference
*
* @param string $id
* @param array $arguments
*
* @return Boolean
*/
private function hasReference($id, array $arguments)
{
foreach ($arguments as $argument) {
if (is_array($argument)) {
if ($this->hasReference($id, $argument)) {
return true;
}
} elseif ($argument instanceof Reference) {
if ($id === (string) $argument) {
return true;
}
}
}
return false;
}
/**
* Dumps values.
*
* @param array $value
* @param Boolean $interpolate
*
* @return string
*/
private function dumpValue($value, $interpolate = true)
{
if (is_array($value)) {
$code = array();
foreach ($value as $k => $v) {
$code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
}
return sprintf('array(%s)', implode(', ', $code));
} elseif (is_object($value) && $value instanceof Definition) {
if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
return $this->dumpValue($this->definitionVariables->offsetGet($value), $interpolate);
}
if (count($value->getMethodCalls()) > 0) {
throw new \RuntimeException('Cannot dump definitions which have method calls.');
}
if (null !== $value->getConfigurator()) {
throw new \RuntimeException('Cannot dump definitions which have a configurator.');
}
$arguments = array();
foreach ($value->getArguments() as $argument) {
$arguments[] = $this->dumpValue($argument);
}
$class = $this->dumpValue($value->getClass());
if (false !== strpos($class, '$')) {
throw new \RuntimeException('Cannot dump definitions which have a variable class name.');
}
if (null !== $value->getFactoryMethod()) {
if (null !== $value->getFactoryClass()) {
return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass()), $value->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
} elseif (null !== $value->getFactoryService()) {
return sprintf("%s->%s(%s)", $this->getServiceCall($value->getFactoryService()), $value->getFactoryMethod(), implode(', ', $arguments));
} else {
throw new \RuntimeException('Cannot dump definitions which have factory method without factory service or factory class.');
}
}
return sprintf("new \\%s(%s)", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
} elseif (is_object($value) && $value instanceof Variable) {
return '$'.$value;
} elseif (is_object($value) && $value instanceof Reference) {
if (null !== $this->referenceVariables && isset($this->referenceVariables[$id = (string) $value])) {
return $this->dumpValue($this->referenceVariables[$id], $interpolate);
}
return $this->getServiceCall((string) $value, $value);
} elseif (is_object($value) && $value instanceof Parameter) {
return $this->dumpParameter($value);
} elseif (true === $interpolate && is_string($value)) {
if (preg_match('/^%([^%]+)%$/', $value, $match)) {
// we do this to deal with non string values (Boolean, integer, ...)
// the preg_replace_callback converts them to strings
return $this->dumpParameter(strtolower($match[1]));
} else {
$that = $this;
$replaceParameters = function ($match) use ($that) {
return "'.".$that->dumpParameter(strtolower($match[2])).".'";
};
$code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, var_export($value, true)));
// optimize string
$code = preg_replace(array("/^''\./", "/\.''$/", "/(\w+)(?:'\.')/", "/(.+)(?:\.''\.)/"), array('', '', '$1', '$1.'), $code);
return $code;
}
} elseif (is_object($value) || is_resource($value)) {
throw new \RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
} else {
return var_export($value, true);
}
}
/**
* Dumps a parameter
*
* @param string $name
*
* @return string
*/
public function dumpParameter($name)
{
if ($this->container->isFrozen() && $this->container->hasParameter($name)) {
return $this->dumpValue($this->container->getParameter($name), false);
}
return sprintf("\$this->getParameter('%s')", strtolower($name));
}
/**
* Gets a service call
*
* @param string $id
* @param Reference $reference
*
* @return string
*/
private function getServiceCall($id, Reference $reference = null)
{
if ('service_container' === $id) {
return '$this';
}
if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
return sprintf('$this->get(\'%s\', ContainerInterface::NULL_ON_INVALID_REFERENCE)', $id);
} else {
if ($this->container->hasAlias($id)) {
$id = (string) $this->container->getAlias($id);
}
return sprintf('$this->get(\'%s\')', $id);
}
}
/**
* Returns the next name to use
*
* @return string
*/
private function getNextVariableName()
{
$firstChars = self::FIRST_CHARS;
$firstCharsLength = strlen($firstChars);
$nonFirstChars = self::NON_FIRST_CHARS;
$nonFirstCharsLength = strlen($nonFirstChars);
while (true) {
$name = '';
$i = $this->variableCount;
if ('' === $name) {
$name .= $firstChars[$i%$firstCharsLength];
$i = intval($i/$firstCharsLength);
}
while ($i > 0) {
$i -= 1;
$name .= $nonFirstChars[$i%$nonFirstCharsLength];
$i = intval($i/$nonFirstCharsLength);
}
$this->variableCount += 1;
// check that the name is not reserved
if (in_array($name, $this->reservedVariables, true)) {
continue;
}
return $name;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
/**
* XmlDumper dumps a service container as an XML string.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Martin Hasoň <martin.hason@gmail.com>
*
* @api
*/
class XmlDumper extends Dumper
{
/**
* @var \DOMDocument
*/
private $document;
/**
* Dumps the service container as an XML string.
*
* @param array $options An array of options
*
* @return string An xml string representing of the service container
*
* @api
*/
public function dump(array $options = array())
{
$this->document = new \DOMDocument('1.0', 'utf-8');
$this->document->formatOutput = true;
$container = $this->document->createElementNS('http://symfony.com/schema/dic/services', 'container');
$container->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$container->setAttribute('xsi:schemaLocation', 'http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd');
$this->addParameters($container);
$this->addServices($container);
$this->document->appendChild($container);
$xml = $this->document->saveXML();
$this->document = null;
return $xml;
}
/**
* Adds parameters.
*
* @param DOMElement $parent
*
* @return void
*/
private function addParameters(\DOMElement $parent)
{
$data = $this->container->getParameterBag()->all();
if (!$data) {
return;
}
if ($this->container->isFrozen()) {
$data = $this->escape($data);
}
$parameters = $this->document->createElement('parameters');
$parent->appendChild($parameters);
$this->convertParameters($data, 'parameter', $parameters);
}
/**
* Adds method calls.
*
* @param array $methodcalls
* @param DOMElement $parent
*
* @return void
*/
private function addMethodCalls(array $methodcalls, \DOMElement $parent)
{
foreach ($methodcalls as $methodcall) {
$call = $this->document->createElement('call');
$call->setAttribute('method', $methodcall[0]);
if (count($methodcall[1])) {
$this->convertParameters($methodcall[1], 'argument', $call);
}
$parent->appendChild($call);
}
}
/**
* Adds a service.
*
* @param Definition $definition
* @param string $id
* @param DOMElement $parent
*
* @return void
*/
private function addService($definition, $id, \DOMElement $parent)
{
$service = $this->document->createElement('service');
if (null !== $id) {
$service->setAttribute('id', $id);
}
if ($definition->getClass()) {
$service->setAttribute('class', $definition->getClass());
}
if ($definition->getFactoryMethod()) {
$service->setAttribute('factory-method', $definition->getFactoryMethod());
}
if ($definition->getFactoryService()) {
$service->setAttribute('factory-service', $definition->getFactoryService());
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
$service->setAttribute('scope', $scope);
}
if (!$definition->isPublic()) {
$service->setAttribute('public', 'false');
}
foreach ($definition->getTags() as $name => $tags) {
foreach ($tags as $attributes) {
$tag = $this->document->createElement('tag');
$tag->setAttribute('name', $name);
foreach ($attributes as $key => $value) {
$tag->setAttribute($key, $value);
}
$service->appendChild($tag);
}
}
if ($definition->getFile()) {
$file = $this->document->createElement('file');
$file->appendChild($this->document->createTextNode($definition->getFile()));
$service->appendChild($file);
}
if ($parameters = $definition->getArguments()) {
$this->convertParameters($parameters, 'argument', $service);
}
if ($parameters = $definition->getProperties()) {
$this->convertParameters($parameters, 'property', $service, 'name');
}
$this->addMethodCalls($definition->getMethodCalls(), $service);
if ($callable = $definition->getConfigurator()) {
$configurator = $this->document->createElement('configurator');
if (is_array($callable)) {
$configurator->setAttribute((is_object($callable[0]) && $callable[0] instanceof Reference ? 'service' : 'class'), $callable[0]);
$configurator->setAttribute('method', $callable[1]);
} else {
$configurator->setAttribute('function', $callable);
}
$service->appendChild($configurator);
}
$parent->appendChild($service);
}
/**
* Adds a service alias.
*
* @param string $alias
* @param string $id
* @param DOMElement $parent
*
* @return void
*/
private function addServiceAlias($alias, $id, \DOMElement $parent)
{
$service = $this->document->createElement('service');
$service->setAttribute('id', $alias);
$service->setAttribute('alias', $id);
if (!$id->isPublic()) {
$service->setAttribute('public', 'false');
}
$parent->appendChild($service);
}
/**
* Adds services.
*
* @param DOMElement $parent
*
* @return void
*/
private function addServices(\DOMElement $parent)
{
$definitions = $this->container->getDefinitions();
if (!$definitions) {
return;
}
$services = $this->document->createElement('services');
foreach ($definitions as $id => $definition) {
$this->addService($definition, $id, $services);
}
foreach ($this->container->getAliases() as $alias => $id) {
$this->addServiceAlias($alias, $id, $services);
}
$parent->appendChild($services);
}
/**
* Converts parameters.
*
* @param array $parameters
* @param string $type
* @param DOMElement $parent
* @param string $keyAttribute
*
* @return void
*/
private function convertParameters($parameters, $type, \DOMElement $parent, $keyAttribute = 'key')
{
$withKeys = array_keys($parameters) !== range(0, count($parameters) - 1);
foreach ($parameters as $key => $value) {
$element = $this->document->createElement($type);
if ($withKeys) {
$element->setAttribute($keyAttribute, $key);
}
if (is_array($value)) {
$element->setAttribute('type', 'collection');
$this->convertParameters($value, $type, $element, 'key');
} elseif (is_object($value) && $value instanceof Reference) {
$element->setAttribute('type', 'service');
$element->setAttribute('id', (string) $value);
$behaviour = $value->getInvalidBehavior();
if ($behaviour == ContainerInterface::NULL_ON_INVALID_REFERENCE) {
$element->setAttribute('on-invalid', 'null');
} elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
$element->setAttribute('on-invalid', 'ignore');
}
} elseif (is_object($value) && $value instanceof Definition) {
$element->setAttribute('type', 'service');
$this->addService($value, null, $element);
} else {
if (in_array($value, array('null', 'true', 'false'), true)) {
$element->setAttribute('type', 'string');
}
$text = $this->document->createTextNode(self::phpToXml($value));
$element->appendChild($text);
}
$parent->appendChild($element);
}
}
/**
* Escapes arguments
*
* @param array $arguments
*
* @return array
*/
private function escape($arguments)
{
$args = array();
foreach ($arguments as $k => $v) {
if (is_array($v)) {
$args[$k] = $this->escape($v);
} elseif (is_string($v)) {
$args[$k] = str_replace('%', '%%', $v);
} else {
$args[$k] = $v;
}
}
return $args;
}
/**
* Converts php types to xml types.
*
* @param mixed $value Value to convert
*
* @throws \RuntimeException When trying to dump object or resource
*/
static public function phpToXml($value)
{
switch (true) {
case null === $value:
return 'null';
case true === $value:
return 'true';
case false === $value:
return 'false';
case is_object($value) && $value instanceof Parameter:
return '%'.$value.'%';
case is_object($value) || is_resource($value):
throw new \RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
default:
return (string) $value;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Dumper;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
/**
* YamlDumper dumps a service container as a YAML string.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class YamlDumper extends Dumper
{
/**
* Dumps the service container as an YAML string.
*
* @param array $options An array of options
*
* @return string A YAML string representing of the service container
*
* @api
*/
public function dump(array $options = array())
{
return $this->addParameters()."\n".$this->addServices();
}
/**
* Adds a service
*
* @param string $id
* @param Definition $definition
*
* @return string
*/
private function addService($id, $definition)
{
$code = " $id:\n";
if ($definition->getClass()) {
$code .= sprintf(" class: %s\n", $definition->getClass());
}
$tagsCode = '';
foreach ($definition->getTags() as $name => $tags) {
foreach ($tags as $attributes) {
$att = array();
foreach ($attributes as $key => $value) {
$att[] = sprintf('%s: %s', Yaml::dump($key), Yaml::dump($value));
}
$att = $att ? ', '.implode(' ', $att) : '';
$tagsCode .= sprintf(" - { name: %s%s }\n", Yaml::dump($name), $att);
}
}
if ($tagsCode) {
$code .= " tags:\n".$tagsCode;
}
if ($definition->getFile()) {
$code .= sprintf(" file: %s\n", $definition->getFile());
}
if ($definition->getFactoryMethod()) {
$code .= sprintf(" factory_method: %s\n", $definition->getFactoryMethod());
}
if ($definition->getFactoryService()) {
$code .= sprintf(" factory_service: %s\n", $definition->getFactoryService());
}
if ($definition->getArguments()) {
$code .= sprintf(" arguments: %s\n", Yaml::dump($this->dumpValue($definition->getArguments()), 0));
}
if ($definition->getProperties()) {
$code .= sprintf(" properties: %s\n", Yaml::dump($this->dumpValue($definition->getProperties()), 0));
}
if ($definition->getMethodCalls()) {
$code .= sprintf(" calls:\n %s\n", str_replace("\n", "\n ", Yaml::dump($this->dumpValue($definition->getMethodCalls()), 1)));
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
$code .= sprintf(" scope: %s\n", $scope);
}
if ($callable = $definition->getConfigurator()) {
if (is_array($callable)) {
if (is_object($callable[0]) && $callable[0] instanceof Reference) {
$callable = array($this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]);
} else {
$callable = array($callable[0], $callable[1]);
}
}
$code .= sprintf(" configurator: %s\n", Yaml::dump($callable, 0));
}
return $code;
}
/**
* Adds a service alias
*
* @param string $alias
* @param string $id
*
* @return string
*/
private function addServiceAlias($alias, $id)
{
if ($id->isPublic()) {
return sprintf(" %s: @%s\n", $alias, $id);
} else {
return sprintf(" %s:\n alias: %s\n public: false", $alias, $id);
}
}
/**
* Adds services
*
* @return string
*/
private function addServices()
{
if (!$this->container->getDefinitions()) {
return '';
}
$code = "services:\n";
foreach ($this->container->getDefinitions() as $id => $definition) {
$code .= $this->addService($id, $definition);
}
foreach ($this->container->getAliases() as $alias => $id) {
$code .= $this->addServiceAlias($alias, $id);
}
return $code;
}
/**
* Adds parameters
*
* @return string
*/
private function addParameters()
{
if (!$this->container->getParameterBag()->all()) {
return '';
}
if ($this->container->isFrozen()) {
$parameters = $this->prepareParameters($this->container->getParameterBag()->all());
} else {
$parameters = $this->container->getParameterBag()->all();
}
return Yaml::dump(array('parameters' => $parameters), 2);
}
/**
* Dumps the value to YAML format
*
* @param mixed $value
*
* @throws \RuntimeException When trying to dump object or resource
*/
private function dumpValue($value)
{
if (is_array($value)) {
$code = array();
foreach ($value as $k => $v) {
$code[$k] = $this->dumpValue($v);
}
return $code;
} elseif (is_object($value) && $value instanceof Reference) {
return $this->getServiceCall((string) $value, $value);
} elseif (is_object($value) && $value instanceof Parameter) {
return $this->getParameterCall((string) $value);
} elseif (is_object($value) || is_resource($value)) {
throw new \RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
}
return $value;
}
/**
* Gets the service call.
*
* @param string $id
* @param Reference $reference
*
* @return string
*/
private function getServiceCall($id, Reference $reference = null)
{
if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
return sprintf('@?%s', $id);
}
return sprintf('@%s', $id);
}
/**
* Gets parameter call.
*
* @param string $id
*
* @return string
*/
private function getParameterCall($id)
{
return sprintf('%%%s%%', $id);
}
/**
* Prepares parameters
*
* @param array $parameters
*
* @return array
*/
private function prepareParameters($parameters)
{
$filtered = array();
foreach ($parameters as $key => $value) {
if (is_array($value)) {
$value = $this->prepareParameters($value);
} elseif ($value instanceof Reference) {
$value = '@'.$value;
}
$filtered[$key] = $value;
}
return $this->escape($filtered);
}
/**
* Escapes arguments
*
* @param array $arguments
*
* @return array
*/
private function escape($arguments)
{
$args = array();
foreach ($arguments as $k => $v) {
if (is_array($v)) {
$args[$k] = $this->escape($v);
} elseif (is_string($v)) {
$args[$k] = str_replace('%', '%%', $v);
} else {
$args[$k] = $v;
}
}
return $args;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* ExceptionInterface
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
*/
interface ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* This exception is thrown when you try to create a service of an inactive scope.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class InactiveScopeException extends RuntimeException
{
private $serviceId;
private $scope;
public function __construct($serviceId, $scope)
{
parent::__construct(sprintf('You cannot create a service ("%s") of an inactive scope ("%s").', $serviceId, $scope));
$this->serviceId = $serviceId;
$this->scope = $scope;
}
public function getServiceId()
{
return $this->serviceId;
}
public function getScope()
{
return $this->scope;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Exception;
use \InvalidArgumentException as BaseInvalidArgumentException;
/**
* InvalidArgumentException
*
* @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
*/
class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* This exception is thrown when a circular reference in a parameter is detected.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ParameterCircularReferenceException extends RuntimeException
{
private $parameters;
public function __construct($parameters)
{
parent::__construct(sprintf('Circular reference detected for parameter "%s" ("%s" > "%s").', $parameters[0], implode('" > "', $parameters), $parameters[0]));
$this->parameters = $parameters;
}
public function getParameters()
{
return $this->parameters;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* This exception is thrown when a non-existent parameter is used.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ParameterNotFoundException extends InvalidArgumentException
{
private $key;
private $sourceId;
private $sourceKey;
/**
* Constructor.
*
* @param string $key The requested parameter key
* @param string $sourceId The service id that references the non-existent parameter
* @param string $sourceKey The parameter key that references the non-existent parameter
*/
public function __construct($key, $sourceId = null, $sourceKey = null)
{
$this->key = $key;
$this->sourceId = $sourceId;
$this->sourceKey = $sourceKey;
$this->updateRepr();
}
public function updateRepr()
{
if (null !== $this->sourceId) {
$this->message = sprintf('The service "%s" has a dependency on a non-existent parameter "%s".', $this->sourceId, $this->key);
} elseif (null !== $this->sourceKey) {
$this->message = sprintf('The parameter "%s" has a dependency on a non-existent parameter "%s".', $this->sourceKey, $this->key);
} else {
$this->message = sprintf('You have requested a non-existent parameter "%s".', $this->key);
}
}
public function getKey()
{
return $this->key;
}
public function getSourceId()
{
return $this->sourceId;
}
public function getSourceKey()
{
return $this->sourceKey;
}
public function setSourceId($sourceId)
{
$this->sourceId = $sourceId;
$this->updateRepr();
}
public function setSourceKey($sourceKey)
{
$this->sourceKey = $sourceKey;
$this->updateRepr();
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* Base RuntimeException for Dependency Injection Component.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* This exception is thrown when the a scope crossing injection is detected.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ScopeCrossingInjectionException extends RuntimeException
{
private $sourceServiceId;
private $sourceScope;
private $destServiceId;
private $destScope;
public function __construct($sourceServiceId, $sourceScope, $destServiceId, $destScope)
{
parent::__construct(sprintf(
'Scope Crossing Injection detected: The definition "%s" references the service "%s" which belongs to another scope hierarchy. '
.'This service might not be available consistently. Generally, it is safer to either move the definition "%s" to scope "%s", or '
.'declare "%s" as a child scope of "%s". If you can be sure that the other scope is always active, you can set the reference to strict=false to get rid of this error.',
$sourceServiceId,
$destServiceId,
$sourceServiceId,
$destScope,
$sourceScope,
$destScope
));
$this->sourceServiceId = $sourceServiceId;
$this->sourceScope = $sourceScope;
$this->destServiceId = $destServiceId;
$this->destScope = $destScope;
}
public function getSourceServiceId()
{
return $this->sourceServiceId;
}
public function getSourceScope()
{
return $this->sourceScope;
}
public function getDestServiceId()
{
return $this->destServiceId;
}
public function getDestScope()
{
return $this->destScope;
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* Thrown when a scope widening injection is detected.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ScopeWideningInjectionException extends RuntimeException
{
private $sourceServiceId;
private $sourceScope;
private $destServiceId;
private $destScope;
public function __construct($sourceServiceId, $sourceScope, $destServiceId, $destScope)
{
parent::__construct(sprintf(
'Scope Widening Injection detected: The definition "%s" references the service "%s" which belongs to a narrower scope. '
.'Generally, it is safer to either move "%s" to scope "%s" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "%s" each time it is needed. '
.'In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error.',
$sourceServiceId,
$destServiceId,
$sourceServiceId,
$destScope,
$destServiceId
));
$this->sourceServiceId = $sourceServiceId;
$this->sourceScope = $sourceScope;
$this->destServiceId = $destServiceId;
$this->destScope = $destScope;
}
public function getSourceServiceId()
{
return $this->sourceServiceId;
}
public function getSourceScope()
{
return $this->sourceScope;
}
public function getDestServiceId()
{
return $this->destServiceId;
}
public function getDestScope()
{
return $this->destScope;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* This exception is thrown when a circular reference is detected.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ServiceCircularReferenceException extends RuntimeException
{
private $serviceId;
private $path;
public function __construct($serviceId, array $path)
{
parent::__construct(sprintf('Circular reference detected for service "%s", path: "%s".', $serviceId, implode(' -> ', $path)));
$this->serviceId = $serviceId;
$this->path = $path;
}
public function getServiceId()
{
return $this->serviceId;
}
public function getPath()
{
return $this->path;
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection\Exception;
/**
* This exception is thrown when a non-existent service is requested.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ServiceNotFoundException extends InvalidArgumentException
{
private $id;
private $sourceId;
public function __construct($id, $sourceId = null)
{
if (null === $sourceId) {
$msg = sprintf('You have requested a non-existent service "%s".', $id);
} else {
$msg = sprintf('The service "%s" has a dependency on a non-existent service "%s".', $sourceId, $id);
}
parent::__construct($msg);
$this->id = $id;
$this->sourceId = $sourceId;
}
public function getId()
{
return $this->id;
}
public function getSourceId()
{
return $this->sourceId;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* ExtensionInterface is the interface implemented by container extension classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface ExtensionInterface
{
/**
* Loads a specific configuration.
*
* @param array $config An array of configuration values
* @param ContainerBuilder $container A ContainerBuilder instance
*
* @throws \InvalidArgumentException When provided tag is not defined in this extension
*
* @api
*/
function load(array $config, ContainerBuilder $container);
/**
* Returns the namespace to be used for this extension (XML namespace).
*
* @return string The XML namespace
*
* @api
*/
function getNamespace();
/**
* Returns the base path for the XSD files.
*
* @return string The XSD base path
*
* @api
*/
function getXsdValidationBasePath();
/**
* Returns the recommended alias to use in XML.
*
* This alias is also the mandatory prefix to use when using YAML.
*
* @return string The alias
*
* @api
*/
function getAlias();
}
Copyright (c) 2004-2012 Fabien Potencier
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.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Loader\Loader;
/**
* ClosureLoader loads service definitions from a PHP closure.
*
* The Closure has access to the container as its first argument.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ClosureLoader extends Loader
{
private $container;
/**
* Constructor.
*
* @param ContainerBuilder $container A ContainerBuilder instance
*/
public function __construct(ContainerBuilder $container)
{
$this->container = $container;
}
/**
* Loads a Closure.
*
* @param \Closure $closure The resource
* @param string $type The resource type
*/
public function load($closure, $type = null)
{
call_user_func($closure, $this->container);
}
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean true if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return $resource instanceof \Closure;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader;
use Symfony\Component\Config\FileLocator;
/**
* FileLoader is the abstract class used by all built-in loaders that are file based.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class FileLoader extends BaseFileLoader
{
protected $container;
/**
* Constructor.
*
* @param ContainerBuilder $container A ContainerBuilder instance
* @param FileLocator $locator A FileLocator instance
*/
public function __construct(ContainerBuilder $container, FileLocator $locator)
{
$this->container = $container;
parent::__construct($locator);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Config\Resource\FileResource;
/**
* IniFileLoader loads parameters from INI files.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class IniFileLoader extends FileLoader
{
/**
* Loads a resource.
*
* @param mixed $file The resource
* @param string $type The resource type
*
* @throws \InvalidArgumentException When ini file is not valid
*/
public function load($file, $type = null)
{
$path = $this->locator->locate($file);
$this->container->addResource(new FileResource($path));
$result = parse_ini_file($path, true);
if (false === $result || array() === $result) {
throw new \InvalidArgumentException(sprintf('The "%s" file is not valid.', $file));
}
if (isset($result['parameters']) && is_array($result['parameters'])) {
foreach ($result['parameters'] as $key => $value) {
$this->container->setParameter($key, $value);
}
}
}
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean true if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return is_string($resource) && 'ini' === pathinfo($resource, PATHINFO_EXTENSION);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Config\Resource\FileResource;
/**
* PhpFileLoader loads service definitions from a PHP file.
*
* The PHP file is required and the $container variable can be
* used form the file to change the container.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class PhpFileLoader extends FileLoader
{
/**
* Loads a PHP file.
*
* @param mixed $file The resource
* @param string $type The resource type
*/
public function load($file, $type = null)
{
// the container and loader variables are exposed to the included file below
$container = $this->container;
$loader = $this;
$path = $this->locator->locate($file);
$this->setCurrentDir(dirname($path));
$this->container->addResource(new FileResource($path));
include $path;
}
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean true if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://symfony.com/schema/dic/services"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://symfony.com/schema/dic/services"
elementFormDefault="qualified">
<xsd:annotation>
<xsd:documentation><![CDATA[
Symfony XML Services Schema, version 1.0
Authors: Fabien Potencier
This defines a way to describe PHP objects (services) and their
dependencies.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="container" type="container" />
<xsd:complexType name="container">
<xsd:annotation>
<xsd:documentation><![CDATA[
The root element of a service file.
]]></xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="imports" type="imports" minOccurs="0" maxOccurs="1" />
<xsd:element name="parameters" type="parameters" minOccurs="0" maxOccurs="1" />
<xsd:element name="services" type="services" minOccurs="0" maxOccurs="1" />
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="services">
<xsd:annotation>
<xsd:documentation><![CDATA[
Enclosing element for the definition of all services
]]></xsd:documentation>
</xsd:annotation>
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="service" type="service" />
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="imports">
<xsd:annotation>
<xsd:documentation><![CDATA[
Enclosing element for the import elements
]]></xsd:documentation>
</xsd:annotation>
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="import" type="import" />
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="import">
<xsd:annotation>
<xsd:documentation><![CDATA[
Import an external resource defining other services or parameters
]]></xsd:documentation>
</xsd:annotation>
<xsd:attribute name="resource" type="xsd:string" use="required" />
<xsd:attribute name="ignore-errors" type="boolean" />
</xsd:complexType>
<xsd:complexType name="configurator">
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="service" type="xsd:string" />
<xsd:attribute name="class" type="xsd:string" />
<xsd:attribute name="method" type="xsd:string" />
<xsd:attribute name="function" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="service">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="file" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="configurator" type="configurator" minOccurs="0" maxOccurs="1" />
<xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="class" type="xsd:string" />
<xsd:attribute name="scope" type="xsd:string" />
<xsd:attribute name="public" type="boolean" />
<xsd:attribute name="synthetic" type="boolean" />
<xsd:attribute name="abstract" type="boolean" />
<xsd:attribute name="factory-class" type="xsd:string" />
<xsd:attribute name="factory-method" type="xsd:string" />
<xsd:attribute name="factory-service" type="xsd:string" />
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="parent" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="tag">
<xsd:attribute name="name" type="xsd:string" />
<xsd:anyAttribute namespace="##any" processContents="lax" />
</xsd:complexType>
<xsd:complexType name="parameters">
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="parameter" type="parameter" />
</xsd:choice>
<xsd:attribute name="type" type="parameter_type" />
<xsd:attribute name="key" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="parameter" mixed="true">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="parameter" type="parameter" />
</xsd:choice>
<xsd:attribute name="type" type="parameter_type" />
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="key" type="xsd:string" />
<xsd:attribute name="on-invalid" type="invalid_sequence" />
</xsd:complexType>
<xsd:complexType name="property" mixed="true">
<xsd:attribute name="type" type="argument_type" />
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="on-invalid" type="xsd:string" />
<xsd:attribute name="strict" type="boolean" />
</xsd:complexType>
<xsd:complexType name="argument" mixed="true">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="service" type="service" />
</xsd:choice>
<xsd:attribute name="type" type="argument_type" />
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="key" type="xsd:string" />
<xsd:attribute name="index" type="xsd:integer" />
<xsd:attribute name="on-invalid" type="xsd:string" />
<xsd:attribute name="strict" type="boolean" />
</xsd:complexType>
<xsd:complexType name="call" mixed="true">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="service" type="service" />
</xsd:choice>
<xsd:attribute name="method" type="xsd:string" />
</xsd:complexType>
<xsd:simpleType name="parameter_type">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="collection" />
<xsd:enumeration value="service" />
<xsd:enumeration value="string" />
<xsd:enumeration value="constant" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="argument_type">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="collection" />
<xsd:enumeration value="service" />
<xsd:enumeration value="string" />
<xsd:enumeration value="constant" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="invalid_sequence">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="null" />
<xsd:enumeration value="ignore" />
<xsd:enumeration value="exception" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="boolean">
<xsd:restriction base="xsd:string">
<xsd:pattern value="(%.+%|true|false)" />
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\SimpleXMLElement;
use Symfony\Component\Config\Resource\FileResource;
/**
* XmlFileLoader loads XML files service definitions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class XmlFileLoader extends FileLoader
{
/**
* Loads an XML file.
*
* @param mixed $file The resource
* @param string $type The resource type
*/
public function load($file, $type = null)
{
$path = $this->locator->locate($file);
$xml = $this->parseFile($path);
$xml->registerXPathNamespace('container', 'http://symfony.com/schema/dic/services');
$this->container->addResource(new FileResource($path));
// anonymous services
$xml = $this->processAnonymousServices($xml, $path);
// imports
$this->parseImports($xml, $path);
// parameters
$this->parseParameters($xml, $path);
// extensions
$this->loadFromExtensions($xml);
// services
$this->parseDefinitions($xml, $path);
}
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean true if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION);
}
/**
* Parses parameters
*
* @param SimpleXMLElement $xml
* @param string $file
*
* @return void
*/
private function parseParameters(SimpleXMLElement $xml, $file)
{
if (!$xml->parameters) {
return;
}
$this->container->getParameterBag()->add($xml->parameters->getArgumentsAsPhp('parameter'));
}
/**
* Parses imports
*
* @param SimpleXMLElement $xml
* @param string $file
*
* @return void
*/
private function parseImports(SimpleXMLElement $xml, $file)
{
if (false === $imports = $xml->xpath('//container:imports/container:import')) {
return;
}
foreach ($imports as $import) {
$this->setCurrentDir(dirname($file));
$this->import((string) $import['resource'], null, (Boolean) $import->getAttributeAsPhp('ignore-errors'), $file);
}
}
/**
* Parses multiple definitions
*
* @param SimpleXMLElement $xml
* @param string $file
*
* @return void
*/
private function parseDefinitions(SimpleXMLElement $xml, $file)
{
if (false === $services = $xml->xpath('//container:services/container:service')) {
return;
}
foreach ($services as $service) {
$this->parseDefinition((string) $service['id'], $service, $file);
}
}
/**
* Parses an individual Definition
*
* @param string $id
* @param SimpleXMLElement $service
* @param string $file
*
* @return void
*/
private function parseDefinition($id, $service, $file)
{
if ((string) $service['alias']) {
$public = true;
if (isset($service['public'])) {
$public = $service->getAttributeAsPhp('public');
}
$this->container->setAlias($id, new Alias((string) $service['alias'], $public));
return;
}
if (isset($service['parent'])) {
$definition = new DefinitionDecorator((string) $service['parent']);
} else {
$definition = new Definition();
}
foreach (array('class', 'scope', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'abstract') as $key) {
if (isset($service[$key])) {
$method = 'set'.str_replace('-', '', $key);
$definition->$method((string) $service->getAttributeAsPhp($key));
}
}
if ($service->file) {
$definition->setFile((string) $service->file);
}
$definition->setArguments($service->getArgumentsAsPhp('argument'));
$definition->setProperties($service->getArgumentsAsPhp('property'));
if (isset($service->configurator)) {
if (isset($service->configurator['function'])) {
$definition->setConfigurator((string) $service->configurator['function']);
} else {
if (isset($service->configurator['service'])) {
$class = new Reference((string) $service->configurator['service'], ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
} else {
$class = (string) $service->configurator['class'];
}
$definition->setConfigurator(array($class, (string) $service->configurator['method']));
}
}
foreach ($service->call as $call) {
$definition->addMethodCall((string) $call['method'], $call->getArgumentsAsPhp('argument'));
}
foreach ($service->tag as $tag) {
$parameters = array();
foreach ($tag->attributes() as $name => $value) {
if ('name' === $name) {
continue;
}
$parameters[$name] = SimpleXMLElement::phpize($value);
}
$definition->addTag((string) $tag['name'], $parameters);
}
$this->container->setDefinition($id, $definition);
}
/**
* Parses a XML file.
*
* @param string $file Path to a file
*
* @throws \InvalidArgumentException When loading of XML file returns error
*/
private function parseFile($file)
{
$dom = new \DOMDocument();
libxml_use_internal_errors(true);
if (!$dom->load($file, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
}
$dom->validateOnParse = true;
$dom->normalizeDocument();
libxml_use_internal_errors(false);
$this->validate($dom, $file);
return simplexml_import_dom($dom, 'Symfony\\Component\\DependencyInjection\\SimpleXMLElement');
}
/**
* Processes anonymous services
*
* @param SimpleXMLElement $xml
* @param string $file
*
* @return array An array of anonymous services
*/
private function processAnonymousServices(SimpleXMLElement $xml, $file)
{
$definitions = array();
$count = 0;
// anonymous services as arguments
if (false === $nodes = $xml->xpath('//container:argument[@type="service"][not(@id)]')) {
return $xml;
}
foreach ($nodes as $node) {
// give it a unique name
$node['id'] = sprintf('%s_%d', md5($file), ++$count);
$definitions[(string) $node['id']] = array($node->service, $file, false);
$node->service['id'] = (string) $node['id'];
}
// anonymous services "in the wild"
if (false === $nodes = $xml->xpath('//container:services/container:service[not(@id)]')) {
return $xml;
}
foreach ($nodes as $node) {
// give it a unique name
$node['id'] = sprintf('%s_%d', md5($file), ++$count);
$definitions[(string) $node['id']] = array($node, $file, true);
$node->service['id'] = (string) $node['id'];
}
// resolve definitions
krsort($definitions);
foreach ($definitions as $id => $def) {
// anonymous services are always private
$def[0]['public'] = false;
$this->parseDefinition($id, $def[0], $def[1]);
$oNode = dom_import_simplexml($def[0]);
if (true === $def[2]) {
$nNode = new \DOMElement('_services');
$oNode->parentNode->replaceChild($nNode, $oNode);
$nNode->setAttribute('id', $id);
} else {
$oNode->parentNode->removeChild($oNode);
}
}
return $xml;
}
/**
* Validates an XML document.
*
* @param DOMDocument $dom
* @param string $file
*/
private function validate(\DOMDocument $dom, $file)
{
$this->validateSchema($dom, $file);
$this->validateExtensions($dom, $file);
}
/**
* Validates a documents XML schema.
*
* @param \DOMDocument $dom
* @param string $file
*
* @return void
*
* @throws \RuntimeException When extension references a non-existent XSD file
* @throws \InvalidArgumentException When xml doesn't validate its xsd schema
*/
private function validateSchema(\DOMDocument $dom, $file)
{
$schemaLocations = array('http://symfony.com/schema/dic/services' => str_replace('\\', '/', __DIR__.'/schema/dic/services/services-1.0.xsd'));
if ($element = $dom->documentElement->getAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation')) {
$items = preg_split('/\s+/', $element);
for ($i = 0, $nb = count($items); $i < $nb; $i += 2) {
if (!$this->container->hasExtension($items[$i])) {
continue;
}
if (($extension = $this->container->getExtension($items[$i])) && false !== $extension->getXsdValidationBasePath()) {
$path = str_replace($extension->getNamespace(), str_replace('\\', '/', $extension->getXsdValidationBasePath()).'/', $items[$i + 1]);
if (!file_exists($path)) {
throw new \RuntimeException(sprintf('Extension "%s" references a non-existent XSD file "%s"', get_class($extension), $path));
}
$schemaLocations[$items[$i]] = $path;
}
}
}
$tmpfiles = array();
$imports = '';
foreach ($schemaLocations as $namespace => $location) {
$parts = explode('/', $location);
if (0 === stripos($location, 'phar://')) {
$tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
if ($tmpfile) {
copy($location, $tmpfile);
$tmpfiles[] = $tmpfile;
$parts = explode('/', str_replace('\\', '/', $tmpfile));
}
}
$drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
$location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
$imports .= sprintf(' <xsd:import namespace="%s" schemaLocation="%s" />'."\n", $namespace, $location);
}
$source = <<<EOF
<?xml version="1.0" encoding="utf-8" ?>
<xsd:schema xmlns="http://symfony.com/schema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://symfony.com/schema"
elementFormDefault="qualified">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
$imports
</xsd:schema>
EOF
;
$current = libxml_use_internal_errors(true);
$valid = $dom->schemaValidateSource($source);
foreach ($tmpfiles as $tmpfile) {
@unlink($tmpfile);
}
if (!$valid) {
throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
}
libxml_use_internal_errors($current);
}
/**
* Validates an extension.
*
* @param \DOMDocument $dom
* @param string $file
*
* @return void
*
* @throws \InvalidArgumentException When non valid tag are found or no extension are found
*/
private function validateExtensions(\DOMDocument $dom, $file)
{
foreach ($dom->documentElement->childNodes as $node) {
if (!$node instanceof \DOMElement || 'http://symfony.com/schema/dic/services' === $node->namespaceURI) {
continue;
}
// can it be handled by an extension?
if (!$this->container->hasExtension($node->namespaceURI)) {
$extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getNamespace(); }, $this->container->getExtensions()));
throw new \InvalidArgumentException(sprintf(
'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
$node->tagName,
$file,
$node->namespaceURI,
$extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
));
}
}
}
/**
* Returns an array of XML errors.
*
* @return array
*/
private function getXmlErrors()
{
$errors = array();
foreach (libxml_get_errors() as $error) {
$errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
$error->code,
trim($error->message),
$error->file ? $error->file : 'n/a',
$error->line,
$error->column
);
}
libxml_clear_errors();
return $errors;
}
/**
* Loads from an extension.
*
* @param SimpleXMLElement $xml
*
* @return void
*/
private function loadFromExtensions(SimpleXMLElement $xml)
{
foreach (dom_import_simplexml($xml)->childNodes as $node) {
if (!$node instanceof \DOMElement || $node->namespaceURI === 'http://symfony.com/schema/dic/services') {
continue;
}
$values = static::convertDomElementToArray($node);
if (!is_array($values)) {
$values = array();
}
$this->container->loadFromExtension($node->namespaceURI, $values);
}
}
/**
* Converts a \DomElement object to a PHP array.
*
* The following rules applies during the conversion:
*
* * Each tag is converted to a key value or an array
* if there is more than one "value"
*
* * The content of a tag is set under a "value" key (<foo>bar</foo>)
* if the tag also has some nested tags
*
* * The attributes are converted to keys (<foo foo="bar"/>)
*
* * The nested-tags are converted to keys (<foo><foo>bar</foo></foo>)
*
* @param \DomElement $element A \DomElement instance
*
* @return array A PHP array
*/
static public function convertDomElementToArray(\DomElement $element)
{
$empty = true;
$config = array();
foreach ($element->attributes as $name => $node) {
$config[$name] = SimpleXMLElement::phpize($node->value);
$empty = false;
}
$nodeValue = false;
foreach ($element->childNodes as $node) {
if ($node instanceof \DOMText) {
if (trim($node->nodeValue)) {
$nodeValue = trim($node->nodeValue);
$empty = false;
}
} elseif (!$node instanceof \DOMComment) {
if ($node instanceof \DOMElement && '_services' === $node->nodeName) {
$value = new Reference($node->getAttribute('id'));
} else {
$value = static::convertDomElementToArray($node);
}
$key = $node->localName;
if (isset($config[$key])) {
if (!is_array($config[$key]) || !is_int(key($config[$key]))) {
$config[$key] = array($config[$key]);
}
$config[$key][] = $value;
} else {
$config[$key] = $value;
}
$empty = false;
}
}
if (false !== $nodeValue) {
$value = SimpleXMLElement::phpize($nodeValue);
if (count($config)) {
$config['value'] = $value;
} else {
$config = $value;
}
}
return !$empty ? $config : null;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Yaml\Yaml;
/**
* YamlFileLoader loads YAML files service definitions.
*
* The YAML format does not support anonymous services (cf. the XML loader).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class YamlFileLoader extends FileLoader
{
/**
* Loads a Yaml file.
*
* @param mixed $file The resource
* @param string $type The resource type
*/
public function load($file, $type = null)
{
$path = $this->locator->locate($file);
$content = $this->loadFile($path);
$this->container->addResource(new FileResource($path));
// empty file
if (null === $content) {
return;
}
// imports
$this->parseImports($content, $file);
// parameters
if (isset($content['parameters'])) {
foreach ($content['parameters'] as $key => $value) {
$this->container->setParameter($key, $this->resolveServices($value));
}
}
// extensions
$this->loadFromExtensions($content);
// services
$this->parseDefinitions($content, $file);
}
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean true if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
}
/**
* Parses all imports
*
* @param array $content
* @param string $file
*
* @return void
*/
private function parseImports($content, $file)
{
if (!isset($content['imports'])) {
return;
}
foreach ($content['imports'] as $import) {
$this->setCurrentDir(dirname($file));
$this->import($import['resource'], null, isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false, $file);
}
}
/**
* Parses definitions
*
* @param array $content
* @param string $file
*
* @return void
*/
private function parseDefinitions($content, $file)
{
if (!isset($content['services'])) {
return;
}
foreach ($content['services'] as $id => $service) {
$this->parseDefinition($id, $service, $file);
}
}
/**
* Parses a definition.
*
* @param string $id
* @param array $service
* @param string $file
*
* @return void
*/
private function parseDefinition($id, $service, $file)
{
if (is_string($service) && 0 === strpos($service, '@')) {
$this->container->setAlias($id, substr($service, 1));
return;
} elseif (isset($service['alias'])) {
$public = !array_key_exists('public', $service) || (Boolean) $service['public'];
$this->container->setAlias($id, new Alias($service['alias'], $public));
return;
}
if (isset($service['parent'])) {
$definition = new DefinitionDecorator($service['parent']);
} else {
$definition = new Definition();
}
if (isset($service['class'])) {
$definition->setClass($service['class']);
}
if (isset($service['scope'])) {
$definition->setScope($service['scope']);
}
if (isset($service['synthetic'])) {
$definition->setSynthetic($service['synthetic']);
}
if (isset($service['public'])) {
$definition->setPublic($service['public']);
}
if (isset($service['abstract'])) {
$definition->setAbstract($service['abstract']);
}
if (isset($service['factory_class'])) {
$definition->setFactoryClass($service['factory_class']);
}
if (isset($service['factory_method'])) {
$definition->setFactoryMethod($service['factory_method']);
}
if (isset($service['factory_service'])) {
$definition->setFactoryService($service['factory_service']);
}
if (isset($service['file'])) {
$definition->setFile($service['file']);
}
if (isset($service['arguments'])) {
$definition->setArguments($this->resolveServices($service['arguments']));
}
if (isset($service['properties'])) {
$definition->setProperties($this->resolveServices($service['properties']));
}
if (isset($service['configurator'])) {
if (is_string($service['configurator'])) {
$definition->setConfigurator($service['configurator']);
} else {
$definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1]));
}
}
if (isset($service['calls'])) {
foreach ($service['calls'] as $call) {
$args = isset($call[1]) ? $this->resolveServices($call[1]) : array();
$definition->addMethodCall($call[0], $args);
}
}
if (isset($service['tags'])) {
if (!is_array($service['tags'])) {
throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s.', $id, $file));
}
foreach ($service['tags'] as $tag) {
if (!isset($tag['name'])) {
throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
}
$name = $tag['name'];
unset($tag['name']);
foreach ($tag as $attribute => $value) {
if (!is_scalar($value)) {
throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s" in %s.', $id, $name, $file));
}
}
$definition->addTag($name, $tag);
}
}
$this->container->setDefinition($id, $definition);
}
/**
* Loads a YAML file.
*
* @param string $file
*
* @return array The file content
*/
private function loadFile($file)
{
return $this->validate(Yaml::parse($file), $file);
}
/**
* Validates a YAML file.
*
* @param mixed $content
* @param string $file
*
* @return array
*
* @throws \InvalidArgumentException When service file is not valid
*/
private function validate($content, $file)
{
if (null === $content) {
return $content;
}
if (!is_array($content)) {
throw new \InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
}
foreach (array_keys($content) as $namespace) {
if (in_array($namespace, array('imports', 'parameters', 'services'))) {
continue;
}
if (!$this->container->hasExtension($namespace)) {
$extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions()));
throw new \InvalidArgumentException(sprintf(
'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
$namespace,
$file,
$namespace,
$extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
));
}
}
return $content;
}
/**
* Resolves services.
*
* @param string $value
*
* @return Reference
*/
private function resolveServices($value)
{
if (is_array($value)) {
$value = array_map(array($this, 'resolveServices'), $value);
} elseif (is_string($value) && 0 === strpos($value, '@')) {
if (0 === strpos($value, '@?')) {
$value = substr($value, 2);
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
} else {
$value = substr($value, 1);
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
}
if ('=' === substr($value, -1)) {
$value = substr($value, 0, -1);
$strict = false;
} else {
$strict = true;
}
$value = new Reference($value, $invalidBehavior, $strict);
}
return $value;
}
/**
* Loads from Extensions
*
* @param array $content
*
* @return void
*/
private function loadFromExtensions($content)
{
foreach ($content as $namespace => $values) {
if (in_array($namespace, array('imports', 'parameters', 'services'))) {
continue;
}
if (!is_array($values)) {
$values = array();
}
$this->container->loadFromExtension($namespace, $values);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* Parameter represents a parameter reference.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Parameter
{
private $id;
/**
* Constructor.
*
* @param string $id The parameter key
*/
public function __construct($id)
{
$this->id = $id;
}
/**
* __toString.
*
* @return string The parameter key
*/
public function __toString()
{
return (string) $this->id;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\ParameterBag;
/**
* Holds read-only parameters.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class FrozenParameterBag extends ParameterBag
{
/**
* Constructor.
*
* For performance reasons, the constructor assumes that
* all keys are already lowercased.
*
* This is always the case when used internally.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function __construct(array $parameters = array())
{
$this->parameters = $parameters;
$this->resolved = true;
}
/**
* {@inheritDoc}
*
* @api
*/
public function clear()
{
throw new \LogicException('Impossible to call clear() on a frozen ParameterBag.');
}
/**
* {@inheritDoc}
*
* @api
*/
public function add(array $parameters)
{
throw new \LogicException('Impossible to call add() on a frozen ParameterBag.');
}
/**
* {@inheritDoc}
*
* @api
*/
public function set($name, $value)
{
throw new \LogicException('Impossible to call set() on a frozen ParameterBag.');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\ParameterBag;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
/**
* Holds parameters.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ParameterBag implements ParameterBagInterface
{
protected $parameters;
protected $resolved;
/**
* Constructor.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function __construct(array $parameters = array())
{
$this->parameters = array();
$this->add($parameters);
$this->resolved = false;
}
/**
* Clears all parameters.
*
* @api
*/
public function clear()
{
$this->parameters = array();
}
/**
* Adds parameters to the service container parameters.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function add(array $parameters)
{
foreach ($parameters as $key => $value) {
$this->parameters[strtolower($key)] = $value;
}
}
/**
* Gets the service container parameters.
*
* @return array An array of parameters
*
* @api
*/
public function all()
{
return $this->parameters;
}
/**
* Gets a service container parameter.
*
* @param string $name The parameter name
*
* @return mixed The parameter value
*
* @throws ParameterNotFoundException if the parameter is not defined
*
* @api
*/
public function get($name)
{
$name = strtolower($name);
if (!array_key_exists($name, $this->parameters)) {
throw new ParameterNotFoundException($name);
}
return $this->parameters[$name];
}
/**
* Sets a service container parameter.
*
* @param string $name The parameter name
* @param mixed $value The parameter value
*
* @api
*/
public function set($name, $value)
{
$this->parameters[strtolower($name)] = $value;
}
/**
* Returns true if a parameter name is defined.
*
* @param string $name The parameter name
*
* @return Boolean true if the parameter name is defined, false otherwise
*
* @api
*/
public function has($name)
{
return array_key_exists(strtolower($name), $this->parameters);
}
/**
* Replaces parameter placeholders (%name%) by their values for all parameters.
*/
public function resolve()
{
if ($this->resolved) {
return;
}
$parameters = array();
foreach ($this->parameters as $key => $value) {
try {
$value = $this->resolveValue($value);
$parameters[$key] = $this->unescapeValue($value);
} catch (ParameterNotFoundException $e) {
$e->setSourceKey($key);
throw $e;
}
}
$this->parameters = $parameters;
$this->resolved = true;
}
/**
* Replaces parameter placeholders (%name%) by their values.
*
* @param mixed $value A value
* @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
*
* @return mixed The resolved value
*
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
* @throws ParameterCircularReferenceException if a circular reference if detected
* @throws RuntimeException when a given parameter has a type problem.
*/
public function resolveValue($value, array $resolving = array())
{
if (is_array($value)) {
$args = array();
foreach ($value as $k => $v) {
$args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving);
}
return $args;
}
if (!is_string($value)) {
return $value;
}
return $this->resolveString($value, $resolving);
}
/**
* Resolves parameters inside a string
*
* @param string $value The string to resolve
* @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
*
* @return string The resolved string
*
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
* @throws ParameterCircularReferenceException if a circular reference if detected
* @throws RuntimeException when a given parameter has a type problem.
*/
public function resolveString($value, array $resolving = array())
{
// we do this to deal with non string values (Boolean, integer, ...)
// as the preg_replace_callback throw an exception when trying
// a non-string in a parameter value
if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
$key = strtolower($match[1]);
if (isset($resolving[$key])) {
throw new ParameterCircularReferenceException(array_keys($resolving));
}
$resolving[$key] = true;
return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving);
}
$self = $this;
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($self, $resolving, $value) {
// skip %%
if (!isset($match[1])) {
return '%%';
}
$key = strtolower($match[1]);
if (isset($resolving[$key])) {
throw new ParameterCircularReferenceException(array_keys($resolving));
}
$resolved = $self->get($key);
if (!is_string($resolved) && !is_numeric($resolved)) {
throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "%s" of type %s inside string value "%s".', $key, gettype($resolved), $value));
}
$resolved = (string) $resolved;
$resolving[$key] = true;
return $self->isResolved() ? $resolved : $self->resolveString($resolved, $resolving);
}, $value);
}
public function isResolved()
{
return $this->resolved;
}
private function unescapeValue($value)
{
if (is_string($value)) {
return str_replace('%%', '%', $value);
}
if (is_array($value)) {
$result = array();
foreach ($value as $k => $v) {
$result[$k] = $this->unescapeValue($v);
}
return $result;
}
return $value;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\ParameterBag;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
/**
* ParameterBagInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface ParameterBagInterface
{
/**
* Clears all parameters.
*
* @api
*/
function clear();
/**
* Adds parameters to the service container parameters.
*
* @param array $parameters An array of parameters
*
* @api
*/
function add(array $parameters);
/**
* Gets the service container parameters.
*
* @return array An array of parameters
*
* @api
*/
function all();
/**
* Gets a service container parameter.
*
* @param string $name The parameter name
*
* @return mixed The parameter value
*
* @throws ParameterNotFoundException if the parameter is not defined
*
* @api
*/
function get($name);
/**
* Sets a service container parameter.
*
* @param string $name The parameter name
* @param mixed $value The parameter value
*
* @api
*/
function set($name, $value);
/**
* Returns true if a parameter name is defined.
*
* @param string $name The parameter name
*
* @return Boolean true if the parameter name is defined, false otherwise
*
* @api
*/
function has($name);
/**
* Replaces parameter placeholders (%name%) by their values for all parameters.
*/
function resolve();
/**
* Replaces parameter placeholders (%name%) by their values.
*
* @param mixed $value A value
*
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
*/
function resolveValue($value);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* Reference represents a service reference.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Reference
{
private $id;
private $invalidBehavior;
private $strict;
/**
* Constructor.
*
* @param string $id The service identifier
* @param int $invalidBehavior The behavior when the service does not exist
* @param Boolean $strict Sets how this reference is validated
*
* @see Container
*/
public function __construct($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $strict = true)
{
$this->id = strtolower($id);
$this->invalidBehavior = $invalidBehavior;
$this->strict = $strict;
}
/**
* __toString.
*
* @return string The service identifier
*/
public function __toString()
{
return (string) $this->id;
}
/**
* Returns the behavior to be used when the service does not exist.
*
* @return int
*/
public function getInvalidBehavior()
{
return $this->invalidBehavior;
}
/**
* Returns true when this Reference is strict
*
* @return Boolean
*/
public function isStrict()
{
return $this->strict;
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection;
/**
* Scope class.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
class Scope implements ScopeInterface
{
private $name;
private $parentName;
/**
* @api
*/
public function __construct($name, $parentName = ContainerInterface::SCOPE_CONTAINER)
{
$this->name = $name;
$this->parentName = $parentName;
}
/**
* @api
*/
public function getName()
{
return $this->name;
}
/**
* @api
*/
public function getParentName()
{
return $this->parentName;
}
}
<?php
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\Component\DependencyInjection;
/**
* Scope Interface.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
interface ScopeInterface
{
/**
* @api
*/
function getName();
/**
* @api
*/
function getParentName();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* SimpleXMLElement class.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SimpleXMLElement extends \SimpleXMLElement
{
/**
* Converts an attribute as a php type.
*
* @param string $name
*
* @return mixed
*/
public function getAttributeAsPhp($name)
{
return self::phpize($this[$name]);
}
/**
* Returns arguments as valid php types.
*
* @param string $name
* @param Boolean $lowercase
*
* @return mixed
*/
public function getArgumentsAsPhp($name, $lowercase = true)
{
$arguments = array();
foreach ($this->$name as $arg) {
if (isset($arg['name'])) {
$arg['key'] = (string) $arg['name'];
}
$key = isset($arg['key']) ? (string) $arg['key'] : (!$arguments ? 0 : max(array_keys($arguments)) + 1);
// parameter keys are case insensitive
if ('parameter' == $name && $lowercase) {
$key = strtolower($key);
}
// this is used by DefinitionDecorator to overwrite a specific
// argument of the parent definition
if (isset($arg['index'])) {
$key = 'index_'.$arg['index'];
}
switch ($arg['type']) {
case 'service':
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
if (isset($arg['on-invalid']) && 'ignore' == $arg['on-invalid']) {
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
} elseif (isset($arg['on-invalid']) && 'null' == $arg['on-invalid']) {
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
}
if (isset($arg['strict'])) {
$strict = self::phpize($arg['strict']);
} else {
$strict = true;
}
$arguments[$key] = new Reference((string) $arg['id'], $invalidBehavior, $strict);
break;
case 'collection':
$arguments[$key] = $arg->getArgumentsAsPhp($name, false);
break;
case 'string':
$arguments[$key] = (string) $arg;
break;
case 'constant':
$arguments[$key] = constant((string) $arg);
break;
default:
$arguments[$key] = self::phpize($arg);
}
}
return $arguments;
}
/**
* Converts an xml value to a php type.
*
* @param mixed $value
*
* @return mixed
*/
static public function phpize($value)
{
$value = (string) $value;
$lowercaseValue = strtolower($value);
switch (true) {
case 'null' === $lowercaseValue:
return null;
case ctype_digit($value):
$raw = $value;
$cast = intval($value);
return '0' == $value[0] ? octdec($value) : (((string) $raw == (string) $cast) ? $cast : $raw);
case 'true' === $lowercaseValue:
return true;
case 'false' === $lowercaseValue:
return false;
case is_numeric($value):
return '0x' == $value[0].$value[1] ? hexdec($value) : floatval($value);
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $value):
return floatval(str_replace(',', '', $value));
default:
return $value;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* TaggedContainerInterface is the interface implemented when a container knows how to deals with tags.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface TaggedContainerInterface extends ContainerInterface
{
/**
* Returns service ids for a given tag.
*
* @param string $name The tag name
*
* @return array An array of tags
*
* @api
*/
function findTaggedServiceIds($name);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* Represents a variable.
*
* $var = new Variable('a');
*
* will be dumped as
*
* $a
*
* by the PHP dumper.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class Variable
{
private $name;
/**
* Constructor
*
* @param string $name
*/
public function __construct($name)
{
$this->name = $name;
}
/**
* Converts the object to a string
*
* @return string
*/
public function __toString()
{
return $this->name;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* Event is the base class for classes containing event data.
*
* This class contains no event data. It is used by events that do not pass
* state information to an event handler when an event is raised.
*
* You can call the method stopPropagation() to abort the execution of
* further listeners in your event listener.
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*/
class Event
{
/**
* @var Boolean Whether no further event listeners should be triggered
*/
private $propagationStopped = false;
/**
* Returns whether further event listeners should be triggered.
*
* @see Event::stopPropagation
* @return Boolean Whether propagation was already stopped for this event.
*
* @api
*/
public function isPropagationStopped()
{
return $this->propagationStopped;
}
/**
* Stops the propagation of the event to further event listeners.
*
* If multiple event listeners are connected to the same event, no
* further event listener will be triggered once any trigger calls
* stopPropagation().
*
* @api
*/
public function stopPropagation()
{
$this->propagationStopped = true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* The EventDispatcherInterface is the central point of Symfony's event listener system.
*
* Listeners are registered on the manager and events are dispatched through the
* manager.
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*
* @api
*/
class EventDispatcher implements EventDispatcherInterface
{
private $listeners = array();
private $sorted = array();
/**
* @see EventDispatcherInterface::dispatch
*
* @api
*/
public function dispatch($eventName, Event $event = null)
{
if (!isset($this->listeners[$eventName])) {
return;
}
if (null === $event) {
$event = new Event();
}
$this->doDispatch($this->getListeners($eventName), $eventName, $event);
}
/**
* @see EventDispatcherInterface::getListeners
*/
public function getListeners($eventName = null)
{
if (null !== $eventName) {
if (!isset($this->sorted[$eventName])) {
$this->sortListeners($eventName);
}
return $this->sorted[$eventName];
}
foreach (array_keys($this->listeners) as $eventName) {
if (!isset($this->sorted[$eventName])) {
$this->sortListeners($eventName);
}
}
return $this->sorted;
}
/**
* @see EventDispatcherInterface::hasListeners
*/
public function hasListeners($eventName = null)
{
return (Boolean) count($this->getListeners($eventName));
}
/**
* @see EventDispatcherInterface::addListener
*
* @api
*/
public function addListener($eventName, $listener, $priority = 0)
{
$this->listeners[$eventName][$priority][] = $listener;
unset($this->sorted[$eventName]);
}
/**
* @see EventDispatcherInterface::removeListener
*/
public function removeListener($eventName, $listener)
{
if (!isset($this->listeners[$eventName])) {
return;
}
foreach ($this->listeners[$eventName] as $priority => $listeners) {
if (false !== ($key = array_search($listener, $listeners))) {
unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]);
}
}
}
/**
* @see EventDispatcherInterface::addSubscriber
*
* @api
*/
public function addSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
if (is_string($params)) {
$this->addListener($eventName, array($subscriber, $params));
} else {
$this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
}
}
}
/**
* @see EventDispatcherInterface::removeSubscriber
*/
public function removeSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
$this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0]));
}
}
/**
* Triggers the listeners of an event.
*
* This method can be overridden to add functionality that is executed
* for each listener.
*
* @param array[callback] $listeners The event listeners.
* @param string $eventName The name of the event to dispatch.
* @param Event $event The event object to pass to the event handlers/listeners.
*/
protected function doDispatch($listeners, $eventName, Event $event)
{
foreach ($listeners as $listener) {
call_user_func($listener, $event);
if ($event->isPropagationStopped()) {
break;
}
}
}
/**
* Sorts the internal list of listeners for the given event by priority.
*
* @param string $eventName The name of the event.
*/
private function sortListeners($eventName)
{
$this->sorted[$eventName] = array();
if (isset($this->listeners[$eventName])) {
krsort($this->listeners[$eventName]);
$this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* The EventDispatcherInterface is the central point of Symfony's event listener system.
* Listeners are registered on the manager and events are dispatched through the
* manager.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*/
interface EventDispatcherInterface
{
/**
* Dispatches an event to all registered listeners.
*
* @param string $eventName The name of the event to dispatch. The name of
* the event is the name of the method that is
* invoked on listeners.
* @param Event $event The event to pass to the event handlers/listeners.
* If not supplied, an empty Event instance is created.
*
* @api
*/
function dispatch($eventName, Event $event = null);
/**
* Adds an event listener that listens on the specified events.
*
* @param string $eventName The event to listen on
* @param callable $listener The listener
* @param integer $priority The higher this value, the earlier an event
* listener will be triggered in the chain (defaults to 0)
*
* @api
*/
function addListener($eventName, $listener, $priority = 0);
/**
* Adds an event subscriber.
*
* The subscriber is asked for all the events he is
* interested in and added as a listener for these events.
*
* @param EventSubscriberInterface $subscriber The subscriber.
*
* @api
*/
function addSubscriber(EventSubscriberInterface $subscriber);
/**
* Removes an event listener from the specified events.
*
* @param string|array $eventName The event(s) to remove a listener from
* @param callable $listener The listener to remove
*/
function removeListener($eventName, $listener);
/**
* Removes an event subscriber.
*
* @param EventSubscriberInterface $subscriber The subscriber
*/
function removeSubscriber(EventSubscriberInterface $subscriber);
/**
* Gets the listeners of a specific event or all listeners.
*
* @param string $eventName The name of the event
*
* @return array The event listeners for the specified event, or all event listeners by event name
*/
function getListeners($eventName = null);
/**
* Checks whether an event has any registered listeners.
*
* @param string $eventName The name of the event
*
* @return Boolean true if the specified event has any listeners, false otherwise
*/
function hasListeners($eventName = null);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* An EventSubscriber knows himself what events he is interested in.
* If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes
* {@link getSubscribedEvents} and registers the subscriber as a listener for all
* returned events.
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*/
interface EventSubscriberInterface
{
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
*
* @return array The event names to listen to
*
* @api
*/
static function getSubscribedEvents();
}
Copyright (c) 2004-2012 Fabien Potencier
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.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Comparator;
/**
* Comparator.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Comparator
{
private $target;
private $operator = '==';
/**
* Gets the target value.
*
* @return string The target value
*/
public function getTarget()
{
return $this->target;
}
/**
* Sets the target value.
*
* @param string $target The target value
*/
public function setTarget($target)
{
$this->target = $target;
}
/**
* Gets the comparison operator.
*
* @return string The operator
*/
public function getOperator()
{
return $this->operator;
}
/**
* Sets the comparison operator.
*
* @param string $operator A valid operator
*/
public function setOperator($operator)
{
if (!$operator) {
$operator = '==';
}
if (!in_array($operator, array('>', '<', '>=', '<=', '=='))) {
throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
}
$this->operator = $operator;
}
/**
* Tests against the target.
*
* @param mixed $test A test value
*/
public function test($test)
{
switch ($this->operator) {
case '>':
return $test > $this->target;
case '>=':
return $test >= $this->target;
case '<':
return $test < $this->target;
case '<=':
return $test <= $this->target;
}
return $test == $this->target;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Comparator;
/**
* DateCompare compiles date comparisons.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DateComparator extends Comparator
{
/**
* Constructor.
*
* @param string $test A comparison string
*
* @throws \InvalidArgumentException If the test is not understood
*/
public function __construct($test)
{
if (!preg_match('#^\s*([<>=]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
}
try {
$date = new \DateTime($matches[2]);
$target = $date->format('U');
} catch (\Exception $e) {
throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
}
$operator = isset($matches[1]) ? $matches[1] : '==';
if ('since' === $operator || 'after' === $operator) {
$operator = '>';
}
if ('until' === $operator || 'before' === $operator) {
$operator = '<';
}
$this->setOperator($operator);
$this->setTarget($target);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Comparator;
/**
* NumberComparator compiles a simple comparison to an anonymous
* subroutine, which you can call with a value to be tested again.
*
* Now this would be very pointless, if NumberCompare didn't understand
* magnitudes.
*
* The target value may use magnitudes of kilobytes (k, ki),
* megabytes (m, mi), or gigabytes (g, gi). Those suffixed
* with an i use the appropriate 2**n version in accordance with the
* IEC standard: http://physics.nist.gov/cuu/Units/binary.html
*
* Based on the Perl Number::Compare module.
*
* @author Fabien Potencier <fabien@symfony.com> PHP port
* @author Richard Clamp <richardc@unixbeard.net> Perl version
*
* @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
* @copyright 2002 Richard Clamp <richardc@unixbeard.net>
*
* @see http://physics.nist.gov/cuu/Units/binary.html
*/
class NumberComparator extends Comparator
{
/**
* Constructor.
*
* @param string $test A comparison string
*
* @throws \InvalidArgumentException If the test is not understood
*/
public function __construct($test)
{
if (!preg_match('#^\s*([<>=]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
}
$target = $matches[2];
if (isset($matches[3])) {
// magnitude
switch (strtolower($matches[3])) {
case 'k':
$target *= 1000;
break;
case 'ki':
$target *= 1024;
break;
case 'm':
$target *= 1000000;
break;
case 'mi':
$target *= 1024*1024;
break;
case 'g':
$target *= 1000000000;
break;
case 'gi':
$target *= 1024*1024*1024;
break;
}
}
$this->setTarget($target);
$this->setOperator(isset($matches[1]) ? $matches[1] : '==');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder;
/**
* Finder allows to build rules to find files and directories.
*
* It is a thin wrapper around several specialized iterator classes.
*
* All rules may be invoked several times.
*
* All methods return the current Finder object to allow easy chaining:
*
* $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Finder implements \IteratorAggregate
{
const IGNORE_VCS_FILES = 1;
const IGNORE_DOT_FILES = 2;
private $mode = 0;
private $names = array();
private $notNames = array();
private $exclude = array();
private $filters = array();
private $depths = array();
private $sizes = array();
private $followLinks = false;
private $sort = false;
private $ignore = 0;
private $dirs = array();
private $dates = array();
private $iterators = array();
static private $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
/**
* Constructor.
*/
public function __construct()
{
$this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
}
/**
* Creates a new Finder.
*
* @return Finder A new Finder instance
*
* @api
*/
static public function create()
{
return new self();
}
/**
* Restricts the matching to directories only.
*
* @return Finder The current Finder instance
*
* @api
*/
public function directories()
{
$this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
return $this;
}
/**
* Restricts the matching to files only.
*
* @return Finder The current Finder instance
*
* @api
*/
public function files()
{
$this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
return $this;
}
/**
* Adds tests for the directory depth.
*
* Usage:
*
* $finder->depth('> 1') // the Finder will start matching at level 1.
* $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.
*
* @param int $level The depth level expression
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\DepthRangeFilterIterator
* @see Symfony\Component\Finder\Comparator\NumberComparator
*
* @api
*/
public function depth($level)
{
$this->depths[] = new Comparator\NumberComparator($level);
return $this;
}
/**
* Adds tests for file dates (last modified).
*
* The date must be something that strtotime() is able to parse:
*
* $finder->date('since yesterday');
* $finder->date('until 2 days ago');
* $finder->date('> now - 2 hours');
* $finder->date('>= 2005-10-15');
*
* @param string $date A date rage string
*
* @return Finder The current Finder instance
*
* @see strtotime
* @see Symfony\Component\Finder\Iterator\DateRangeFilterIterator
* @see Symfony\Component\Finder\Comparator\DateComparator
*
* @api
*/
public function date($date)
{
$this->dates[] = new Comparator\DateComparator($date);
return $this;
}
/**
* Adds rules that files must match.
*
* You can use patterns (delimited with / sign), globs or simple strings.
*
* $finder->name('*.php')
* $finder->name('/\.php$/') // same as above
* $finder->name('test.php')
*
* @param string $pattern A pattern (a regexp, a glob, or a string)
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\FilenameFilterIterator
*
* @api
*/
public function name($pattern)
{
$this->names[] = $pattern;
return $this;
}
/**
* Adds rules that files must not match.
*
* @param string $pattern A pattern (a regexp, a glob, or a string)
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\FilenameFilterIterator
*
* @api
*/
public function notName($pattern)
{
$this->notNames[] = $pattern;
return $this;
}
/**
* Adds tests for file sizes.
*
* $finder->size('> 10K');
* $finder->size('<= 1Ki');
* $finder->size(4);
*
* @param string $size A size range string
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\SizeRangeFilterIterator
* @see Symfony\Component\Finder\Comparator\NumberComparator
*
* @api
*/
public function size($size)
{
$this->sizes[] = new Comparator\NumberComparator($size);
return $this;
}
/**
* Excludes directories.
*
* @param string $dir A directory to exclude
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator
*
* @api
*/
public function exclude($dir)
{
$this->exclude[] = $dir;
return $this;
}
/**
* Excludes "hidden" directories and files (starting with a dot).
*
* @param Boolean $ignoreDotFiles Whether to exclude "hidden" files or not
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator
*
* @api
*/
public function ignoreDotFiles($ignoreDotFiles)
{
if ($ignoreDotFiles) {
$this->ignore = $this->ignore | static::IGNORE_DOT_FILES;
} else {
$this->ignore = $this->ignore ^ static::IGNORE_DOT_FILES;
}
return $this;
}
/**
* Forces the finder to ignore version control directories.
*
* @param Boolean $ignoreVCS Whether to exclude VCS files or not
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator
*
* @api
*/
public function ignoreVCS($ignoreVCS)
{
if ($ignoreVCS) {
$this->ignore = $this->ignore | static::IGNORE_VCS_FILES;
} else {
$this->ignore = $this->ignore ^ static::IGNORE_VCS_FILES;
}
return $this;
}
static public function addVCSPattern($pattern)
{
self::$vcsPatterns[] = $pattern;
}
/**
* Sorts files and directories by an anonymous function.
*
* The anonymous function receives two \SplFileInfo instances to compare.
*
* This can be slow as all the matching files and directories must be retrieved for comparison.
*
* @param Closure $closure An anonymous function
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\SortableIterator
*
* @api
*/
public function sort(\Closure $closure)
{
$this->sort = $closure;
return $this;
}
/**
* Sorts files and directories by name.
*
* This can be slow as all the matching files and directories must be retrieved for comparison.
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\SortableIterator
*
* @api
*/
public function sortByName()
{
$this->sort = Iterator\SortableIterator::SORT_BY_NAME;
return $this;
}
/**
* Sorts files and directories by type (directories before files), then by name.
*
* This can be slow as all the matching files and directories must be retrieved for comparison.
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\SortableIterator
*
* @api
*/
public function sortByType()
{
$this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
return $this;
}
/**
* Filters the iterator with an anonymous function.
*
* The anonymous function receives a \SplFileInfo and must return false
* to remove files.
*
* @param Closure $closure An anonymous function
*
* @return Finder The current Finder instance
*
* @see Symfony\Component\Finder\Iterator\CustomFilterIterator
*
* @api
*/
public function filter(\Closure $closure)
{
$this->filters[] = $closure;
return $this;
}
/**
* Forces the following of symlinks.
*
* @return Finder The current Finder instance
*
* @api
*/
public function followLinks()
{
$this->followLinks = true;
return $this;
}
/**
* Searches files and directories which match defined rules.
*
* @param string|array $dirs A directory path or an array of directories
*
* @return Finder The current Finder instance
*
* @throws \InvalidArgumentException if one of the directory does not exist
*
* @api
*/
public function in($dirs)
{
$dirs = (array) $dirs;
foreach ($dirs as $dir) {
if (!is_dir($dir)) {
throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
}
}
$this->dirs = array_merge($this->dirs, $dirs);
return $this;
}
/**
* Returns an Iterator for the current Finder configuration.
*
* This method implements the IteratorAggregate interface.
*
* @return \Iterator An iterator
*
* @throws \LogicException if the in() method has not been called
*/
public function getIterator()
{
if (0 === count($this->dirs)) {
throw new \LogicException('You must call the in() method before iterating over a Finder.');
}
if (1 === count($this->dirs) && 0 === count($this->iterators)) {
return $this->searchInDirectory($this->dirs[0]);
}
$iterator = new \AppendIterator();
foreach ($this->dirs as $dir) {
$iterator->append($this->searchInDirectory($dir));
}
foreach ($this->iterators as $it) {
$iterator->append($it);
}
return $iterator;
}
/**
* Appends an existing set of files/directories to the finder.
*
* The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.
*
* @param mixed $iterator
*/
public function append($iterator)
{
if ($iterator instanceof \IteratorAggregate) {
$this->iterators[] = $iterator->getIterator();
} elseif ($iterator instanceof \Iterator) {
$this->iterators[] = $iterator;
} elseif ($iterator instanceof \Traversable || is_array($iterator)) {
$it = new \ArrayIterator();
foreach ($iterator as $file) {
$it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
}
$this->iterators[] = $it;
} else {
throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
}
}
private function searchInDirectory($dir)
{
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
if ($this->followLinks) {
$flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
}
$iterator = new \RecursiveIteratorIterator(
new Iterator\RecursiveDirectoryIterator($dir, $flags),
\RecursiveIteratorIterator::SELF_FIRST
);
if ($this->depths) {
$iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->depths);
}
if ($this->mode) {
$iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
}
if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
$this->exclude = array_merge($this->exclude, self::$vcsPatterns);
}
if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
$this->exclude[] = '\..+';
}
if ($this->exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
}
if ($this->names || $this->notNames) {
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
}
if ($this->sizes) {
$iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
}
if ($this->dates) {
$iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
}
if ($this->filters) {
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
}
if ($this->sort) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
$iterator = $iteratorAggregate->getIterator();
}
return $iterator;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder;
/**
* Glob matches globbing patterns against text.
*
* if match_glob("foo.*", "foo.bar") echo "matched\n";
*
* // prints foo.bar and foo.baz
* $regex = glob_to_regex("foo.*");
* for (array('foo.bar', 'foo.baz', 'foo', 'bar') as $t)
* {
* if (/$regex/) echo "matched: $car\n";
* }
*
* Glob implements glob(3) style matching that can be used to match
* against text, rather than fetching names from a filesystem.
*
* Based on the Perl Text::Glob module.
*
* @author Fabien Potencier <fabien@symfony.com> PHP port
* @author Richard Clamp <richardc@unixbeard.net> Perl version
* @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
* @copyright 2002 Richard Clamp <richardc@unixbeard.net>
*/
class Glob
{
/**
* Returns a regexp which is the equivalent of the glob pattern.
*
* @param string $glob The glob pattern
* @param Boolean $strictLeadingDot
* @param Boolean $strictWildcardSlash
*
* @return string regex The regexp
*/
static public function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true)
{
$firstByte = true;
$escaping = false;
$inCurlies = 0;
$regex = '';
$sizeGlob = strlen($glob);
for ($i = 0; $i < $sizeGlob; $i++) {
$car = $glob[$i];
if ($firstByte) {
if ($strictLeadingDot && '.' !== $car) {
$regex .= '(?=[^\.])';
}
$firstByte = false;
}
if ('/' === $car) {
$firstByte = true;
}
if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
$regex .= "\\$car";
} elseif ('*' === $car) {
$regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
} elseif ('?' === $car) {
$regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
} elseif ('{' === $car) {
$regex .= $escaping ? '\\{' : '(';
if (!$escaping) {
++$inCurlies;
}
} elseif ('}' === $car && $inCurlies) {
$regex .= $escaping ? '}' : ')';
if (!$escaping) {
--$inCurlies;
}
} elseif (',' === $car && $inCurlies) {
$regex .= $escaping ? ',' : '|';
} elseif ('\\' === $car) {
if ($escaping) {
$regex .= '\\\\';
$escaping = false;
} else {
$escaping = true;
}
continue;
} else {
$regex .= $car;
}
$escaping = false;
}
return '#^'.$regex.'$#';
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* CustomFilterIterator filters files by applying anonymous functions.
*
* The anonymous function receives a \SplFileInfo and must return false
* to remove files.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class CustomFilterIterator extends \FilterIterator
{
private $filters = array();
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param array $filters An array of PHP callbacks
*/
public function __construct(\Iterator $iterator, array $filters)
{
foreach ($filters as $filter) {
if (!is_callable($filter)) {
throw new \InvalidArgumentException('Invalid PHP callback.');
}
}
$this->filters = $filters;
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return Boolean true if the value should be kept, false otherwise
*/
public function accept()
{
$fileinfo = $this->current();
foreach ($this->filters as $filter) {
if (false === call_user_func($filter, $fileinfo)) {
return false;
}
}
return true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DateRangeFilterIterator extends \FilterIterator
{
private $comparators = array();
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param array $comparators An array of \DateCompare instances
*/
public function __construct(\Iterator $iterator, array $comparators)
{
$this->comparators = $comparators;
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return Boolean true if the value should be kept, false otherwise
*/
public function accept()
{
$fileinfo = $this->current();
if (!$fileinfo->isFile()) {
return true;
}
$filedate = $fileinfo->getMTime();
foreach ($this->comparators as $compare) {
if (!$compare->test($filedate)) {
return false;
}
}
return true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* DepthRangeFilterIterator limits the directory depth.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DepthRangeFilterIterator extends \FilterIterator
{
private $minDepth = 0;
/**
* Constructor.
*
* @param \RecursiveIteratorIterator $iterator The Iterator to filter
* @param array $comparators An array of \NumberComparator instances
*/
public function __construct(\RecursiveIteratorIterator $iterator, array $comparators)
{
$minDepth = 0;
$maxDepth = INF;
foreach ($comparators as $comparator) {
switch ($comparator->getOperator()) {
case '>':
$minDepth = $comparator->getTarget() + 1;
break;
case '>=':
$minDepth = $comparator->getTarget();
break;
case '<':
$maxDepth = $comparator->getTarget() - 1;
break;
case '<=':
$maxDepth = $comparator->getTarget();
break;
default:
$minDepth = $maxDepth = $comparator->getTarget();
}
}
$this->minDepth = $minDepth;
$iterator->setMaxDepth(INF === $maxDepth ? -1 : $maxDepth);
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return Boolean true if the value should be kept, false otherwise
*/
public function accept()
{
return $this->getInnerIterator()->getDepth() >= $this->minDepth;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* ExcludeDirectoryFilterIterator filters out directories.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExcludeDirectoryFilterIterator extends \FilterIterator
{
private $patterns;
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param array $directories An array of directories to exclude
*/
public function __construct(\Iterator $iterator, array $directories)
{
$this->patterns = array();
foreach ($directories as $directory) {
$this->patterns[] = '#(^|/)'.preg_quote($directory, '#').'(/|$)#';
}
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return Boolean true if the value should be kept, false otherwise
*/
public function accept()
{
$path = $this->isDir() ? $this->getSubPathname() : $this->getSubPath();
$path = strtr($path, '\\', '/');
foreach ($this->patterns as $pattern) {
if (preg_match($pattern, $path)) {
return false;
}
}
return true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Glob;
/**
* FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FilenameFilterIterator extends \FilterIterator
{
private $matchRegexps;
private $noMatchRegexps;
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param array $matchPatterns An array of patterns that need to match
* @param array $noMatchPatterns An array of patterns that need to not match
*/
public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
{
$this->matchRegexps = array();
foreach ($matchPatterns as $pattern) {
$this->matchRegexps[] = $this->toRegex($pattern);
}
$this->noMatchRegexps = array();
foreach ($noMatchPatterns as $pattern) {
$this->noMatchRegexps[] = $this->toRegex($pattern);
}
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return Boolean true if the value should be kept, false otherwise
*/
public function accept()
{
// should at least match one rule
if ($this->matchRegexps) {
$match = false;
foreach ($this->matchRegexps as $regex) {
if (preg_match($regex, $this->getFilename())) {
$match = true;
break;
}
}
} else {
$match = true;
}
// should at least not match one rule to exclude
if ($this->noMatchRegexps) {
$exclude = false;
foreach ($this->noMatchRegexps as $regex) {
if (preg_match($regex, $this->getFilename())) {
$exclude = true;
break;
}
}
} else {
$exclude = false;
}
return $match && !$exclude;
}
private function toRegex($str)
{
if (preg_match('/^([^a-zA-Z0-9\\\\]).+?\\1[ims]?$/', $str)) {
return $str;
}
return Glob::toRegex($str);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* FileTypeFilterIterator only keeps files, directories, or both.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FileTypeFilterIterator extends \FilterIterator
{
const ONLY_FILES = 1;
const ONLY_DIRECTORIES = 2;
private $mode;
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param integer $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
*/
public function __construct(\Iterator $iterator, $mode)
{
$this->mode = $mode;
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return Boolean true if the value should be kept, false otherwise
*/
public function accept()
{
if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $this->isFile()) {
return false;
} elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $this->isDir()) {
return false;
}
return true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\SplFileInfo;
/**
* Extends the \RecursiveDirectoryIterator to support relative paths
*
* @author Victor Berchet <victor@suumit.com>
*/
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
{
public function __construct($path, $flags)
{
if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
throw new \RuntimeException('This iterator only support returning current as fileinfo.');
}
parent::__construct($path, $flags);
}
/**
* Return an instance of SplFileInfo with support for relative paths
*
* @return SplFileInfo File information
*/
public function current()
{
return new SplFileInfo(parent::current()->getPathname(), $this->getSubPath(), $this->getSubPathname());
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* SizeRangeFilterIterator filters out files that are not in the given size range.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SizeRangeFilterIterator extends \FilterIterator
{
private $comparators = array();
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param array $comparators An array of \NumberComparator instances
*/
public function __construct(\Iterator $iterator, array $comparators)
{
$this->comparators = $comparators;
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return Boolean true if the value should be kept, false otherwise
*/
public function accept()
{
if (!$this->isFile()) {
return true;
}
$filesize = $this->getSize();
foreach ($this->comparators as $compare) {
if (!$compare->test($filesize)) {
return false;
}
}
return true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* SortableIterator applies a sort on a given Iterator.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SortableIterator implements \IteratorAggregate
{
const SORT_BY_NAME = 1;
const SORT_BY_TYPE = 2;
private $iterator;
private $sort;
/**
* Constructor.
*
* @param \Traversable $iterator The Iterator to filter
* @param integer|callback $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
*/
public function __construct(\Traversable $iterator, $sort)
{
$this->iterator = $iterator;
if (self::SORT_BY_NAME === $sort) {
$this->sort = function ($a, $b) {
return strcmp($a->getRealpath(), $b->getRealpath());
};
} elseif (self::SORT_BY_TYPE === $sort) {
$this->sort = function ($a, $b) {
if ($a->isDir() && $b->isFile()) {
return -1;
} elseif ($a->isFile() && $b->isDir()) {
return 1;
}
return strcmp($a->getRealpath(), $b->getRealpath());
};
} elseif (is_callable($sort)) {
$this->sort = $sort;
} else {
throw new \InvalidArgumentException('The SortableIterator takes a PHP callback or a valid built-in sort algorithm as an argument.');
}
}
public function getIterator()
{
$array = iterator_to_array($this->iterator, true);
uasort($array, $this->sort);
return new \ArrayIterator($array);
}
}
Copyright (c) 2004-2012 Fabien Potencier
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.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder;
/**
* Extends \SplFileInfo to support relative paths
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SplFileInfo extends \SplFileInfo
{
private $relativePath;
private $relativePathname;
/**
* Constructor
*
* @param string $file The file name
* @param string $relativePath The relative path
* @param string $relativePathname The relative path name
*/
public function __construct($file, $relativePath, $relativePathname)
{
parent::__construct($file);
$this->relativePath = $relativePath;
$this->relativePathname = $relativePathname;
}
/**
* Returns the relative path
*
* @return string the relative path
*/
public function getRelativePath()
{
return $this->relativePath;
}
/**
* Returns the relative path name
*
* @return string the relative path name
*/
public function getRelativePathname()
{
return $this->relativePathname;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
/**
* IdentityTranslator does not translate anything.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class IdentityTranslator implements TranslatorInterface
{
private $selector;
/**
* Constructor.
*
* @param MessageSelector $selector The message selector for pluralization
*
* @api
*/
public function __construct(MessageSelector $selector)
{
$this->selector = $selector;
}
/**
* {@inheritdoc}
*
* @api
*/
public function setLocale($locale)
{
}
/**
* {@inheritdoc}
*
* @api
*/
public function getLocale()
{
}
/**
* {@inheritdoc}
*
* @api
*/
public function trans($id, array $parameters = array(), $domain = 'messages', $locale = null)
{
return strtr($id, $parameters);
}
/**
* {@inheritdoc}
*
* @api
*/
public function transChoice($id, $number, array $parameters = array(), $domain = 'messages', $locale = null)
{
return strtr($this->selector->choose($id, (int) $number, $locale), $parameters);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
/**
* Tests if a given number belongs to a given math interval.
*
* An interval can represent a finite set of numbers:
*
* {1,2,3,4}
*
* An interval can represent numbers between two numbers:
*
* [1, +Inf]
* ]-1,2[
*
* The left delimiter can be [ (inclusive) or ] (exclusive).
* The right delimiter can be [ (exclusive) or ] (inclusive).
* Beside numbers, you can use -Inf and +Inf for the infinite.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
*/
class Interval
{
/**
* Tests if the given number is in the math interval.
*
* @param integer $number A number
* @param string $interval An interval
*/
static public function test($number, $interval)
{
$interval = trim($interval);
if (!preg_match('/^'.self::getIntervalRegexp().'$/x', $interval, $matches)) {
throw new \InvalidArgumentException(sprintf('"%s" is not a valid interval.', $interval));
}
if ($matches[1]) {
foreach (explode(',', $matches[2]) as $n) {
if ($number == $n) {
return true;
}
}
} else {
$leftNumber = self::convertNumber($matches['left']);
$rightNumber = self::convertNumber($matches['right']);
return
('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
&& (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
;
}
return false;
}
/**
* Returns a Regexp that matches valid intervals.
*
* @return string A Regexp (without the delimiters)
*/
static public function getIntervalRegexp()
{
return <<<EOF
({\s*
(\-?\d+[\s*,\s*\-?\d+]*)
\s*})
|
(?P<left_delimiter>[\[\]])
\s*
(?P<left>-Inf|\-?\d+)
\s*,\s*
(?P<right>\+?Inf|\-?\d+)
\s*
(?P<right_delimiter>[\[\]])
EOF;
}
static private function convertNumber($number)
{
if ('-Inf' === $number) {
return log(0);
} elseif ('+Inf' === $number || 'Inf' === $number) {
return -log(0);
}
return (int) $number;
}
}
Copyright (c) 2004-2012 Fabien Potencier
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.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\MessageCatalogue;
/**
* ArrayLoader loads translations from a PHP array.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ArrayLoader implements LoaderInterface
{
/**
* {@inheritdoc}
*
* @api
*/
public function load($resource, $locale, $domain = 'messages')
{
$this->flatten($resource);
$catalogue = new MessageCatalogue($locale);
$catalogue->add($resource, $domain);
return $catalogue;
}
/**
* Flattens an nested array of translations
*
* The scheme used is:
* 'key' => array('key2' => array('key3' => 'value'))
* Becomes:
* 'key.key2.key3' => 'value'
*
* This function takes an array by reference and will modify it
*
* @param array &$messages The array that will be flattened
* @param array $subnode Current subnode being parsed, used internally for recursive calls
* @param string $path Current path being parsed, used internally for recursive calls
*/
private function flatten(array &$messages, array $subnode = null, $path = null)
{
if (null === $subnode) {
$subnode =& $messages;
}
foreach ($subnode as $key => $value) {
if (is_array($value)) {
$nodePath = $path ? $path.'.'.$key : $key;
$this->flatten($messages, $value, $nodePath);
if (null === $path) {
unset($messages[$key]);
}
} elseif (null !== $path) {
$messages[$path.'.'.$key] = $value;
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Config\Resource\FileResource;
/**
* CsvFileLoader loads translations from CSV files.
*
* @author Saša Stamenković <umpirsky@gmail.com>
*
* @api
*/
class CsvFileLoader extends ArrayLoader implements LoaderInterface
{
private $delimiter = ';';
private $enclosure = '"';
private $escape = '\\';
/**
* {@inheritdoc}
*
* @api
*/
public function load($resource, $locale, $domain = 'messages')
{
$messages = array();
if (!stream_is_local($resource)) {
throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $resource));
}
try {
$file = new \SplFileObject($resource, 'rb');
} catch (\RuntimeException $e) {
throw new \InvalidArgumentException(sprintf('Error opening file "%s".', $resource));
}
$file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY);
$file->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
foreach ($file as $data) {
if (substr($data[0], 0, 1) === '#') {
continue;
}
if (!isset($data[1])) {
continue;
}
if (count($data) == 2) {
$messages[$data[0]] = $data[1];
} else {
continue;
}
}
$catalogue = parent::load($messages, $locale, $domain);
$catalogue->addResource(new FileResource($resource));
return $catalogue;
}
/**
* Sets the delimiter, enclosure, and escape character for CSV.
*
* @param string $delimiter delimiter character
* @param string $enclosure enclosure character
* @param string $escape escape character
*/
public function setCsvControl($delimiter = ';', $enclosure = '"', $escape = '\\')
{
$this->delimiter = $delimiter;
$this->enclosure = $enclosure;
$this->escape = $escape;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\MessageCatalogue;
/**
* LoaderInterface is the interface implemented by all translation loaders.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface LoaderInterface
{
/**
* Loads a locale.
*
* @param mixed $resource A resource
* @param string $locale A locale
* @param string $domain The domain
*
* @return MessageCatalogue A MessageCatalogue instance
*
* @api
*/
function load($resource, $locale, $domain = 'messages');
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Config\Resource\FileResource;
/**
* PhpFileLoader loads translations from PHP files returning an array of translations.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class PhpFileLoader extends ArrayLoader implements LoaderInterface
{
/**
* {@inheritdoc}
*
* @api
*/
public function load($resource, $locale, $domain = 'messages')
{
if (!stream_is_local($resource)) {
throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $resource));
}
$messages = require($resource);
$catalogue = parent::load($messages, $locale, $domain);
$catalogue->addResource(new FileResource($resource));
return $catalogue;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
May-19-2004:
- Changed the <choice> for ElemType_header, moving minOccurs="0" maxOccurs="unbounded" from its elements
to <choice> itself.
- Added <choice> for ElemType_trans-unit to allow "any order" for <context-group>, <count-group>, <prop-group>, <note>, and
<alt-trans>.
Oct-2005
- updated version info to 1.2
- equiv-trans attribute to <trans-unit> element
- merged-trans attribute for <group> element
- Add the <seg-source> element as optional in the <trans-unit> and <alt-trans> content models, at the same level as <source>
- Create a new value "seg" for the mtype attribute of the <mrk> element
- Add mid as an optional attribute for the <alt-trans> element
Nov-14-2005
- Changed name attribute for <context-group> from required to optional
- Added extension point at <xliff>
Jan-9-2006
- Added alttranstype type attribute to <alt-trans>, and values
Jan-10-2006
- Corrected error with overwritten purposeValueList
- Corrected name="AttrType_Version", attribute should have been "name"
-->
<xsd:schema xmlns:xlf="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:oasis:names:tc:xliff:document:1.2" xml:lang="en">
<!-- Import for xml:lang and xml:space -->
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
<!-- Attributes Lists -->
<xsd:simpleType name="XTend">
<xsd:restriction base="xsd:string">
<xsd:pattern value="x-[^\s]+"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="context-typeValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'context-type'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="database">
<xsd:annotation>
<xsd:documentation>Indicates a database content.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="element">
<xsd:annotation>
<xsd:documentation>Indicates the content of an element within an XML document.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="elementtitle">
<xsd:annotation>
<xsd:documentation>Indicates the name of an element within an XML document.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="linenumber">
<xsd:annotation>
<xsd:documentation>Indicates the line number from the sourcefile (see context-type="sourcefile") where the &lt;source&gt; is found.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="numparams">
<xsd:annotation>
<xsd:documentation>Indicates a the number of parameters contained within the &lt;source&gt;.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="paramnotes">
<xsd:annotation>
<xsd:documentation>Indicates notes pertaining to the parameters in the &lt;source&gt;.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="record">
<xsd:annotation>
<xsd:documentation>Indicates the content of a record within a database.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="recordtitle">
<xsd:annotation>
<xsd:documentation>Indicates the name of a record within a database.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="sourcefile">
<xsd:annotation>
<xsd:documentation>Indicates the original source file in the case that multiple files are merged to form the original file from which the XLIFF file is created. This differs from the original &lt;file&gt; attribute in that this sourcefile is one of many that make up that file.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="count-typeValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'count-type'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="num-usages">
<xsd:annotation>
<xsd:documentation>Indicates the count units are items that are used X times in a certain context; example: this is a reusable text unit which is used 42 times in other texts.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="repetition">
<xsd:annotation>
<xsd:documentation>Indicates the count units are translation units existing already in the same document.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="total">
<xsd:annotation>
<xsd:documentation>Indicates a total count.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="InlineDelimitersValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'ctype' when used other elements than &lt;ph&gt; or &lt;x&gt;.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="bold">
<xsd:annotation>
<xsd:documentation>Indicates a run of bolded text.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="italic">
<xsd:annotation>
<xsd:documentation>Indicates a run of text in italics.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="underlined">
<xsd:annotation>
<xsd:documentation>Indicates a run of underlined text.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="link">
<xsd:annotation>
<xsd:documentation>Indicates a run of hyper-text.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="InlinePlaceholdersValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'ctype' when used with &lt;ph&gt; or &lt;x&gt;.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="image">
<xsd:annotation>
<xsd:documentation>Indicates a inline image.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="pb">
<xsd:annotation>
<xsd:documentation>Indicates a page break.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="lb">
<xsd:annotation>
<xsd:documentation>Indicates a line break.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="mime-typeValueList">
<xsd:restriction base="xsd:string">
<xsd:pattern value="(text|multipart|message|application|image|audio|video|model)(/.+)*"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="datatypeValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'datatype'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="asp">
<xsd:annotation>
<xsd:documentation>Indicates Active Server Page data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="c">
<xsd:annotation>
<xsd:documentation>Indicates C source file data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="cdf">
<xsd:annotation>
<xsd:documentation>Indicates Channel Definition Format (CDF) data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="cfm">
<xsd:annotation>
<xsd:documentation>Indicates ColdFusion data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="cpp">
<xsd:annotation>
<xsd:documentation>Indicates C++ source file data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="csharp">
<xsd:annotation>
<xsd:documentation>Indicates C-Sharp data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="cstring">
<xsd:annotation>
<xsd:documentation>Indicates strings from C, ASM, and driver files data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="csv">
<xsd:annotation>
<xsd:documentation>Indicates comma-separated values data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="database">
<xsd:annotation>
<xsd:documentation>Indicates database data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="documentfooter">
<xsd:annotation>
<xsd:documentation>Indicates portions of document that follows data and contains metadata.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="documentheader">
<xsd:annotation>
<xsd:documentation>Indicates portions of document that precedes data and contains metadata.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="filedialog">
<xsd:annotation>
<xsd:documentation>Indicates data from standard UI file operations dialogs (e.g., Open, Save, Save As, Export, Import).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="form">
<xsd:annotation>
<xsd:documentation>Indicates standard user input screen data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="html">
<xsd:annotation>
<xsd:documentation>Indicates HyperText Markup Language (HTML) data - document instance.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="htmlbody">
<xsd:annotation>
<xsd:documentation>Indicates content within an HTML document’s &lt;body&gt; element.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="ini">
<xsd:annotation>
<xsd:documentation>Indicates Windows INI file data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="interleaf">
<xsd:annotation>
<xsd:documentation>Indicates Interleaf data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="javaclass">
<xsd:annotation>
<xsd:documentation>Indicates Java source file data (extension '.java').</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="javapropertyresourcebundle">
<xsd:annotation>
<xsd:documentation>Indicates Java property resource bundle data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="javalistresourcebundle">
<xsd:annotation>
<xsd:documentation>Indicates Java list resource bundle data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="javascript">
<xsd:annotation>
<xsd:documentation>Indicates JavaScript source file data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="jscript">
<xsd:annotation>
<xsd:documentation>Indicates JScript source file data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="layout">
<xsd:annotation>
<xsd:documentation>Indicates information relating to formatting.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="lisp">
<xsd:annotation>
<xsd:documentation>Indicates LISP source file data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="margin">
<xsd:annotation>
<xsd:documentation>Indicates information relating to margin formats.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="menufile">
<xsd:annotation>
<xsd:documentation>Indicates a file containing menu.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="messagefile">
<xsd:annotation>
<xsd:documentation>Indicates numerically identified string table.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="mif">
<xsd:annotation>
<xsd:documentation>Indicates Maker Interchange Format (MIF) data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="mimetype">
<xsd:annotation>
<xsd:documentation>Indicates that the datatype attribute value is a MIME Type value and is defined in the mime-type attribute.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="mo">
<xsd:annotation>
<xsd:documentation>Indicates GNU Machine Object data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="msglib">
<xsd:annotation>
<xsd:documentation>Indicates Message Librarian strings created by Novell's Message Librarian Tool.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="pagefooter">
<xsd:annotation>
<xsd:documentation>Indicates information to be displayed at the bottom of each page of a document.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="pageheader">
<xsd:annotation>
<xsd:documentation>Indicates information to be displayed at the top of each page of a document.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="parameters">
<xsd:annotation>
<xsd:documentation>Indicates a list of property values (e.g., settings within INI files or preferences dialog).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="pascal">
<xsd:annotation>
<xsd:documentation>Indicates Pascal source file data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="php">
<xsd:annotation>
<xsd:documentation>Indicates Hypertext Preprocessor data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="plaintext">
<xsd:annotation>
<xsd:documentation>Indicates plain text file (no formatting other than, possibly, wrapping).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="po">
<xsd:annotation>
<xsd:documentation>Indicates GNU Portable Object file.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="report">
<xsd:annotation>
<xsd:documentation>Indicates dynamically generated user defined document. e.g. Oracle Report, Crystal Report, etc.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="resources">
<xsd:annotation>
<xsd:documentation>Indicates Windows .NET binary resources.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="resx">
<xsd:annotation>
<xsd:documentation>Indicates Windows .NET Resources.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="rtf">
<xsd:annotation>
<xsd:documentation>Indicates Rich Text Format (RTF) data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="sgml">
<xsd:annotation>
<xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - document instance.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="sgmldtd">
<xsd:annotation>
<xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - Document Type Definition (DTD).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="svg">
<xsd:annotation>
<xsd:documentation>Indicates Scalable Vector Graphic (SVG) data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="vbscript">
<xsd:annotation>
<xsd:documentation>Indicates VisualBasic Script source file.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="warning">
<xsd:annotation>
<xsd:documentation>Indicates warning message.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="winres">
<xsd:annotation>
<xsd:documentation>Indicates Windows (Win32) resources (i.e. resources extracted from an RC script, a message file, or a compiled file).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="xhtml">
<xsd:annotation>
<xsd:documentation>Indicates Extensible HyperText Markup Language (XHTML) data - document instance.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="xml">
<xsd:annotation>
<xsd:documentation>Indicates Extensible Markup Language (XML) data - document instance.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="xmldtd">
<xsd:annotation>
<xsd:documentation>Indicates Extensible Markup Language (XML) data - Document Type Definition (DTD).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="xsl">
<xsd:annotation>
<xsd:documentation>Indicates Extensible Stylesheet Language (XSL) data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="xul">
<xsd:annotation>
<xsd:documentation>Indicates XUL elements.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="mtypeValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'mtype'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="abbrev">
<xsd:annotation>
<xsd:documentation>Indicates the marked text is an abbreviation.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="abbreviated-form">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.8: A term resulting from the omission of any part of the full term while designating the same concept.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="abbreviation">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.8.1: An abbreviated form of a simple term resulting from the omission of some of its letters (e.g. 'adj.' for 'adjective').</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="acronym">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.8.4: An abbreviated form of a term made up of letters from the full form of a multiword term strung together into a sequence pronounced only syllabically (e.g. 'radar' for 'radio detecting and ranging').</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="appellation">
<xsd:annotation>
<xsd:documentation>ISO-12620: A proper-name term, such as the name of an agency or other proper entity.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="collocation">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.18.1: A recurrent word combination characterized by cohesion in that the components of the collocation must co-occur within an utterance or series of utterances, even though they do not necessarily have to maintain immediate proximity to one another.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="common-name">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.5: A synonym for an international scientific term that is used in general discourse in a given language.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="datetime">
<xsd:annotation>
<xsd:documentation>Indicates the marked text is a date and/or time.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="equation">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.15: An expression used to represent a concept based on a statement that two mathematical expressions are, for instance, equal as identified by the equal sign (=), or assigned to one another by a similar sign.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="expanded-form">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.7: The complete representation of a term for which there is an abbreviated form.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="formula">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.14: Figures, symbols or the like used to express a concept briefly, such as a mathematical or chemical formula.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="head-term">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.1: The concept designation that has been chosen to head a terminological record.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="initialism">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.8.3: An abbreviated form of a term consisting of some of the initial letters of the words making up a multiword term or the term elements making up a compound term when these letters are pronounced individually (e.g. 'BSE' for 'bovine spongiform encephalopathy').</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="international-scientific-term">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.4: A term that is part of an international scientific nomenclature as adopted by an appropriate scientific body.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="internationalism">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.6: A term that has the same or nearly identical orthographic or phonemic form in many languages.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="logical-expression">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.16: An expression used to represent a concept based on mathematical or logical relations, such as statements of inequality, set relationships, Boolean operations, and the like.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="materials-management-unit">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.17: A unit to track object.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="name">
<xsd:annotation>
<xsd:documentation>Indicates the marked text is a name.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="near-synonym">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.3: A term that represents the same or a very similar concept as another term in the same language, but for which interchangeability is limited to some contexts and inapplicable in others.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="part-number">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.17.2: A unique alphanumeric designation assigned to an object in a manufacturing system.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="phrase">
<xsd:annotation>
<xsd:documentation>Indicates the marked text is a phrase.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="phraseological-unit">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.18: Any group of two or more words that form a unit, the meaning of which frequently cannot be deduced based on the combined sense of the words making up the phrase.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="protected">
<xsd:annotation>
<xsd:documentation>Indicates the marked text should not be translated.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="romanized-form">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.12: A form of a term resulting from an operation whereby non-Latin writing systems are converted to the Latin alphabet.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="seg">
<xsd:annotation>
<xsd:documentation>Indicates that the marked text represents a segment.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="set-phrase">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.18.2: A fixed, lexicalized phrase.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="short-form">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.8.2: A variant of a multiword term that includes fewer words than the full form of the term (e.g. 'Group of Twenty-four' for 'Intergovernmental Group of Twenty-four on International Monetary Affairs').</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="sku">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.17.1: Stock keeping unit, an inventory item identified by a unique alphanumeric designation assigned to an object in an inventory control system.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="standard-text">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.19: A fixed chunk of recurring text.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="symbol">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.13: A designation of a concept by letters, numerals, pictograms or any combination thereof.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="synonym">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.2: Any term that represents the same or a very similar concept as the main entry term in a term entry.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="synonymous-phrase">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.18.3: Phraseological unit in a language that expresses the same semantic content as another phrase in that same language.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="term">
<xsd:annotation>
<xsd:documentation>Indicates the marked text is a term.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="transcribed-form">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.11: A form of a term resulting from an operation whereby the characters of one writing system are represented by characters from another writing system, taking into account the pronunciation of the characters converted.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="transliterated-form">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.10: A form of a term resulting from an operation whereby the characters of an alphabetic writing system are represented by characters from another alphabetic writing system.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="truncated-term">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.8.5: An abbreviated form of a term resulting from the omission of one or more term elements or syllables (e.g. 'flu' for 'influenza').</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="variant">
<xsd:annotation>
<xsd:documentation>ISO-12620 2.1.9: One of the alternate forms of a term.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="restypeValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'restype'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="auto3state">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC AUTO3STATE control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="autocheckbox">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC AUTOCHECKBOX control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="autoradiobutton">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC AUTORADIOBUTTON control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="bedit">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC BEDIT control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="bitmap">
<xsd:annotation>
<xsd:documentation>Indicates a bitmap, for example a BITMAP resource in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="button">
<xsd:annotation>
<xsd:documentation>Indicates a button object, for example a BUTTON control Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="caption">
<xsd:annotation>
<xsd:documentation>Indicates a caption, such as the caption of a dialog box.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="cell">
<xsd:annotation>
<xsd:documentation>Indicates the cell in a table, for example the content of the &lt;td&gt; element in HTML.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="checkbox">
<xsd:annotation>
<xsd:documentation>Indicates check box object, for example a CHECKBOX control in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="checkboxmenuitem">
<xsd:annotation>
<xsd:documentation>Indicates a menu item with an associated checkbox.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="checkedlistbox">
<xsd:annotation>
<xsd:documentation>Indicates a list box, but with a check-box for each item.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="colorchooser">
<xsd:annotation>
<xsd:documentation>Indicates a color selection dialog.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="combobox">
<xsd:annotation>
<xsd:documentation>Indicates a combination of edit box and listbox object, for example a COMBOBOX control in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="comboboxexitem">
<xsd:annotation>
<xsd:documentation>Indicates an initialization entry of an extended combobox DLGINIT resource block. (code 0x1234).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="comboboxitem">
<xsd:annotation>
<xsd:documentation>Indicates an initialization entry of a combobox DLGINIT resource block (code 0x0403).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="component">
<xsd:annotation>
<xsd:documentation>Indicates a UI base class element that cannot be represented by any other element.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="contextmenu">
<xsd:annotation>
<xsd:documentation>Indicates a context menu.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="ctext">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC CTEXT control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="cursor">
<xsd:annotation>
<xsd:documentation>Indicates a cursor, for example a CURSOR resource in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="datetimepicker">
<xsd:annotation>
<xsd:documentation>Indicates a date/time picker.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="defpushbutton">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC DEFPUSHBUTTON control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="dialog">
<xsd:annotation>
<xsd:documentation>Indicates a dialog box.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="dlginit">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC DLGINIT resource block.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="edit">
<xsd:annotation>
<xsd:documentation>Indicates an edit box object, for example an EDIT control in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="file">
<xsd:annotation>
<xsd:documentation>Indicates a filename.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="filechooser">
<xsd:annotation>
<xsd:documentation>Indicates a file dialog.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="fn">
<xsd:annotation>
<xsd:documentation>Indicates a footnote.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="font">
<xsd:annotation>
<xsd:documentation>Indicates a font name.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="footer">
<xsd:annotation>
<xsd:documentation>Indicates a footer.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="frame">
<xsd:annotation>
<xsd:documentation>Indicates a frame object.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="grid">
<xsd:annotation>
<xsd:documentation>Indicates a XUL grid element.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="groupbox">
<xsd:annotation>
<xsd:documentation>Indicates a groupbox object, for example a GROUPBOX control in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="header">
<xsd:annotation>
<xsd:documentation>Indicates a header item.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="heading">
<xsd:annotation>
<xsd:documentation>Indicates a heading, such has the content of &lt;h1&gt;, &lt;h2&gt;, etc. in HTML.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="hedit">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC HEDIT control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="hscrollbar">
<xsd:annotation>
<xsd:documentation>Indicates a horizontal scrollbar.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="icon">
<xsd:annotation>
<xsd:documentation>Indicates an icon, for example an ICON resource in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="iedit">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC IEDIT control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="keywords">
<xsd:annotation>
<xsd:documentation>Indicates keyword list, such as the content of the Keywords meta-data in HTML, or a K footnote in WinHelp RTF.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="label">
<xsd:annotation>
<xsd:documentation>Indicates a label object.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="linklabel">
<xsd:annotation>
<xsd:documentation>Indicates a label that is also a HTML link (not necessarily a URL).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="list">
<xsd:annotation>
<xsd:documentation>Indicates a list (a group of list-items, for example an &lt;ol&gt; or &lt;ul&gt; element in HTML).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="listbox">
<xsd:annotation>
<xsd:documentation>Indicates a listbox object, for example an LISTBOX control in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="listitem">
<xsd:annotation>
<xsd:documentation>Indicates an list item (an entry in a list).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="ltext">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC LTEXT control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="menu">
<xsd:annotation>
<xsd:documentation>Indicates a menu (a group of menu-items).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="menubar">
<xsd:annotation>
<xsd:documentation>Indicates a toolbar containing one or more tope level menus.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="menuitem">
<xsd:annotation>
<xsd:documentation>Indicates a menu item (an entry in a menu).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="menuseparator">
<xsd:annotation>
<xsd:documentation>Indicates a XUL menuseparator element.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="message">
<xsd:annotation>
<xsd:documentation>Indicates a message, for example an entry in a MESSAGETABLE resource in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="monthcalendar">
<xsd:annotation>
<xsd:documentation>Indicates a calendar control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="numericupdown">
<xsd:annotation>
<xsd:documentation>Indicates an edit box beside a spin control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="panel">
<xsd:annotation>
<xsd:documentation>Indicates a catch all for rectangular areas.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="popupmenu">
<xsd:annotation>
<xsd:documentation>Indicates a standalone menu not necessarily associated with a menubar.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="pushbox">
<xsd:annotation>
<xsd:documentation>Indicates a pushbox object, for example a PUSHBOX control in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="pushbutton">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC PUSHBUTTON control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="radio">
<xsd:annotation>
<xsd:documentation>Indicates a radio button object.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="radiobuttonmenuitem">
<xsd:annotation>
<xsd:documentation>Indicates a menuitem with associated radio button.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="rcdata">
<xsd:annotation>
<xsd:documentation>Indicates raw data resources for an application.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="row">
<xsd:annotation>
<xsd:documentation>Indicates a row in a table.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="rtext">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC RTEXT control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="scrollpane">
<xsd:annotation>
<xsd:documentation>Indicates a user navigable container used to show a portion of a document.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="separator">
<xsd:annotation>
<xsd:documentation>Indicates a generic divider object (e.g. menu group separator).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="shortcut">
<xsd:annotation>
<xsd:documentation>Windows accelerators, shortcuts in resource or property files.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="spinner">
<xsd:annotation>
<xsd:documentation>Indicates a UI control to indicate process activity but not progress.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="splitter">
<xsd:annotation>
<xsd:documentation>Indicates a splitter bar.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="state3">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC STATE3 control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="statusbar">
<xsd:annotation>
<xsd:documentation>Indicates a window for providing feedback to the users, like 'read-only', etc.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="string">
<xsd:annotation>
<xsd:documentation>Indicates a string, for example an entry in a STRINGTABLE resource in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="tabcontrol">
<xsd:annotation>
<xsd:documentation>Indicates a layers of controls with a tab to select layers.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="table">
<xsd:annotation>
<xsd:documentation>Indicates a display and edits regular two-dimensional tables of cells.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="textbox">
<xsd:annotation>
<xsd:documentation>Indicates a XUL textbox element.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="togglebutton">
<xsd:annotation>
<xsd:documentation>Indicates a UI button that can be toggled to on or off state.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="toolbar">
<xsd:annotation>
<xsd:documentation>Indicates an array of controls, usually buttons.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="tooltip">
<xsd:annotation>
<xsd:documentation>Indicates a pop up tool tip text.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="trackbar">
<xsd:annotation>
<xsd:documentation>Indicates a bar with a pointer indicating a position within a certain range.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="tree">
<xsd:annotation>
<xsd:documentation>Indicates a control that displays a set of hierarchical data.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="uri">
<xsd:annotation>
<xsd:documentation>Indicates a URI (URN or URL).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="userbutton">
<xsd:annotation>
<xsd:documentation>Indicates a Windows RC USERBUTTON control.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="usercontrol">
<xsd:annotation>
<xsd:documentation>Indicates a user-defined control like CONTROL control in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="var">
<xsd:annotation>
<xsd:documentation>Indicates the text of a variable.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="versioninfo">
<xsd:annotation>
<xsd:documentation>Indicates version information about a resource like VERSIONINFO in Windows.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="vscrollbar">
<xsd:annotation>
<xsd:documentation>Indicates a vertical scrollbar.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="window">
<xsd:annotation>
<xsd:documentation>Indicates a graphical window.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="size-unitValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'size-unit'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="byte">
<xsd:annotation>
<xsd:documentation>Indicates a size in 8-bit bytes.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="char">
<xsd:annotation>
<xsd:documentation>Indicates a size in Unicode characters.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="col">
<xsd:annotation>
<xsd:documentation>Indicates a size in columns. Used for HTML text area.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="cm">
<xsd:annotation>
<xsd:documentation>Indicates a size in centimeters.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="dlgunit">
<xsd:annotation>
<xsd:documentation>Indicates a size in dialog units, as defined in Windows resources.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="em">
<xsd:annotation>
<xsd:documentation>Indicates a size in 'font-size' units (as defined in CSS).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="ex">
<xsd:annotation>
<xsd:documentation>Indicates a size in 'x-height' units (as defined in CSS).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="glyph">
<xsd:annotation>
<xsd:documentation>Indicates a size in glyphs. A glyph is considered to be one or more combined Unicode characters that represent a single displayable text character. Sometimes referred to as a 'grapheme cluster'</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="in">
<xsd:annotation>
<xsd:documentation>Indicates a size in inches.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="mm">
<xsd:annotation>
<xsd:documentation>Indicates a size in millimeters.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="percent">
<xsd:annotation>
<xsd:documentation>Indicates a size in percentage.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="pixel">
<xsd:annotation>
<xsd:documentation>Indicates a size in pixels.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="point">
<xsd:annotation>
<xsd:documentation>Indicates a size in point.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="row">
<xsd:annotation>
<xsd:documentation>Indicates a size in rows. Used for HTML text area.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="stateValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'state'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="final">
<xsd:annotation>
<xsd:documentation>Indicates the terminating state.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="needs-adaptation">
<xsd:annotation>
<xsd:documentation>Indicates only non-textual information needs adaptation.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="needs-l10n">
<xsd:annotation>
<xsd:documentation>Indicates both text and non-textual information needs adaptation.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="needs-review-adaptation">
<xsd:annotation>
<xsd:documentation>Indicates only non-textual information needs review.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="needs-review-l10n">
<xsd:annotation>
<xsd:documentation>Indicates both text and non-textual information needs review.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="needs-review-translation">
<xsd:annotation>
<xsd:documentation>Indicates that only the text of the item needs to be reviewed.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="needs-translation">
<xsd:annotation>
<xsd:documentation>Indicates that the item needs to be translated.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="new">
<xsd:annotation>
<xsd:documentation>Indicates that the item is new. For example, translation units that were not in a previous version of the document.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="signed-off">
<xsd:annotation>
<xsd:documentation>Indicates that changes are reviewed and approved.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="translated">
<xsd:annotation>
<xsd:documentation>Indicates that the item has been translated.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="state-qualifierValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'state-qualifier'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="exact-match">
<xsd:annotation>
<xsd:documentation>Indicates an exact match. An exact match occurs when a source text of a segment is exactly the same as the source text of a segment that was translated previously.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="fuzzy-match">
<xsd:annotation>
<xsd:documentation>Indicates a fuzzy match. A fuzzy match occurs when a source text of a segment is very similar to the source text of a segment that was translated previously (e.g. when the difference is casing, a few changed words, white-space discripancy, etc.).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="id-match">
<xsd:annotation>
<xsd:documentation>Indicates a match based on matching IDs (in addition to matching text).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="leveraged-glossary">
<xsd:annotation>
<xsd:documentation>Indicates a translation derived from a glossary.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="leveraged-inherited">
<xsd:annotation>
<xsd:documentation>Indicates a translation derived from existing translation.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="leveraged-mt">
<xsd:annotation>
<xsd:documentation>Indicates a translation derived from machine translation.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="leveraged-repository">
<xsd:annotation>
<xsd:documentation>Indicates a translation derived from a translation repository.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="leveraged-tm">
<xsd:annotation>
<xsd:documentation>Indicates a translation derived from a translation memory.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="mt-suggestion">
<xsd:annotation>
<xsd:documentation>Indicates the translation is suggested by machine translation.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="rejected-grammar">
<xsd:annotation>
<xsd:documentation>Indicates that the item has been rejected because of incorrect grammar.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="rejected-inaccurate">
<xsd:annotation>
<xsd:documentation>Indicates that the item has been rejected because it is incorrect.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="rejected-length">
<xsd:annotation>
<xsd:documentation>Indicates that the item has been rejected because it is too long or too short.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="rejected-spelling">
<xsd:annotation>
<xsd:documentation>Indicates that the item has been rejected because of incorrect spelling.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="tm-suggestion">
<xsd:annotation>
<xsd:documentation>Indicates the translation is suggested by translation memory.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="unitValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'unit'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="word">
<xsd:annotation>
<xsd:documentation>Refers to words.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="page">
<xsd:annotation>
<xsd:documentation>Refers to pages.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="trans-unit">
<xsd:annotation>
<xsd:documentation>Refers to &lt;trans-unit&gt; elements.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="bin-unit">
<xsd:annotation>
<xsd:documentation>Refers to &lt;bin-unit&gt; elements.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="glyph">
<xsd:annotation>
<xsd:documentation>Refers to glyphs.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="item">
<xsd:annotation>
<xsd:documentation>Refers to &lt;trans-unit&gt; and/or &lt;bin-unit&gt; elements.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="instance">
<xsd:annotation>
<xsd:documentation>Refers to the occurrences of instances defined by the count-type value.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="character">
<xsd:annotation>
<xsd:documentation>Refers to characters.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="line">
<xsd:annotation>
<xsd:documentation>Refers to lines.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="sentence">
<xsd:annotation>
<xsd:documentation>Refers to sentences.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="paragraph">
<xsd:annotation>
<xsd:documentation>Refers to paragraphs.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="segment">
<xsd:annotation>
<xsd:documentation>Refers to segments.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="placeable">
<xsd:annotation>
<xsd:documentation>Refers to placeables (inline elements).</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="priorityValueList">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'priority'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:positiveInteger">
<xsd:enumeration value="1">
<xsd:annotation>
<xsd:documentation>Highest priority.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="2">
<xsd:annotation>
<xsd:documentation>High priority.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="3">
<xsd:annotation>
<xsd:documentation>High priority, but not as important as 2.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="4">
<xsd:annotation>
<xsd:documentation>High priority, but not as important as 3.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="5">
<xsd:annotation>
<xsd:documentation>Medium priority, but more important than 6.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="6">
<xsd:annotation>
<xsd:documentation>Medium priority, but less important than 5.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="7">
<xsd:annotation>
<xsd:documentation>Low priority, but more important than 8.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="8">
<xsd:annotation>
<xsd:documentation>Low priority, but more important than 9.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="9">
<xsd:annotation>
<xsd:documentation>Low priority.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="10">
<xsd:annotation>
<xsd:documentation>Lowest priority.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="reformatValueYesNo">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="yes">
<xsd:annotation>
<xsd:documentation>This value indicates that all properties can be reformatted. This value must be used alone.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="no">
<xsd:annotation>
<xsd:documentation>This value indicates that no properties should be reformatted. This value must be used alone.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="reformatValueList">
<xsd:list>
<xsd:simpleType>
<xsd:union memberTypes="xlf:XTend">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="coord">
<xsd:annotation>
<xsd:documentation>This value indicates that all information in the coord attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="coord-x">
<xsd:annotation>
<xsd:documentation>This value indicates that the x information in the coord attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="coord-y">
<xsd:annotation>
<xsd:documentation>This value indicates that the y information in the coord attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="coord-cx">
<xsd:annotation>
<xsd:documentation>This value indicates that the cx information in the coord attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="coord-cy">
<xsd:annotation>
<xsd:documentation>This value indicates that the cy information in the coord attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="font">
<xsd:annotation>
<xsd:documentation>This value indicates that all the information in the font attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="font-name">
<xsd:annotation>
<xsd:documentation>This value indicates that the name information in the font attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="font-size">
<xsd:annotation>
<xsd:documentation>This value indicates that the size information in the font attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="font-weight">
<xsd:annotation>
<xsd:documentation>This value indicates that the weight information in the font attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="css-style">
<xsd:annotation>
<xsd:documentation>This value indicates that the information in the css-style attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="style">
<xsd:annotation>
<xsd:documentation>This value indicates that the information in the style attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="ex-style">
<xsd:annotation>
<xsd:documentation>This value indicates that the information in the exstyle attribute can be modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:union>
</xsd:simpleType>
</xsd:list>
</xsd:simpleType>
<xsd:simpleType name="purposeValueList">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="information">
<xsd:annotation>
<xsd:documentation>Indicates that the context is informational in nature, specifying for example, how a term should be translated. Thus, should be displayed to anyone editing the XLIFF document.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="location">
<xsd:annotation>
<xsd:documentation>Indicates that the context-group is used to specify where the term was found in the translatable source. Thus, it is not displayed.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="match">
<xsd:annotation>
<xsd:documentation>Indicates that the context information should be used during translation memory lookups. Thus, it is not displayed.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="alttranstypeValueList">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="proposal">
<xsd:annotation>
<xsd:documentation>Represents a translation proposal from a translation memory or other resource.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="previous-version">
<xsd:annotation>
<xsd:documentation>Represents a previous version of the target element.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="rejected">
<xsd:annotation>
<xsd:documentation>Represents a rejected version of the target element.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="reference">
<xsd:annotation>
<xsd:documentation>Represents a translation to be used for reference purposes only, for example from a related product or a different language.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="accepted">
<xsd:annotation>
<xsd:documentation>Represents a proposed translation that was used for the translation of the trans-unit, possibly modified.</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
<!-- Other Types -->
<xsd:complexType name="ElemType_ExternalReference">
<xsd:choice>
<xsd:element ref="xlf:internal-file"/>
<xsd:element ref="xlf:external-file"/>
</xsd:choice>
</xsd:complexType>
<xsd:simpleType name="AttrType_purpose">
<xsd:list>
<xsd:simpleType>
<xsd:union memberTypes="xlf:purposeValueList xlf:XTend"/>
</xsd:simpleType>
</xsd:list>
</xsd:simpleType>
<xsd:simpleType name="AttrType_datatype">
<xsd:union memberTypes="xlf:datatypeValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_restype">
<xsd:union memberTypes="xlf:restypeValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_alttranstype">
<xsd:union memberTypes="xlf:alttranstypeValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_context-type">
<xsd:union memberTypes="xlf:context-typeValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_state">
<xsd:union memberTypes="xlf:stateValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_state-qualifier">
<xsd:union memberTypes="xlf:state-qualifierValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_count-type">
<xsd:union memberTypes="xlf:restypeValueList xlf:count-typeValueList xlf:datatypeValueList xlf:stateValueList xlf:state-qualifierValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_InlineDelimiters">
<xsd:union memberTypes="xlf:InlineDelimitersValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_InlinePlaceholders">
<xsd:union memberTypes="xlf:InlinePlaceholdersValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_size-unit">
<xsd:union memberTypes="xlf:size-unitValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_mtype">
<xsd:union memberTypes="xlf:mtypeValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_unit">
<xsd:union memberTypes="xlf:unitValueList xlf:XTend"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_priority">
<xsd:union memberTypes="xlf:priorityValueList"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_reformat">
<xsd:union memberTypes="xlf:reformatValueYesNo xlf:reformatValueList"/>
</xsd:simpleType>
<xsd:simpleType name="AttrType_YesNo">
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="yes"/>
<xsd:enumeration value="no"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="AttrType_Position">
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="open"/>
<xsd:enumeration value="close"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="AttrType_assoc">
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="preceding"/>
<xsd:enumeration value="following"/>
<xsd:enumeration value="both"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="AttrType_annotates">
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="source"/>
<xsd:enumeration value="target"/>
<xsd:enumeration value="general"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="AttrType_Coordinates">
<xsd:annotation>
<xsd:documentation>Values for the attribute 'coord'.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:pattern value="(-?\d+|#);(-?\d+|#);(-?\d+|#);(-?\d+|#)"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="AttrType_Version">
<xsd:annotation>
<xsd:documentation>Version values: 1.0 and 1.1 are allowed for backward compatibility.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="1.2"/>
<xsd:enumeration value="1.1"/>
<xsd:enumeration value="1.0"/>
</xsd:restriction>
</xsd:simpleType>
<!-- Groups -->
<xsd:group name="ElemGroup_TextContent">
<xsd:choice>
<xsd:element ref="xlf:g"/>
<xsd:element ref="xlf:bpt"/>
<xsd:element ref="xlf:ept"/>
<xsd:element ref="xlf:ph"/>
<xsd:element ref="xlf:it"/>
<xsd:element ref="xlf:mrk"/>
<xsd:element ref="xlf:x"/>
<xsd:element ref="xlf:bx"/>
<xsd:element ref="xlf:ex"/>
</xsd:choice>
</xsd:group>
<xsd:attributeGroup name="AttrGroup_TextContent">
<xsd:attribute name="id" type="xsd:string" use="required"/>
<xsd:attribute name="xid" type="xsd:string" use="optional"/>
<xsd:attribute name="equiv-text" type="xsd:string" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:attributeGroup>
<!-- XLIFF Structure -->
<xsd:element name="xliff">
<xsd:complexType>
<xsd:sequence maxOccurs="unbounded">
<xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
<xsd:element ref="xlf:file"/>
</xsd:sequence>
<xsd:attribute name="version" type="xlf:AttrType_Version" use="required"/>
<xsd:attribute ref="xml:lang" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="file">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" ref="xlf:header"/>
<xsd:element ref="xlf:body"/>
</xsd:sequence>
<xsd:attribute name="original" type="xsd:string" use="required"/>
<xsd:attribute name="source-language" type="xsd:language" use="required"/>
<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="required"/>
<xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
<xsd:attribute name="date" type="xsd:dateTime" use="optional"/>
<xsd:attribute ref="xml:space" use="optional"/>
<xsd:attribute name="category" type="xsd:string" use="optional"/>
<xsd:attribute name="target-language" type="xsd:language" use="optional"/>
<xsd:attribute name="product-name" type="xsd:string" use="optional"/>
<xsd:attribute name="product-version" type="xsd:string" use="optional"/>
<xsd:attribute name="build-num" type="xsd:string" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
<xsd:unique name="U_group_id">
<xsd:selector xpath=".//xlf:group"/>
<xsd:field xpath="@id"/>
</xsd:unique>
<xsd:key name="K_unit_id">
<xsd:selector xpath=".//xlf:trans-unit|.//xlf:bin-unit"/>
<xsd:field xpath="@id"/>
</xsd:key>
<xsd:keyref name="KR_unit_id" refer="xlf:K_unit_id">
<xsd:selector xpath=".//bpt|.//ept|.//it|.//ph|.//g|.//x|.//bx|.//ex|.//sub"/>
<xsd:field xpath="@xid"/>
</xsd:keyref>
<xsd:key name="K_tool-id">
<xsd:selector xpath="xlf:header/xlf:tool"/>
<xsd:field xpath="@tool-id"/>
</xsd:key>
<xsd:keyref name="KR_file_tool-id" refer="xlf:K_tool-id">
<xsd:selector xpath="."/>
<xsd:field xpath="@tool-id"/>
</xsd:keyref>
<xsd:keyref name="KR_phase_tool-id" refer="xlf:K_tool-id">
<xsd:selector xpath="xlf:header/xlf:phase-group/xlf:phase"/>
<xsd:field xpath="@tool-id"/>
</xsd:keyref>
<xsd:keyref name="KR_alt-trans_tool-id" refer="xlf:K_tool-id">
<xsd:selector xpath=".//xlf:trans-unit/xlf:alt-trans"/>
<xsd:field xpath="@tool-id"/>
</xsd:keyref>
<xsd:key name="K_count-group_name">
<xsd:selector xpath=".//xlf:count-group"/>
<xsd:field xpath="@name"/>
</xsd:key>
<xsd:unique name="U_context-group_name">
<xsd:selector xpath=".//xlf:context-group"/>
<xsd:field xpath="@name"/>
</xsd:unique>
<xsd:key name="K_phase-name">
<xsd:selector xpath="xlf:header/xlf:phase-group/xlf:phase"/>
<xsd:field xpath="@phase-name"/>
</xsd:key>
<xsd:keyref name="KR_phase-name" refer="xlf:K_phase-name">
<xsd:selector xpath=".//xlf:count|.//xlf:trans-unit|.//xlf:target|.//bin-unit|.//bin-target"/>
<xsd:field xpath="@phase-name"/>
</xsd:keyref>
<xsd:unique name="U_uid">
<xsd:selector xpath=".//xlf:external-file"/>
<xsd:field xpath="@uid"/>
</xsd:unique>
</xsd:element>
<xsd:element name="header">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" name="skl" type="xlf:ElemType_ExternalReference"/>
<xsd:element minOccurs="0" ref="xlf:phase-group"/>
<xsd:choice maxOccurs="unbounded" minOccurs="0">
<xsd:element name="glossary" type="xlf:ElemType_ExternalReference"/>
<xsd:element name="reference" type="xlf:ElemType_ExternalReference"/>
<xsd:element ref="xlf:count-group"/>
<xsd:element ref="xlf:note"/>
<xsd:element ref="xlf:tool"/>
</xsd:choice>
<xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="internal-file">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="form" type="xsd:string"/>
<xsd:attribute name="crc" type="xsd:NMTOKEN"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="external-file">
<xsd:complexType>
<xsd:attribute name="href" type="xsd:string" use="required"/>
<xsd:attribute name="crc" type="xsd:NMTOKEN"/>
<xsd:attribute name="uid" type="xsd:NMTOKEN"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="note">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute ref="xml:lang" use="optional"/>
<xsd:attribute default="1" name="priority" type="xlf:AttrType_priority" use="optional"/>
<xsd:attribute name="from" type="xsd:string" use="optional"/>
<xsd:attribute default="general" name="annotates" type="xlf:AttrType_annotates" use="optional"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="phase-group">
<xsd:complexType>
<xsd:sequence maxOccurs="unbounded">
<xsd:element ref="xlf:phase"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="phase">
<xsd:complexType>
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
<xsd:element ref="xlf:note"/>
</xsd:sequence>
<xsd:attribute name="phase-name" type="xsd:string" use="required"/>
<xsd:attribute name="process-name" type="xsd:string" use="required"/>
<xsd:attribute name="company-name" type="xsd:string" use="optional"/>
<xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
<xsd:attribute name="date" type="xsd:dateTime" use="optional"/>
<xsd:attribute name="job-id" type="xsd:string" use="optional"/>
<xsd:attribute name="contact-name" type="xsd:string" use="optional"/>
<xsd:attribute name="contact-email" type="xsd:string" use="optional"/>
<xsd:attribute name="contact-phone" type="xsd:string" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="count-group">
<xsd:complexType>
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
<xsd:element ref="xlf:count"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="count">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="count-type" type="xlf:AttrType_count-type" use="optional"/>
<xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
<xsd:attribute default="word" name="unit" type="xlf:AttrType_unit" use="optional"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="context-group">
<xsd:complexType>
<xsd:sequence maxOccurs="unbounded">
<xsd:element ref="xlf:context"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="optional"/>
<xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="purpose" type="xlf:AttrType_purpose" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="context">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="context-type" type="xlf:AttrType_context-type" use="required"/>
<xsd:attribute default="no" name="match-mandatory" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="tool">
<xsd:complexType mixed="true">
<xsd:sequence>
<xsd:any namespace="##any" processContents="strict" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="tool-id" type="xsd:string" use="required"/>
<xsd:attribute name="tool-name" type="xsd:string" use="required"/>
<xsd:attribute name="tool-version" type="xsd:string" use="optional"/>
<xsd:attribute name="tool-company" type="xsd:string" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="body">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded" minOccurs="0">
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:group"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:trans-unit"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:bin-unit"/>
</xsd:choice>
</xsd:complexType>
</xsd:element>
<xsd:element name="group">
<xsd:complexType>
<xsd:sequence>
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:context-group"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:count-group"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:note"/>
<xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
</xsd:sequence>
<xsd:choice maxOccurs="unbounded">
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:group"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:trans-unit"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:bin-unit"/>
</xsd:choice>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="optional"/>
<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
<xsd:attribute default="default" ref="xml:space" use="optional"/>
<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
<xsd:attribute name="resname" type="xsd:string" use="optional"/>
<xsd:attribute name="extradata" type="xsd:string" use="optional"/>
<xsd:attribute name="extype" type="xsd:string" use="optional"/>
<xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="menu" type="xsd:string" use="optional"/>
<xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
<xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
<xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
<xsd:attribute name="font" type="xsd:string" use="optional"/>
<xsd:attribute name="css-style" type="xsd:string" use="optional"/>
<xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
<xsd:attribute default="pixel" name="size-unit" type="xlf:AttrType_size-unit" use="optional"/>
<xsd:attribute name="maxwidth" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="minwidth" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="maxheight" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="minheight" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="maxbytes" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="minbytes" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="charclass" type="xsd:string" use="optional"/>
<xsd:attribute default="no" name="merged-trans" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="trans-unit">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="xlf:source"/>
<xsd:element minOccurs="0" ref="xlf:seg-source"/>
<xsd:element minOccurs="0" ref="xlf:target"/>
<xsd:choice maxOccurs="unbounded" minOccurs="0">
<xsd:element ref="xlf:context-group"/>
<xsd:element ref="xlf:count-group"/>
<xsd:element ref="xlf:note"/>
<xsd:element ref="xlf:alt-trans"/>
</xsd:choice>
<xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required"/>
<xsd:attribute name="approved" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
<xsd:attribute default="default" ref="xml:space" use="optional"/>
<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
<xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
<xsd:attribute name="resname" type="xsd:string" use="optional"/>
<xsd:attribute name="extradata" type="xsd:string" use="optional"/>
<xsd:attribute name="extype" type="xsd:string" use="optional"/>
<xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="menu" type="xsd:string" use="optional"/>
<xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
<xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
<xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
<xsd:attribute name="font" type="xsd:string" use="optional"/>
<xsd:attribute name="css-style" type="xsd:string" use="optional"/>
<xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute default="pixel" name="size-unit" type="xlf:AttrType_size-unit" use="optional"/>
<xsd:attribute name="maxwidth" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="minwidth" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="maxheight" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="minheight" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="maxbytes" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="minbytes" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="charclass" type="xsd:string" use="optional"/>
<xsd:attribute default="yes" name="merged-trans" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
<xsd:unique name="U_tu_segsrc_mid">
<xsd:selector xpath="./xlf:seg-source/xlf:mrk"/>
<xsd:field xpath="@mid"/>
</xsd:unique>
<xsd:keyref name="KR_tu_segsrc_mid" refer="xlf:U_tu_segsrc_mid">
<xsd:selector xpath="./xlf:target/xlf:mrk|./xlf:alt-trans"/>
<xsd:field xpath="@mid"/>
</xsd:keyref>
</xsd:element>
<xsd:element name="source">
<xsd:complexType mixed="true">
<xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
<xsd:attribute ref="xml:lang" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
<xsd:unique name="U_source_bpt_rid">
<xsd:selector xpath=".//xlf:bpt"/>
<xsd:field xpath="@rid"/>
</xsd:unique>
<xsd:keyref name="KR_source_ept_rid" refer="xlf:U_source_bpt_rid">
<xsd:selector xpath=".//xlf:ept"/>
<xsd:field xpath="@rid"/>
</xsd:keyref>
<xsd:unique name="U_source_bx_rid">
<xsd:selector xpath=".//xlf:bx"/>
<xsd:field xpath="@rid"/>
</xsd:unique>
<xsd:keyref name="KR_source_ex_rid" refer="xlf:U_source_bx_rid">
<xsd:selector xpath=".//xlf:ex"/>
<xsd:field xpath="@rid"/>
</xsd:keyref>
</xsd:element>
<xsd:element name="seg-source">
<xsd:complexType mixed="true">
<xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
<xsd:attribute ref="xml:lang" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
<xsd:unique name="U_segsrc_bpt_rid">
<xsd:selector xpath=".//xlf:bpt"/>
<xsd:field xpath="@rid"/>
</xsd:unique>
<xsd:keyref name="KR_segsrc_ept_rid" refer="xlf:U_segsrc_bpt_rid">
<xsd:selector xpath=".//xlf:ept"/>
<xsd:field xpath="@rid"/>
</xsd:keyref>
<xsd:unique name="U_segsrc_bx_rid">
<xsd:selector xpath=".//xlf:bx"/>
<xsd:field xpath="@rid"/>
</xsd:unique>
<xsd:keyref name="KR_segsrc_ex_rid" refer="xlf:U_segsrc_bx_rid">
<xsd:selector xpath=".//xlf:ex"/>
<xsd:field xpath="@rid"/>
</xsd:keyref>
</xsd:element>
<xsd:element name="target">
<xsd:complexType mixed="true">
<xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
<xsd:attribute name="state" type="xlf:AttrType_state" use="optional"/>
<xsd:attribute name="state-qualifier" type="xlf:AttrType_state-qualifier" use="optional"/>
<xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute ref="xml:lang" use="optional"/>
<xsd:attribute name="resname" type="xsd:string" use="optional"/>
<xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
<xsd:attribute name="font" type="xsd:string" use="optional"/>
<xsd:attribute name="css-style" type="xsd:string" use="optional"/>
<xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute default="yes" name="equiv-trans" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
<xsd:unique name="U_target_bpt_rid">
<xsd:selector xpath=".//xlf:bpt"/>
<xsd:field xpath="@rid"/>
</xsd:unique>
<xsd:keyref name="KR_target_ept_rid" refer="xlf:U_target_bpt_rid">
<xsd:selector xpath=".//xlf:ept"/>
<xsd:field xpath="@rid"/>
</xsd:keyref>
<xsd:unique name="U_target_bx_rid">
<xsd:selector xpath=".//xlf:bx"/>
<xsd:field xpath="@rid"/>
</xsd:unique>
<xsd:keyref name="KR_target_ex_rid" refer="xlf:U_target_bx_rid">
<xsd:selector xpath=".//xlf:ex"/>
<xsd:field xpath="@rid"/>
</xsd:keyref>
</xsd:element>
<xsd:element name="alt-trans">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" ref="xlf:source"/>
<xsd:element minOccurs="0" ref="xlf:seg-source"/>
<xsd:element maxOccurs="1" ref="xlf:target"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:context-group"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:note"/>
<xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
</xsd:sequence>
<xsd:attribute name="match-quality" type="xsd:string" use="optional"/>
<xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
<xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute ref="xml:lang" use="optional"/>
<xsd:attribute name="origin" type="xsd:string" use="optional"/>
<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
<xsd:attribute default="default" ref="xml:space" use="optional"/>
<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
<xsd:attribute name="resname" type="xsd:string" use="optional"/>
<xsd:attribute name="extradata" type="xsd:string" use="optional"/>
<xsd:attribute name="extype" type="xsd:string" use="optional"/>
<xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="menu" type="xsd:string" use="optional"/>
<xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
<xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
<xsd:attribute name="mid" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
<xsd:attribute name="font" type="xsd:string" use="optional"/>
<xsd:attribute name="css-style" type="xsd:string" use="optional"/>
<xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute default="proposal" name="alttranstype" type="xlf:AttrType_alttranstype" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
<xsd:unique name="U_at_segsrc_mid">
<xsd:selector xpath="./xlf:seg-source/xlf:mrk"/>
<xsd:field xpath="@mid"/>
</xsd:unique>
<xsd:keyref name="KR_at_segsrc_mid" refer="xlf:U_at_segsrc_mid">
<xsd:selector xpath="./xlf:target/xlf:mrk"/>
<xsd:field xpath="@mid"/>
</xsd:keyref>
</xsd:element>
<xsd:element name="bin-unit">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="xlf:bin-source"/>
<xsd:element minOccurs="0" ref="xlf:bin-target"/>
<xsd:choice maxOccurs="unbounded" minOccurs="0">
<xsd:element ref="xlf:context-group"/>
<xsd:element ref="xlf:count-group"/>
<xsd:element ref="xlf:note"/>
<xsd:element ref="xlf:trans-unit"/>
</xsd:choice>
<xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required"/>
<xsd:attribute name="mime-type" type="xlf:mime-typeValueList" use="required"/>
<xsd:attribute name="approved" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
<xsd:attribute name="resname" type="xsd:string" use="optional"/>
<xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="bin-source">
<xsd:complexType>
<xsd:choice>
<xsd:element ref="xlf:internal-file"/>
<xsd:element ref="xlf:external-file"/>
</xsd:choice>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="bin-target">
<xsd:complexType>
<xsd:choice>
<xsd:element ref="xlf:internal-file"/>
<xsd:element ref="xlf:external-file"/>
</xsd:choice>
<xsd:attribute name="mime-type" type="xlf:mime-typeValueList" use="optional"/>
<xsd:attribute name="state" type="xlf:AttrType_state" use="optional"/>
<xsd:attribute name="state-qualifier" type="xlf:AttrType_state-qualifier" use="optional"/>
<xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
<xsd:attribute name="resname" type="xsd:string" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
</xsd:element>
<!-- Element for inline codes -->
<xsd:element name="g">
<xsd:complexType mixed="true">
<xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
<xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="x">
<xsd:complexType>
<xsd:attribute name="ctype" type="xlf:AttrType_InlinePlaceholders" use="optional"/>
<xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="bx">
<xsd:complexType>
<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
<xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
<xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="ex">
<xsd:complexType>
<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
<xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="ph">
<xsd:complexType mixed="true">
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
<xsd:element ref="xlf:sub"/>
</xsd:sequence>
<xsd:attribute name="ctype" type="xlf:AttrType_InlinePlaceholders" use="optional"/>
<xsd:attribute name="crc" type="xsd:string" use="optional"/>
<xsd:attribute name="assoc" type="xlf:AttrType_assoc" use="optional"/>
<xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="bpt">
<xsd:complexType mixed="true">
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
<xsd:element ref="xlf:sub"/>
</xsd:sequence>
<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
<xsd:attribute name="crc" type="xsd:string" use="optional"/>
<xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="ept">
<xsd:complexType mixed="true">
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
<xsd:element ref="xlf:sub"/>
</xsd:sequence>
<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="crc" type="xsd:string" use="optional"/>
<xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="it">
<xsd:complexType mixed="true">
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
<xsd:element ref="xlf:sub"/>
</xsd:sequence>
<xsd:attribute name="pos" type="xlf:AttrType_Position" use="required"/>
<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
<xsd:attribute name="crc" type="xsd:string" use="optional"/>
<xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="sub">
<xsd:complexType mixed="true">
<xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
<xsd:attribute name="xid" type="xsd:string" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="mrk">
<xsd:complexType mixed="true">
<xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
<xsd:attribute name="mtype" type="xlf:AttrType_mtype" use="required"/>
<xsd:attribute name="mid" type="xsd:NMTOKEN" use="optional"/>
<xsd:attribute name="comment" type="xsd:string" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<?xml version='1.0'?>
<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns ="http://www.w3.org/1999/xhtml"
xml:lang="en">
<xs:annotation>
<xs:documentation>
<div>
<h1>About the XML namespace</h1>
<div class="bodytext">
<p>
This schema document describes the XML namespace, in a form
suitable for import by other schema documents.
</p>
<p>
See <a href="http://www.w3.org/XML/1998/namespace.html">
http://www.w3.org/XML/1998/namespace.html</a> and
<a href="http://www.w3.org/TR/REC-xml">
http://www.w3.org/TR/REC-xml</a> for information
about this namespace.
</p>
<p>
Note that local names in this namespace are intended to be
defined only by the World Wide Web Consortium or its subgroups.
The names currently defined in this namespace are listed below.
They should not be used with conflicting semantics by any Working
Group, specification, or document instance.
</p>
<p>
See further below in this document for more information about <a
href="#usage">how to refer to this schema document from your own
XSD schema documents</a> and about <a href="#nsversioning">the
namespace-versioning policy governing this schema document</a>.
</p>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:attribute name="lang">
<xs:annotation>
<xs:documentation>
<div>
<h3>lang (as an attribute name)</h3>
<p>
denotes an attribute whose value
is a language code for the natural language of the content of
any element; its value is inherited. This name is reserved
by virtue of its definition in the XML specification.</p>
</div>
<div>
<h4>Notes</h4>
<p>
Attempting to install the relevant ISO 2- and 3-letter
codes as the enumerated possible values is probably never
going to be a realistic possibility.
</p>
<p>
See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
and the IANA language subtag registry at
<a href="http://www.iana.org/assignments/language-subtag-registry">
http://www.iana.org/assignments/language-subtag-registry</a>
for further information.
</p>
<p>
The union allows for the 'un-declaration' of xml:lang with
the empty string.
</p>
</div>
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:union memberTypes="xs:language">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value=""/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="space">
<xs:annotation>
<xs:documentation>
<div>
<h3>space (as an attribute name)</h3>
<p>
denotes an attribute whose
value is a keyword indicating what whitespace processing
discipline is intended for the content of the element; its
value is inherited. This name is reserved by virtue of its
definition in the XML specification.</p>
</div>
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:NCName">
<xs:enumeration value="default"/>
<xs:enumeration value="preserve"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
<xs:documentation>
<div>
<h3>base (as an attribute name)</h3>
<p>
denotes an attribute whose value
provides a URI to be used as the base for interpreting any
relative URIs in the scope of the element on which it
appears; its value is inherited. This name is reserved
by virtue of its definition in the XML Base specification.</p>
<p>
See <a
href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
for information about this attribute.
</p>
</div>
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="id" type="xs:ID">
<xs:annotation>
<xs:documentation>
<div>
<h3>id (as an attribute name)</h3>
<p>
denotes an attribute whose value
should be interpreted as if declared to be of type ID.
This name is reserved by virtue of its definition in the
xml:id specification.</p>
<p>
See <a
href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
for information about this attribute.
</p>
</div>
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attributeGroup name="specialAttrs">
<xs:attribute ref="xml:base"/>
<xs:attribute ref="xml:lang"/>
<xs:attribute ref="xml:space"/>
<xs:attribute ref="xml:id"/>
</xs:attributeGroup>
<xs:annotation>
<xs:documentation>
<div>
<h3>Father (in any context at all)</h3>
<div class="bodytext">
<p>
denotes Jon Bosak, the chair of
the original XML Working Group. This name is reserved by
the following decision of the W3C XML Plenary and
XML Coordination groups:
</p>
<blockquote>
<p>
In appreciation for his vision, leadership and
dedication the W3C XML Plenary on this 10th day of
February, 2000, reserves for Jon Bosak in perpetuity
the XML name "xml:Father".
</p>
</blockquote>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:annotation>
<xs:documentation>
<div xml:id="usage" id="usage">
<h2><a name="usage">About this schema document</a></h2>
<div class="bodytext">
<p>
This schema defines attributes and an attribute group suitable
for use by schemas wishing to allow <code>xml:base</code>,
<code>xml:lang</code>, <code>xml:space</code> or
<code>xml:id</code> attributes on elements they define.
</p>
<p>
To enable this, such a schema must import this schema for
the XML namespace, e.g. as follows:
</p>
<pre>
&lt;schema . . .>
. . .
&lt;import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
</pre>
<p>
or
</p>
<pre>
&lt;import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
</pre>
<p>
Subsequently, qualified reference to any of the attributes or the
group defined below will have the desired effect, e.g.
</p>
<pre>
&lt;type . . .>
. . .
&lt;attributeGroup ref="xml:specialAttrs"/>
</pre>
<p>
will define a type which will schema-validate an instance element
with any of those attributes.
</p>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:annotation>
<xs:documentation>
<div id="nsversioning" xml:id="nsversioning">
<h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
<div class="bodytext">
<p>
In keeping with the XML Schema WG's standard versioning
policy, this schema document will persist at
<a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd</a>.
</p>
<p>
At the date of issue it can also be found at
<a href="http://www.w3.org/2001/xml.xsd">
http://www.w3.org/2001/xml.xsd</a>.
</p>
<p>
The schema document at that URI may however change in the future,
in order to remain compatible with the latest version of XML
Schema itself, or with the XML namespace itself. In other words,
if the XML Schema or XML namespaces change, the version of this
document at <a href="http://www.w3.org/2001/xml.xsd">
http://www.w3.org/2001/xml.xsd
</a>
will change accordingly; the version at
<a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd
</a>
will not change.
</p>
<p>
Previous dated (and unchanging) versions of this schema
document are at:
</p>
<ul>
<li><a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd</a></li>
<li><a href="http://www.w3.org/2007/08/xml.xsd">
http://www.w3.org/2007/08/xml.xsd</a></li>
<li><a href="http://www.w3.org/2004/10/xml.xsd">
http://www.w3.org/2004/10/xml.xsd</a></li>
<li><a href="http://www.w3.org/2001/03/xml.xsd">
http://www.w3.org/2001/03/xml.xsd</a></li>
</ul>
</div>
</div>
</xs:documentation>
</xs:annotation>
</xs:schema>
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Config\Resource\FileResource;
/**
* XliffFileLoader loads translations from XLIFF files.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class XliffFileLoader implements LoaderInterface
{
/**
* {@inheritdoc}
*
* @api
*/
public function load($resource, $locale, $domain = 'messages')
{
if (!stream_is_local($resource)) {
throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $resource));
}
$xml = $this->parseFile($resource);
$xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
$catalogue = new MessageCatalogue($locale);
foreach ($xml->xpath('//xliff:trans-unit') as $translation) {
$catalogue->set((string) $translation->source, (string) $translation->target, $domain);
}
$catalogue->addResource(new FileResource($resource));
return $catalogue;
}
/**
* Validates and parses the given file into a SimpleXMLElement
*
* @param string $file
*
* @return SimpleXMLElement
*/
private function parseFile($file)
{
$dom = new \DOMDocument();
$current = libxml_use_internal_errors(true);
if (!@$dom->load($file, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
throw new \RuntimeException(implode("\n", $this->getXmlErrors()));
}
$location = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
$parts = explode('/', $location);
if (0 === stripos($location, 'phar://')) {
$tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
if ($tmpfile) {
copy($location, $tmpfile);
$parts = explode('/', str_replace('\\', '/', $tmpfile));
}
}
$drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
$location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
$source = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-1.2-strict.xsd');
$source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source);
if (!@$dom->schemaValidateSource($source)) {
throw new \RuntimeException(implode("\n", $this->getXmlErrors()));
}
$dom->validateOnParse = true;
$dom->normalizeDocument();
libxml_use_internal_errors($current);
return simplexml_import_dom($dom);
}
/**
* Returns the XML errors of the internal XML parser
*
* @return array An array of errors
*/
private function getXmlErrors()
{
$errors = array();
foreach (libxml_get_errors() as $error) {
$errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
$error->code,
trim($error->message),
$error->file ? $error->file : 'n/a',
$error->line,
$error->column
);
}
libxml_clear_errors();
libxml_use_internal_errors(false);
return $errors;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Yaml\Yaml;
/**
* YamlFileLoader loads translations from Yaml files.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class YamlFileLoader extends ArrayLoader implements LoaderInterface
{
/**
* {@inheritdoc}
*
* @api
*/
public function load($resource, $locale, $domain = 'messages')
{
$messages = Yaml::parse($resource);
// empty file
if (null === $messages) {
$messages = array();
}
// not an array
if (!is_array($messages)) {
throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $resource));
}
$catalogue = parent::load($messages, $locale, $domain);
$catalogue->addResource(new FileResource($resource));
return $catalogue;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* MessageCatalogue.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class MessageCatalogue implements MessageCatalogueInterface
{
private $messages = array();
private $locale;
private $resources;
private $fallbackCatalogue;
private $parent;
/**
* Constructor.
*
* @param string $locale The locale
* @param array $messages An array of messages classified by domain
*
* @api
*/
public function __construct($locale, array $messages = array())
{
$this->locale = $locale;
$this->messages = $messages;
$this->resources = array();
}
/**
* {@inheritdoc}
*
* @api
*/
public function getLocale()
{
return $this->locale;
}
/**
* {@inheritdoc}
*
* @api
*/
public function getDomains()
{
return array_keys($this->messages);
}
/**
* {@inheritdoc}
*
* @api
*/
public function all($domain = null)
{
if (null === $domain) {
return $this->messages;
}
return isset($this->messages[$domain]) ? $this->messages[$domain] : array();
}
/**
* {@inheritdoc}
*
* @api
*/
public function set($id, $translation, $domain = 'messages')
{
$this->add(array($id => $translation), $domain);
}
/**
* {@inheritdoc}
*
* @api
*/
public function has($id, $domain = 'messages')
{
if (isset($this->messages[$domain][$id])) {
return true;
}
if (null !== $this->fallbackCatalogue) {
return $this->fallbackCatalogue->has($id, $domain);
}
return false;
}
/**
* {@inheritdoc}
*/
public function defines($id, $domain = 'messages')
{
return isset($this->messages[$domain][$id]);
}
/**
* {@inheritdoc}
*
* @api
*/
public function get($id, $domain = 'messages')
{
if (isset($this->messages[$domain][$id])) {
return $this->messages[$domain][$id];
}
if (null !== $this->fallbackCatalogue) {
return $this->fallbackCatalogue->get($id, $domain);
}
return $id;
}
/**
* {@inheritdoc}
*
* @api
*/
public function replace($messages, $domain = 'messages')
{
$this->messages[$domain] = array();
$this->add($messages, $domain);
}
/**
* {@inheritdoc}
*
* @api
*/
public function add($messages, $domain = 'messages')
{
if (!isset($this->messages[$domain])) {
$this->messages[$domain] = $messages;
} else {
$this->messages[$domain] = array_replace($this->messages[$domain], $messages);
}
}
/**
* {@inheritdoc}
*
* @api
*/
public function addCatalogue(MessageCatalogueInterface $catalogue)
{
if ($catalogue->getLocale() !== $this->locale) {
throw new \LogicException(sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s"', $catalogue->getLocale(), $this->locale));
}
foreach ($catalogue->all() as $domain => $messages) {
$this->add($messages, $domain);
}
foreach ($catalogue->getResources() as $resource) {
$this->addResource($resource);
}
}
/**
* {@inheritdoc}
*
* @api
*/
public function addFallbackCatalogue(MessageCatalogueInterface $catalogue)
{
// detect circular references
$c = $this;
do {
if ($c->getLocale() === $catalogue->getLocale()) {
throw new \LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
}
} while ($c = $c->parent);
$catalogue->parent = $this;
$this->fallbackCatalogue = $catalogue;
foreach ($catalogue->getResources() as $resource) {
$this->addResource($resource);
}
}
/**
* {@inheritdoc}
*
* @api
*/
public function getResources()
{
return array_values(array_unique($this->resources));
}
/**
* {@inheritdoc}
*
* @api
*/
public function addResource(ResourceInterface $resource)
{
$this->resources[] = $resource;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* MessageCatalogueInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface MessageCatalogueInterface
{
/**
* Gets the catalogue locale.
*
* @return string The locale
*
* @api
*/
function getLocale();
/**
* Gets the domains.
*
* @return array An array of domains
*
* @api
*/
function getDomains();
/**
* Gets the messages within a given domain.
*
* If $domain is null, it returns all messages.
*
* @param string $domain The domain name
*
* @return array An array of messages
*
* @api
*/
function all($domain = null);
/**
* Sets a message translation.
*
* @param string $id The message id
* @param string $translation The messages translation
* @param string $domain The domain name
*
* @api
*/
function set($id, $translation, $domain = 'messages');
/**
* Checks if a message has a translation.
*
* @param string $id The message id
* @param string $domain The domain name
*
* @return Boolean true if the message has a translation, false otherwise
*
* @api
*/
function has($id, $domain = 'messages');
/**
* Checks if a message has a translation (it does not take into account the fallback mechanism).
*
* @param string $id The message id
* @param string $domain The domain name
*
* @return Boolean true if the message has a translation, false otherwise
*
* @api
*/
function defines($id, $domain = 'messages');
/**
* Gets a message translation.
*
* @param string $id The message id
* @param string $domain The domain name
*
* @return string The message translation
*
* @api
*/
function get($id, $domain = 'messages');
/**
* Sets translations for a given domain.
*
* @param string $messages An array of translations
* @param string $domain The domain name
*
* @api
*/
function replace($messages, $domain = 'messages');
/**
* Adds translations for a given domain.
*
* @param string $messages An array of translations
* @param string $domain The domain name
*
* @api
*/
function add($messages, $domain = 'messages');
/**
* Merges translations from the given Catalogue into the current one.
*
* The two catalogues must have the same locale.
*
* @param MessageCatalogueInterface $catalogue A MessageCatalogueInterface instance
*
* @api
*/
function addCatalogue(MessageCatalogueInterface $catalogue);
/**
* Merges translations from the given Catalogue into the current one
* only when the translation does not exist.
*
* This is used to provide default translations when they do not exist for the current locale.
*
* @param MessageCatalogueInterface $catalogue A MessageCatalogueInterface instance
*
* @api
*/
function addFallbackCatalogue(MessageCatalogueInterface $catalogue);
/**
* Returns an array of resources loaded to build this collection.
*
* @return ResourceInterface[] An array of resources
*
* @api
*/
function getResources();
/**
* Adds a resource for this collection.
*
* @param ResourceInterface $resource A resource instance
*
* @api
*/
function addResource(ResourceInterface $resource);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
/**
* MessageSelector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class MessageSelector
{
/**
* Given a message with different plural translations separated by a
* pipe (|), this method returns the correct portion of the message based
* on the given number, locale and the pluralization rules in the message
* itself.
*
* The message supports two different types of pluralization rules:
*
* interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples
* indexed: There is one apple|There is %count% apples
*
* The indexed solution can also contain labels (e.g. one: There is one apple).
* This is purely for making the translations more clear - it does not
* affect the functionality.
*
* The two methods can also be mixed:
* {0} There are no apples|one: There is one apple|more: There are %count% apples
*
* @param string $message The message being translated
* @param integer $number The number of items represented for the message
* @param string $locale The locale to use for choosing
*
* @return string
*
* @throws InvalidArgumentException
*
* @api
*/
public function choose($message, $number, $locale)
{
$parts = explode('|', $message);
$explicitRules = array();
$standardRules = array();
foreach ($parts as $part) {
$part = trim($part);
if (preg_match('/^(?P<interval>'.Interval::getIntervalRegexp().')\s*(?P<message>.*?)$/x', $part, $matches)) {
$explicitRules[$matches['interval']] = $matches['message'];
} elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
$standardRules[] = $matches[1];
} else {
$standardRules[] = $part;
}
}
// try to match an explicit rule, then fallback to the standard ones
foreach ($explicitRules as $interval => $m) {
if (Interval::test($number, $interval)) {
return $m;
}
}
$position = PluralizationRules::get($number, $locale);
if (!isset($standardRules[$position])) {
throw new \InvalidArgumentException('Unable to choose a translation.');
}
return $standardRules[$position];
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
/**
* Returns the plural rules for a given locale.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class PluralizationRules
{
// @codeCoverageIgnoreStart
static private $rules = array();
/**
* Returns the plural position to use for the given locale and number.
*
* @param integer $number The number
* @param string $locale The locale
*
* @return integer The plural position
*/
static public function get($number, $locale)
{
if ("pt_BR" == $locale) {
// temporary set a locale for brazilian
$locale = "xbr";
}
if (strlen($locale) > 3) {
$locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
}
if (isset(self::$rules[$locale])) {
$return = call_user_func(self::$rules[$locale], $number);
if (!is_int($return) || $return < 0) {
return 0;
}
return $return;
}
/*
* The plural rules are derived from code of the Zend Framework (2010-09-25),
* which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
* Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
*/
switch ($locale) {
case 'bo':
case 'dz':
case 'id':
case 'ja':
case 'jv':
case 'ka':
case 'km':
case 'kn':
case 'ko':
case 'ms':
case 'th':
case 'tr':
case 'vi':
case 'zh':
return 0;
break;
case 'af':
case 'az':
case 'bn':
case 'bg':
case 'ca':
case 'da':
case 'de':
case 'el':
case 'en':
case 'eo':
case 'es':
case 'et':
case 'eu':
case 'fa':
case 'fi':
case 'fo':
case 'fur':
case 'fy':
case 'gl':
case 'gu':
case 'ha':
case 'he':
case 'hu':
case 'is':
case 'it':
case 'ku':
case 'lb':
case 'ml':
case 'mn':
case 'mr':
case 'nah':
case 'nb':
case 'ne':
case 'nl':
case 'nn':
case 'no':
case 'om':
case 'or':
case 'pa':
case 'pap':
case 'ps':
case 'pt':
case 'so':
case 'sq':
case 'sv':
case 'sw':
case 'ta':
case 'te':
case 'tk':
case 'ur':
case 'zu':
return ($number == 1) ? 0 : 1;
case 'am':
case 'bh':
case 'fil':
case 'fr':
case 'gun':
case 'hi':
case 'ln':
case 'mg':
case 'nso':
case 'xbr':
case 'ti':
case 'wa':
return (($number == 0) || ($number == 1)) ? 0 : 1;
case 'be':
case 'bs':
case 'hr':
case 'ru':
case 'sr':
case 'uk':
return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
case 'cs':
case 'sk':
return ($number == 1) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2);
case 'ga':
return ($number == 1) ? 0 : (($number == 2) ? 1 : 2);
case 'lt':
return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
case 'sl':
return ($number % 100 == 1) ? 0 : (($number % 100 == 2) ? 1 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 2 : 3));
case 'mk':
return ($number % 10 == 1) ? 0 : 1;
case 'mt':
return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3));
case 'lv':
return ($number == 0) ? 0 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2);
case 'pl':
return ($number == 1) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2);
case 'cy':
return ($number == 1) ? 0 : (($number == 2) ? 1 : ((($number == 8) || ($number == 11)) ? 2 : 3));
case 'ro':
return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2);
case 'ar':
return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number >= 3) && ($number <= 10)) ? 3 : ((($number >= 11) && ($number <= 99)) ? 4 : 5))));
default:
return 0;
}
}
/**
* Overrides the default plural rule for a given locale.
*
* @param string $rule A PHP callable
* @param string $locale The locale
*
* @return null
*/
static public function set($rule, $locale)
{
if ("pt_BR" == $locale) {
// temporary set a locale for brazilian
$locale = "xbr";
}
if (strlen($locale) > 3) {
$locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
}
if (!is_callable($rule)) {
throw new \LogicException('The given rule can not be called');
}
self::$rules[$locale] = $rule;
}
// @codeCoverageIgnoreEnd
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
use Symfony\Component\Translation\Loader\LoaderInterface;
/**
* Translator.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Translator implements TranslatorInterface
{
protected $catalogues;
protected $locale;
private $fallbackLocale;
private $loaders;
private $resources;
private $selector;
/**
* Constructor.
*
* @param string $locale The locale
* @param MessageSelector $selector The message selector for pluralization
*
* @api
*/
public function __construct($locale, MessageSelector $selector)
{
$this->locale = $locale;
$this->selector = $selector;
$this->loaders = array();
$this->resources = array();
$this->catalogues = array();
}
/**
* Adds a Loader.
*
* @param string $format The name of the loader (@see addResource())
* @param LoaderInterface $loader A LoaderInterface instance
*
* @api
*/
public function addLoader($format, LoaderInterface $loader)
{
$this->loaders[$format] = $loader;
}
/**
* Adds a Resource.
*
* @param string $format The name of the loader (@see addLoader())
* @param mixed $resource The resource name
* @param string $locale The locale
* @param string $domain The domain
*
* @api
*/
public function addResource($format, $resource, $locale, $domain = 'messages')
{
$this->resources[$locale][] = array($format, $resource, $domain);
}
/**
* {@inheritdoc}
*
* @api
*/
public function setLocale($locale)
{
$this->locale = $locale;
}
/**
* {@inheritdoc}
*
* @api
*/
public function getLocale()
{
return $this->locale;
}
/**
* Sets the fallback locale.
*
* @param string $locale The fallback locale
*
* @api
*/
public function setFallbackLocale($locale)
{
// needed as the fallback locale is used to fill-in non-yet translated messages
$this->catalogues = array();
$this->fallbackLocale = $locale;
}
/**
* {@inheritdoc}
*
* @api
*/
public function trans($id, array $parameters = array(), $domain = 'messages', $locale = null)
{
if (!isset($locale)) {
$locale = $this->getLocale();
}
if (!isset($this->catalogues[$locale])) {
$this->loadCatalogue($locale);
}
return strtr($this->catalogues[$locale]->get((string) $id, $domain), $parameters);
}
/**
* {@inheritdoc}
*
* @api
*/
public function transChoice($id, $number, array $parameters = array(), $domain = 'messages', $locale = null)
{
if (!isset($locale)) {
$locale = $this->getLocale();
}
if (!isset($this->catalogues[$locale])) {
$this->loadCatalogue($locale);
}
if (!$this->catalogues[$locale]->defines((string) $id, $domain)) {
// we will use the fallback
$locale = $this->computeFallbackLocale($locale);
if (!isset($this->catalogues[$locale])) {
$this->loadCatalogue($locale);
}
}
return strtr($this->selector->choose($this->catalogues[$locale]->get((string) $id, $domain), (int) $number, $locale), $parameters);
}
protected function loadCatalogue($locale)
{
$this->catalogues[$locale] = new MessageCatalogue($locale);
if (isset($this->resources[$locale])) {
foreach ($this->resources[$locale] as $resource) {
if (!isset($this->loaders[$resource[0]])) {
throw new \RuntimeException(sprintf('The "%s" translation loader is not registered.', $resource[0]));
}
$this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));
}
}
$this->addFallbackCatalogue($locale);
}
protected function computeFallbackLocale($locale)
{
if (strrchr($locale, '_') !== false) {
return substr($locale, 0, -strlen(strrchr($locale, '_')));
} else {
return $this->fallbackLocale;
}
}
private function addFallbackCatalogue($locale)
{
if (!$fallback = $this->computeFallbackLocale($locale)) {
return;
}
if (!isset($this->catalogues[$fallback])) {
$this->loadCatalogue($fallback);
}
if ($fallback != $locale) {
$this->catalogues[$locale]->addFallbackCatalogue($this->catalogues[$fallback]);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
/**
* TranslatorInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface TranslatorInterface
{
/**
* Translates the given message.
*
* @param string $id The message id
* @param array $parameters An array of parameters for the message
* @param string $domain The domain for the message
* @param string $locale The locale
*
* @return string The translated string
*
* @api
*/
function trans($id, array $parameters = array(), $domain = null, $locale = null);
/**
* Translates the given choice message by choosing a translation according to a number.
*
* @param string $id The message id
* @param integer $number The number to use to find the indice of the message
* @param array $parameters An array of parameters for the message
* @param string $domain The domain for the message
* @param string $locale The locale
*
* @return string The translated string
*
* @api
*/
function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null);
/**
* Sets the current locale.
*
* @param string $locale The locale
*
* @api
*/
function setLocale($locale);
/**
* Returns the current locale.
*
* @return string The locale
*
* @api
*/
function getLocale();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
/**
* Dumper dumps PHP variables to YAML strings.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Dumper
{
/**
* Dumps a PHP value to YAML.
*
* @param mixed $input The PHP value
* @param integer $inline The level where you switch to inline YAML
* @param integer $indent The level of indentation (used internally)
*
* @return string The YAML representation of the PHP value
*/
public function dump($input, $inline = 0, $indent = 0)
{
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) : '';
if ($inline <= 0 || !is_array($input) || empty($input)) {
$output .= $prefix.Inline::dump($input);
} else {
$isAHash = array_keys($input) !== range(0, count($input) - 1);
foreach ($input as $key => $value) {
$willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
$output .= sprintf('%s%s%s%s',
$prefix,
$isAHash ? Inline::dump($key).':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2)
).($willBeInlined ? "\n" : '');
}
}
return $output;
}
}
<?php
/*
* This file is part of the Symfony package.
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
/**
* Escaper encapsulates escaping rules for single and double-quoted
* YAML strings.
*
* @author Matthew Lewinski <matthew@lewinski.org>
*/
class Escaper
{
// Characters that would cause a dumped string to require double quoting.
const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";
// Mapping arrays for escaping a double quoted string. The backslash is
// first to ensure proper escaping because str_replace operates iteratively
// on the input arrays. This ordering of the characters avoids the use of strtr,
// which performs more slowly.
static private $escapees = array('\\\\', '\\"',
"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
"\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
"\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
"\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
"\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9");
static private $escaped = array('\\"', '\\\\',
"\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a",
"\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f",
"\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17",
"\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", "\\x1f",
"\\N", "\\_", "\\L", "\\P");
/**
* Determines if a PHP value would require double quoting in YAML.
*
* @param string $value A PHP value
*
* @return Boolean True if the value would require double quotes.
*/
static public function requiresDoubleQuoting($value)
{
return preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value);
}
/**
* Escapes and surrounds a PHP value with double quotes.
*
* @param string $value A PHP value
*
* @return string The quoted, escaped string
*/
static public function escapeWithDoubleQuotes($value)
{
return sprintf('"%s"', str_replace(self::$escapees, self::$escaped, $value));
}
/**
* Determines if a PHP value would require single quoting in YAML.
*
* @param string $value A PHP value
*
* @return Boolean True if the value would require single quotes.
*/
static public function requiresSingleQuoting($value)
{
return preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value);
}
/**
* Escapes and surrounds a PHP value with single quotes.
*
* @param string $value A PHP value
*
* @return string The quoted, escaped string
*/
static public function escapeWithSingleQuotes($value)
{
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml\Exception;
/**
* Exception class thrown when an error occurs during dumping.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class DumpException extends \RuntimeException implements ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml\Exception;
/**
* Exception interface for all exceptions thrown by the component.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml\Exception;
/**
* Exception class thrown when an error occurs during parsing.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ParseException extends \RuntimeException implements ExceptionInterface
{
private $parsedFile;
private $parsedLine;
private $snippet;
private $rawMessage;
/**
* Constructor.
*
* @param string $message The error message
* @param integer $parsedLine The line where the error occurred
* @param integer $snippet The snippet of code near the problem
* @param string $parsedFile The file name where the error occurred
* @param Exception $previous The previous exception
*/
public function __construct($message, $parsedLine = -1, $snippet = null, $parsedFile = null, Exception $previous = null)
{
$this->parsedFile = $parsedFile;
$this->parsedLine = $parsedLine;
$this->snippet = $snippet;
$this->rawMessage = $message;
$this->updateRepr();
parent::__construct($this->message, 0, $previous);
}
/**
* Gets the snippet of code near the error.
*
* @return string The snippet of code
*/
public function getSnippet()
{
return $this->snippet;
}
/**
* Sets the snippet of code near the error.
*
* @param string $snippet The code snippet
*/
public function setSnippet($snippet)
{
$this->snippet = $snippet;
$this->updateRepr();
}
/**
* Gets the filename where the error occurred.
*
* This method returns null if a string is parsed.
*
* @return string The filename
*/
public function getParsedFile()
{
return $this->parsedFile;
}
/**
* Sets the filename where the error occurred.
*
* @param string $parsedFile The filename
*/
public function setParsedFile($parsedFile)
{
$this->parsedFile = $parsedFile;
$this->updateRepr();
}
/**
* Gets the line where the error occurred.
*
* @return integer The file line
*/
public function getParsedLine()
{
return $this->parsedLine;
}
/**
* Sets the line where the error occurred.
*
* @param integer $parsedLine The file line
*/
public function setParsedLine($parsedLine)
{
$this->parsedLine = $parsedLine;
$this->updateRepr();
}
private function updateRepr()
{
$this->message = $this->rawMessage;
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
if (null !== $this->parsedFile) {
$this->message .= sprintf(' in %s', json_encode($this->parsedFile));
}
if ($this->parsedLine >= 0) {
$this->message .= sprintf(' at line %d', $this->parsedLine);
}
if ($this->snippet) {
$this->message .= sprintf(' (near "%s")', $this->snippet);
}
if ($dot) {
$this->message .= '.';
}
}
}
<?php
/*
* This file is part of the Symfony package.
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Exception\DumpException;
/**
* Inline implements a YAML parser/dumper for the YAML inline syntax.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Inline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
/**
* Converts a YAML string to a PHP array.
*
* @param string $value A YAML string
*
* @return array A PHP array representing the YAML string
*/
static public function parse($value)
{
$value = trim($value);
if (0 == strlen($value)) {
return '';
}
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
switch ($value[0]) {
case '[':
$result = self::parseSequence($value);
break;
case '{':
$result = self::parseMapping($value);
break;
default:
$result = self::parseScalar($value);
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return $result;
}
/**
* Dumps a given PHP variable to a YAML string.
*
* @param mixed $value The PHP variable to convert
*
* @return string The YAML string representing the PHP array
*
* @throws DumpException When trying to dump PHP resource
*/
static public function dump($value)
{
switch (true) {
case is_resource($value):
throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
case is_object($value):
return '!!php/object:'.serialize($value);
case is_array($value):
return self::dumpArray($value);
case null === $value:
return 'null';
case true === $value:
return 'true';
case false === $value:
return 'false';
case ctype_digit($value):
return is_string($value) ? "'$value'" : (int) $value;
case is_numeric($value):
$locale = setlocale(LC_NUMERIC, 0);
if (false !== $locale) {
setlocale(LC_NUMERIC, 'C');
}
$repr = is_string($value) ? "'$value'" : (is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : strval($value));
if (false !== $locale) {
setlocale(LC_NUMERIC, $locale);
}
return $repr;
case Escaper::requiresDoubleQuoting($value):
return Escaper::escapeWithDoubleQuotes($value);
case Escaper::requiresSingleQuoting($value):
return Escaper::escapeWithSingleQuotes($value);
case '' == $value:
return "''";
case preg_match(self::getTimestampRegex(), $value):
case in_array(strtolower($value), array('null', '~', 'true', 'false')):
return "'$value'";
default:
return $value;
}
}
/**
* Dumps a PHP array to a YAML string.
*
* @param array $value The PHP array to dump
*
* @return string The YAML string representing the PHP array
*/
static private function dumpArray($value)
{
// array
$keys = array_keys($value);
if ((1 == count($keys) && '0' == $keys[0])
|| (count($keys) > 1 && array_reduce($keys, function ($v, $w) { return (integer) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2)
) {
$output = array();
foreach ($value as $val) {
$output[] = self::dump($val);
}
return sprintf('[%s]', implode(', ', $output));
}
// mapping
$output = array();
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
}
return sprintf('{ %s }', implode(', ', $output));
}
/**
* Parses a scalar to a YAML string.
*
* @param scalar $scalar
* @param string $delimiters
* @param array $stringDelimiters
* @param integer &$i
* @param Boolean $evaluate
*
* @return string A YAML string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
{
if (in_array($scalar[$i], $stringDelimiters)) {
// quoted scalar
$output = self::parseQuotedScalar($scalar, $i);
} else {
// "normal" string
if (!$delimiters) {
$output = substr($scalar, $i);
$i += strlen($output);
// remove comments
if (false !== $strpos = strpos($output, ' #')) {
$output = rtrim(substr($output, 0, $strpos));
}
} elseif (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
$output = $match[1];
$i += strlen($output);
} else {
throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
}
$output = $evaluate ? self::evaluateScalar($output) : $output;
}
return $output;
}
/**
* Parses a quoted scalar to YAML.
*
* @param string $scalar
* @param integer &$i
*
* @return string A YAML string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
static private function parseQuotedScalar($scalar, &$i)
{
if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
}
$output = substr($match[0], 1, strlen($match[0]) - 2);
$unescaper = new Unescaper();
if ('"' == $scalar[$i]) {
$output = $unescaper->unescapeDoubleQuotedString($output);
} else {
$output = $unescaper->unescapeSingleQuotedString($output);
}
$i += strlen($match[0]);
return $output;
}
/**
* Parses a sequence to a YAML string.
*
* @param string $sequence
* @param integer &$i
*
* @return string A YAML string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
static private function parseSequence($sequence, &$i = 0)
{
$output = array();
$len = strlen($sequence);
$i += 1;
// [foo, bar, ...]
while ($i < $len) {
switch ($sequence[$i]) {
case '[':
// nested sequence
$output[] = self::parseSequence($sequence, $i);
break;
case '{':
// nested mapping
$output[] = self::parseMapping($sequence, $i);
break;
case ']':
return $output;
case ',':
case ' ':
break;
default:
$isQuoted = in_array($sequence[$i], array('"', "'"));
$value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
if (!$isQuoted && false !== strpos($value, ': ')) {
// embedded mapping?
try {
$value = self::parseMapping('{'.$value.'}');
} catch (\InvalidArgumentException $e) {
// no, it's not
}
}
$output[] = $value;
--$i;
}
++$i;
}
throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
}
/**
* Parses a mapping to a YAML string.
*
* @param string $mapping
* @param integer &$i
*
* @return string A YAML string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
static private function parseMapping($mapping, &$i = 0)
{
$output = array();
$len = strlen($mapping);
$i += 1;
// {foo: bar, bar:foo, ...}
while ($i < $len) {
switch ($mapping[$i]) {
case ' ':
case ',':
++$i;
continue 2;
case '}':
return $output;
}
// key
$key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
// value
$done = false;
while ($i < $len) {
switch ($mapping[$i]) {
case '[':
// nested sequence
$output[$key] = self::parseSequence($mapping, $i);
$done = true;
break;
case '{':
// nested mapping
$output[$key] = self::parseMapping($mapping, $i);
$done = true;
break;
case ':':
case ' ':
break;
default:
$output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
$done = true;
--$i;
}
++$i;
if ($done) {
continue 2;
}
}
}
throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping));
}
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
*
* @return string A YAML string
*/
static private function evaluateScalar($scalar)
{
$scalar = trim($scalar);
switch (true) {
case 'null' == strtolower($scalar):
case '' == $scalar:
case '~' == $scalar:
return null;
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return intval(self::parseScalar(substr($scalar, 2)));
case 0 === strpos($scalar, '!!php/object:'):
return unserialize(substr($scalar, 13));
case ctype_digit($scalar):
$raw = $scalar;
$cast = intval($scalar);
return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case 'true' === strtolower($scalar):
return true;
case 'false' === strtolower($scalar):
return false;
case is_numeric($scalar):
return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
case 0 == strcasecmp($scalar, '.inf'):
case 0 == strcasecmp($scalar, '.NaN'):
return -log(0);
case 0 == strcasecmp($scalar, '-.inf'):
return log(0);
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return floatval(str_replace(',', '', $scalar));
case preg_match(self::getTimestampRegex(), $scalar):
return strtotime($scalar);
default:
return (string) $scalar;
}
}
/**
* Gets a regex that matches an unix timestamp
*
* @return string The regular expression
*/
static private function getTimestampRegex()
{
return <<<EOF
~^
(?P<year>[0-9][0-9][0-9][0-9])
-(?P<month>[0-9][0-9]?)
-(?P<day>[0-9][0-9]?)
(?:(?:[Tt]|[ \t]+)
(?P<hour>[0-9][0-9]?)
:(?P<minute>[0-9][0-9])
:(?P<second>[0-9][0-9])
(?:\.(?P<fraction>[0-9]*))?
(?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
(?::(?P<tz_minute>[0-9][0-9]))?))?)?
$~x
EOF;
}
}
Copyright (c) 2004-2012 Fabien Potencier
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.
<?php
/*
* This file is part of the Symfony package.
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;
/**
* Parser parses YAML strings to convert them to PHP arrays.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Parser
{
private $offset = 0;
private $lines = array();
private $currentLineNb = -1;
private $currentLine = '';
private $refs = array();
/**
* Constructor
*
* @param integer $offset The offset of YAML document (used for line numbers in error messages)
*/
public function __construct($offset = 0)
{
$this->offset = $offset;
}
/**
* Parses a YAML string to a PHP value.
*
* @param string $value A YAML string
*
* @return mixed A PHP value
*
* @throws ParseException If the YAML is not valid
*/
public function parse($value)
{
$this->currentLineNb = -1;
$this->currentLine = '';
$this->lines = explode("\n", $this->cleanup($value));
if (function_exists('mb_detect_encoding') && false === mb_detect_encoding($value, 'UTF-8', true)) {
throw new ParseException('The YAML value does not appear to be valid UTF-8.');
}
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
}
$data = array();
while ($this->moveToNextLine()) {
if ($this->isCurrentLineEmpty()) {
continue;
}
// tab?
if ("\t" === $this->currentLine[0]) {
throw new ParseException('A YAML file cannot contain tabs as indentation.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
$isRef = $isInPlace = $isProcessed = false;
if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}
// array
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new Parser($c);
$parser->refs =& $this->refs;
$data[] = $parser->parse($this->getNextEmbedBlock());
} else {
if (isset($values['leadspaces'])
&& ' ' == $values['leadspaces']
&& preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches)
) {
// this is a compact notation element, add to next block and parse
$c = $this->getRealCurrentLineNb();
$parser = new Parser($c);
$parser->refs =& $this->refs;
$block = $values['value'];
if (!$this->isNextLineIndented()) {
$block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2);
}
$data[] = $parser->parse($block);
} else {
$data[] = $this->parseValue($values['value']);
}
}
} elseif (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
try {
$key = Inline::parseScalar($values['key']);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
if ('<<' === $key) {
if (isset($values['value']) && 0 === strpos($values['value'], '*')) {
$isInPlace = substr($values['value'], 1);
if (!array_key_exists($isInPlace, $this->refs)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $isInPlace), $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
} else {
if (isset($values['value']) && $values['value'] !== '') {
$value = $values['value'];
} else {
$value = $this->getNextEmbedBlock();
}
$c = $this->getRealCurrentLineNb() + 1;
$parser = new Parser($c);
$parser->refs =& $this->refs;
$parsed = $parser->parse($value);
$merged = array();
if (!is_array($parsed)) {
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
} elseif (isset($parsed[0])) {
// Numeric array, merge individual elements
foreach (array_reverse($parsed) as $parsedItem) {
if (!is_array($parsedItem)) {
throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem);
}
$merged = array_merge($parsedItem, $merged);
}
} else {
// Associative array, merge
$merged = array_merge($merged, $parsed);
}
$isProcessed = $merged;
}
} elseif (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}
if ($isProcessed) {
// Merge keys
$data = $isProcessed;
// hash
} elseif (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
// if next line is less indented or equal, then it means that the current value is null
if ($this->isNextLineIndented()) {
$data[$key] = null;
} else {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new Parser($c);
$parser->refs =& $this->refs;
$data[$key] = $parser->parse($this->getNextEmbedBlock());
}
} else {
if ($isInPlace) {
$data = $this->refs[$isInPlace];
} else {
$data[$key] = $this->parseValue($values['value']);
}
}
} else {
// 1-liner followed by newline
if (2 == count($this->lines) && empty($this->lines[1])) {
try {
$value = Inline::parse($this->lines[0]);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
if (is_array($value)) {
$first = reset($value);
if (is_string($first) && 0 === strpos($first, '*')) {
$data = array();
foreach ($value as $alias) {
$data[] = $this->refs[substr($alias, 1)];
}
$value = $data;
}
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return $value;
}
switch (preg_last_error()) {
case PREG_INTERNAL_ERROR:
$error = 'Internal PCRE error.';
break;
case PREG_BACKTRACK_LIMIT_ERROR:
$error = 'pcre.backtrack_limit reached.';
break;
case PREG_RECURSION_LIMIT_ERROR:
$error = 'pcre.recursion_limit reached.';
break;
case PREG_BAD_UTF8_ERROR:
$error = 'Malformed UTF-8 data.';
break;
case PREG_BAD_UTF8_OFFSET_ERROR:
$error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point.';
break;
default:
$error = 'Unable to parse.';
}
throw new ParseException($error, $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
if ($isRef) {
$this->refs[$isRef] = end($data);
}
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return empty($data) ? null : $data;
}
/**
* Returns the current line number (takes the offset into account).
*
* @return integer The current line number
*/
private function getRealCurrentLineNb()
{
return $this->currentLineNb + $this->offset;
}
/**
* Returns the current line indentation.
*
* @return integer The current line indentation
*/
private function getCurrentLineIndentation()
{
return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
}
/**
* Returns the next embed block of YAML.
*
* @param integer $indentation The indent level at which the block is to be read, or null for default
*
* @return string A YAML string
*
* @throws ParseException When indentation problem are detected
*/
private function getNextEmbedBlock($indentation = null)
{
$this->moveToNextLine();
if (null === $indentation) {
$newIndent = $this->getCurrentLineIndentation();
if (!$this->isCurrentLineEmpty() && 0 == $newIndent) {
throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
} else {
$newIndent = $indentation;
}
$data = array(substr($this->currentLine, $newIndent));
while ($this->moveToNextLine()) {
if ($this->isCurrentLineEmpty()) {
if ($this->isCurrentLineBlank()) {
$data[] = substr($this->currentLine, $newIndent);
}
continue;
}
$indent = $this->getCurrentLineIndentation();
if (preg_match('#^(?P<text> *)$#', $this->currentLine, $match)) {
// empty line
$data[] = $match['text'];
} elseif ($indent >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} elseif (0 == $indent) {
$this->moveToPreviousLine();
break;
} else {
throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}
return implode("\n", $data);
}
/**
* Moves the parser to the next line.
*
* @return Boolean
*/
private function moveToNextLine()
{
if ($this->currentLineNb >= count($this->lines) - 1) {
return false;
}
$this->currentLine = $this->lines[++$this->currentLineNb];
return true;
}
/**
* Moves the parser to the previous line.
*/
private function moveToPreviousLine()
{
$this->currentLine = $this->lines[--$this->currentLineNb];
}
/**
* Parses a YAML value.
*
* @param string $value A YAML value
*
* @return mixed A PHP value
*
* @throws ParseException When reference does not exist
*/
private function parseValue($value)
{
if (0 === strpos($value, '*')) {
if (false !== $pos = strpos($value, '#')) {
$value = substr($value, 1, $pos - 2);
} else {
$value = substr($value, 1);
}
if (!array_key_exists($value, $this->refs)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLine);
}
return $this->refs[$value];
}
if (preg_match('/^(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?$/', $value, $matches)) {
$modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
}
try {
return Inline::parse($value);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
}
/**
* Parses a folded scalar.
*
* @param string $separator The separator that was used to begin this folded scalar (| or >)
* @param string $indicator The indicator that was used to begin this folded scalar (+ or -)
* @param integer $indentation The indentation that was used to begin this folded scalar
*
* @return string The text value
*/
private function parseFoldedScalar($separator, $indicator = '', $indentation = 0)
{
$separator = '|' == $separator ? "\n" : ' ';
$text = '';
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineBlank()) {
$text .= "\n";
$notEOF = $this->moveToNextLine();
}
if (!$notEOF) {
return '';
}
if (!preg_match('#^(?P<indent>'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P<text>.*)$#u', $this->currentLine, $matches)) {
$this->moveToPreviousLine();
return '';
}
$textIndent = $matches['indent'];
$previousIndent = 0;
$text .= $matches['text'].$separator;
while ($this->currentLineNb + 1 < count($this->lines)) {
$this->moveToNextLine();
if (preg_match('#^(?P<indent> {'.strlen($textIndent).',})(?P<text>.+)$#u', $this->currentLine, $matches)) {
if (' ' == $separator && $previousIndent != $matches['indent']) {
$text = substr($text, 0, -1)."\n";
}
$previousIndent = $matches['indent'];
$text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator);
} elseif (preg_match('#^(?P<text> *)$#', $this->currentLine, $matches)) {
$text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n";
} else {
$this->moveToPreviousLine();
break;
}
}
if (' ' == $separator) {
// replace last separator by a newline
$text = preg_replace('/ (\n*)$/', "\n$1", $text);
}
switch ($indicator) {
case '':
$text = preg_replace('#\n+$#s', "\n", $text);
break;
case '+':
break;
case '-':
$text = preg_replace('#\n+$#s', '', $text);
break;
}
return $text;
}
/**
* Returns true if the next line is indented.
*
* @return Boolean Returns true if the next line is indented, false otherwise
*/
private function isNextLineIndented()
{
$currentIndentation = $this->getCurrentLineIndentation();
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineEmpty()) {
$notEOF = $this->moveToNextLine();
}
if (false === $notEOF) {
return false;
}
$ret = false;
if ($this->getCurrentLineIndentation() <= $currentIndentation) {
$ret = true;
}
$this->moveToPreviousLine();
return $ret;
}
/**
* Returns true if the current line is blank or if it is a comment line.
*
* @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
*/
private function isCurrentLineEmpty()
{
return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
}
/**
* Returns true if the current line is blank.
*
* @return Boolean Returns true if the current line is blank, false otherwise
*/
private function isCurrentLineBlank()
{
return '' == trim($this->currentLine, ' ');
}
/**
* Returns true if the current line is a comment line.
*
* @return Boolean Returns true if the current line is a comment line, false otherwise
*/
private function isCurrentLineComment()
{
//checking explicitly the first char of the trim is faster than loops or strpos
$ltrimmedLine = ltrim($this->currentLine, ' ');
return $ltrimmedLine[0] === '#';
}
/**
* Cleanups a YAML string to be parsed.
*
* @param string $value The input YAML string
*
* @return string A cleaned up YAML string
*/
private function cleanup($value)
{
$value = str_replace(array("\r\n", "\r"), "\n", $value);
if (!preg_match("#\n$#", $value)) {
$value .= "\n";
}
// strip YAML header
$count = 0;
$value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#su', '', $value, -1, $count);
$this->offset += $count;
// remove leading comments
$trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
if ($count == 1) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}
// remove start of the document marker (---)
$trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
if ($count == 1) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
// remove end of the document marker (...)
$value = preg_replace('#\.\.\.\s*$#s', '', $value);
}
return $value;
}
}
<?php
/*
* This file is part of the Symfony package.
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
/**
* Unescaper encapsulates unescaping rules for single and double-quoted
* YAML strings.
*
* @author Matthew Lewinski <matthew@lewinski.org>
*/
class Unescaper
{
// Parser and Inline assume UTF-8 encoding, so escaped Unicode characters
// must be converted to that encoding.
const ENCODING = 'UTF-8';
// Regex fragment that matches an escaped character in a double quoted
// string.
const REGEX_ESCAPED_CHARACTER = "\\\\([0abt\tnvfre \\\"\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})";
/**
* Unescapes a single quoted string.
*
* @param string $value A single quoted string.
*
* @return string The unescaped string.
*/
public function unescapeSingleQuotedString($value)
{
return str_replace('\'\'', '\'', $value);
}
/**
* Unescapes a double quoted string.
*
* @param string $value A double quoted string.
*
* @return string The unescaped string.
*/
public function unescapeDoubleQuotedString($value)
{
$self = $this;
$callback = function($match) use($self) {
return $self->unescapeCharacter($match[0]);
};
// evaluate the string
return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value);
}
/**
* Unescapes a character that was found in a double-quoted string
*
* @param string $value An escaped character
*
* @return string The unescaped character
*/
public function unescapeCharacter($value)
{
switch ($value{1}) {
case '0':
return "\x0";
case 'a':
return "\x7";
case 'b':
return "\x8";
case 't':
return "\t";
case "\t":
return "\t";
case 'n':
return "\n";
case 'v':
return "\xb";
case 'f':
return "\xc";
case 'r':
return "\xd";
case 'e':
return "\x1b";
case ' ':
return ' ';
case '"':
return '"';
case '/':
return '/';
case '\\':
return '\\';
case 'N':
// U+0085 NEXT LINE
return $this->convertEncoding("\x00\x85", self::ENCODING, 'UCS-2BE');
case '_':
// U+00A0 NO-BREAK SPACE
return $this->convertEncoding("\x00\xA0", self::ENCODING, 'UCS-2BE');
case 'L':
// U+2028 LINE SEPARATOR
return $this->convertEncoding("\x20\x28", self::ENCODING, 'UCS-2BE');
case 'P':
// U+2029 PARAGRAPH SEPARATOR
return $this->convertEncoding("\x20\x29", self::ENCODING, 'UCS-2BE');
case 'x':
$char = pack('n', hexdec(substr($value, 2, 2)));
return $this->convertEncoding($char, self::ENCODING, 'UCS-2BE');
case 'u':
$char = pack('n', hexdec(substr($value, 2, 4)));
return $this->convertEncoding($char, self::ENCODING, 'UCS-2BE');
case 'U':
$char = pack('N', hexdec(substr($value, 2, 8)));
return $this->convertEncoding($char, self::ENCODING, 'UCS-4BE');
}
}
/**
* Convert a string from one encoding to another.
*
* @param string $value The string to convert
* @param string $to The input encoding
* @param string $from The output encoding
*
* @return string The string with the new encoding
*
* @throws \RuntimeException if no suitable encoding function is found (iconv or mbstring)
*/
private function convertEncoding($value, $to, $from)
{
if (function_exists('iconv')) {
return iconv($from, $to, $value);
} elseif (function_exists('mb_convert_encoding')) {
return mb_convert_encoding($value, $to, $from);
}
throw new \RuntimeException('No suitable convert encoding function (install the iconv or mbstring extension).');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;
/**
* Yaml offers convenience methods to load and dump YAML.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Yaml
{
/**
* Parses YAML into a PHP array.
*
* The parse method, when supplied with a YAML stream (string or file),
* will do its best to convert YAML in a file into a PHP array.
*
* Usage:
* <code>
* $array = Yaml::parse('config.yml');
* print_r($array);
* </code>
*
* @param string $input Path to a YAML file or a string containing YAML
*
* @return array The YAML converted to a PHP array
*
* @throws \InvalidArgumentException If the YAML is not valid
*
* @api
*/
static public function parse($input)
{
$file = '';
// if input is a file, process it
if (strpos($input, "\n") === false && is_file($input)) {
if (false === is_readable($input)) {
throw new ParseException(sprintf('Unable to parse "%s" as the file is not readable.', $input));
}
$file = $input;
ob_start();
$retval = include($input);
$content = ob_get_clean();
// if an array is returned by the config file assume it's in plain php form else in YAML
$input = is_array($retval) ? $retval : $content;
}
// if an array is returned by the config file assume it's in plain php form else in YAML
if (is_array($input)) {
return $input;
}
$yaml = new Parser();
try {
return $yaml->parse($input);
} catch (ParseException $e) {
if ($file) {
$e->setParsedFile($file);
}
throw $e;
}
}
/**
* Dumps a PHP array to a YAML string.
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML.
*
* @param array $array PHP array
* @param integer $inline The level where you switch to inline YAML
*
* @return string A YAML string representing the original PHP array
*
* @api
*/
static public function dump($array, $inline = 2)
{
$yaml = new Dumper();
return $yaml->dump($array, $inline);
}
}
Copyright (c) 2012 Konstantin Kudryashov <ever.zet@gmail.com>
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.<?php return array (
'en' =>
array (
'proposal_title' => 'You can implement step definitions for undefined steps with these snippets:',
'failed_steps_title' => 'failed steps',
'pending_steps_title' => 'pending steps',
'scenarios_count' => '{0} No scenarios|{1} 1 scenario|]1,Inf] %1% scenarios',
'steps_count' => '{0} No steps|{1} 1 step|]1,Inf] %1% steps',
'passed_count' => '[1,Inf] %1% passed',
'failed_count' => '[1,Inf] %1% failed',
'pending_count' => '[1,Inf] %1% pending',
'undefined_count' => '[1,Inf] %1% undefined',
'skipped_count' => '[1,Inf] %1% skipped',
),
'cs' =>
array (
'proposal_title' => 'Můžete implementovat definice kroku pro nedifinované kroky za použitíchto kusů kódu (snippetů):',
'failed_steps_title' => 'zkažené kroky',
'pending_steps_title' => 'Ä<>ekají­ kroky',
'scenarios_count' => '{0} Žádný scénář|{1} 1 scénář|]|{2,3,4} %1% scénáře|4,Inf] %1% scénářů',
'steps_count' => '{0} Žádné kroky|{1} 1 krok|{2,3,4} %1% kroky|]4,Inf] %1% kroků',
'passed_count' => '{1} %1% prošel|{2,3,4} %1% prošli|[4,Inf] %1% prošlo',
'failed_count' => '{1} %1% selhal|{2,3,4} %1% selhali|[4,Inf] %1% selhalo',
'pending_count' => '{1} %1% Ä<>eká|{2,3,4} %1% Ä<>ekají|[4,Inf] %1% Ä<>eká',
'undefined_count' => '{1} %1% nedefinován|{2,3,4} %1% nedefinovány|[4,Inf] %1% nedefinováno',
'skipped_count' => '{1} %1% pÅ™eskoÄ<6F>en| {2,3,4} %1% pÅ™eskoÄ<6F>eny|[5,Inf] %1% pÅ™eskoÄ<6F>eno',
),
'de' =>
array (
'proposal_title' => 'Neue Anweisungen für undefinierte Schritte können mit diesen Code-Schnipseln angelegt werden:',
'failed_steps_title' => 'fehlgeschlagene Schritte',
'pending_steps_title' => 'ausbleibende Schritte',
'scenarios_count' => '{0} Keine Szenarien|{1} 1 Szenario|]1,Inf] %1% Szenarien',
'steps_count' => '{0} Keine Schritte|{1} 1 Schritt|]1,Inf] %1% Schritte',
'passed_count' => '[1,Inf] %1% bestanden',
'failed_count' => '[1,Inf] %1% fehlgeschlagen',
'pending_count' => '[1,Inf] %1% ausbleibend',
'undefined_count' => '[1,Inf] %1% undefiniert',
'skipped_count' => '[1,Inf] %1% übersprungen',
),
'es' =>
array (
'proposal_title' => 'Puedes implementar la definición de pasos de los pasos sin definir con el siguiente código:',
'failed_steps_title' => 'Pasos fallidos',
'pending_steps_title' => 'Pasos pendientes',
'scenarios_count' => '{0} No hay escenarios|{1} 1 escenario|]1,Inf] %1% escenarios',
'steps_count' => '{0} No hay pasos|{1} 1 paso|]1,Inf] %1% pasos',
'passed_count' => '[1,Inf] %1% exitosos',
'failed_count' => '[1,Inf] %1% fallidos',
'pending_count' => '[1,Inf] %1% pendientes',
'undefined_count' => '[1,Inf] %1% sin definir',
'skipped_count' => '[1,Inf] %1% omitidos',
),
'fr' =>
array (
'proposal_title' => 'Vous pouvez implémenter les définitions d\'étapes pour les étapes non définies avec ces modèles :',
'failed_steps_title' => 'étapes échouées',
'pending_steps_title' => 'étapes en attente',
'scenarios_count' => '{0} Aucun scénario|{1} 1 scénario|]1,Inf] %1% scénarios',
'steps_count' => '{0} Aucune étape|{1} 1 étape|]1,Inf] %1% étapes',
'passed_count' => '[1,Inf] %1% succès',
'failed_count' => '[1,Inf] %1% échecs',
'pending_count' => '[1,Inf] %1% en attente',
'undefined_count' => '[1,Inf] %1% non définies',
'skipped_count' => '[1,Inf] %1% ignorées',
),
'id' =>
array (
'proposal_title' => 'Anda dapat membuat definisi untuk langkah yang tidak terdefinisikan menggunakan potongan kode ini:',
'failed_steps_title' => 'langkah gagal',
'pending_steps_title' => 'langkah ditunda',
'scenarios_count' => '{0} Tidak ada skenario|{1} 1 skenario|]1,Inf] %1% skenario',
'steps_count' => '{0} Tidak ada langkah|{1} 1 langkah|]1,Inf] %1% langkah',
'passed_count' => '[1,Inf] %1% sukses',
'failed_count' => '[1,Inf] %1% gagal',
'pending_count' => '[1,Inf] %1% ditunda',
'undefined_count' => '[1,Inf] %1% tidak terdefinisikan',
'skipped_count' => '[1,Inf] %1% dilewat',
),
'it' =>
array (
'proposal_title' => 'E\' possibile implementare gli step ancora non definiti con queste parti di codice:',
'failed_steps_title' => 'step falliti',
'pending_steps_title' => 'step pendenti',
'scenarios_count' => '{0} Nessuno scenario|{1} 1 scenario|]1,Inf] %1% scenari',
'steps_count' => '{0} Nessuno step|{1} 1 step|]1,Inf] %1% step',
'passed_count' => '[1,Inf] %1% passato',
'failed_count' => '[1,Inf] %1% fallito',
'pending_count' => '[1,Inf] %1% in attesa',
'undefined_count' => '[1,Inf] %1% non definito',
'skipped_count' => '[1,Inf] %1% saltato',
),
'ja' =>
array (
'proposal_title' => '未定義ã<C2A9>®ã¹ãƒ†ãƒƒãƒ—ãã€<C3A3>次ã<C2A1>®ã¹ãƒãƒšãƒƒãƒˆã<CB86>§å®Ÿè£…ã<E280A6>§ã<C2A7><C3A3>ã<EFBFBD>¾ã<C2BE>™:',
'failed_steps_title' => '失敗ã<E28094>—ã<E28094>Ÿã¹ãƒ†ãƒƒãƒ—',
'pending_steps_title' => 'ペンデã£ãƒ³ã°ä¸­ã<C2AD>®ã¹ãƒ†ãƒƒãƒ—',
'scenarios_count' => '{0} ã·ãƒŠãƒªãªã<C2AA>Œã<C592>ãŠã<C5A0>¾ã<C2BE>ã“|{1} 1 å€ã<E280B9>®ã·ãƒŠãƒªãª|]1,Inf] %1% å€ã<E280B9>®ã·ãƒŠãƒªãª',
'steps_count' => '{0} ã¹ãƒ†ãƒƒãƒ—ã<E28094>Œã<C592>ãŠã<C5A0>¾ã<C2BE>ã“|{1} 1 å€ã<E280B9>®ã¹ãƒ†ãƒƒãƒ—|]1,Inf] %1% å€ã<E280B9>®ã¹ãƒ†ãƒƒãƒ—',
'passed_count' => '[1,Inf] %1% å€æˆ<C3A6>功',
'failed_count' => '[1,Inf] %1% 個失敗',
'pending_count' => '[1,Inf] %1% 個ペンディング',
'undefined_count' => '[1,Inf] %1% 個未定義',
'skipped_count' => '[1,Inf] %1% 個スキップ',
),
'nl' =>
array (
'proposal_title' => 'U kunt stap definities voor ongedefinieerde stappen implementeren met deze snippets:',
'failed_steps_title' => 'mislukte stappen',
'pending_steps_title' => 'wachtende stappen',
'scenarios_count' => '{0} Geen scenario\'s|{1} 1 scenario|]1,Inf] %1% scenario\'s',
'steps_count' => '{0} Geen stappen|{1} 1 stap|]1,Inf] %1% stappen',
'passed_count' => '[1,Inf] %1% gelukt',
'failed_count' => '[1,Inf] %1% mislukt',
'pending_count' => '[1,Inf] %1% wachtend',
'undefined_count' => '[1,Inf] %1% ongedefinieerd',
'skipped_count' => '[1,Inf] %1% overgeslagen',
),
'pl' =>
array (
'proposal_title' => 'Możesz zaimplementować niezdefiniowane jeszcze kroki, korzystając z tych fragmentów kodu:',
'failed_steps_title' => 'nieudane kroki',
'pending_steps_title' => 'oczekujÄ…ce kroki',
'scenarios_count' => '{0} Brak scenariuszy|{1} 1 scenariusz|{2,3,4,22,23,24,32,33,34,42,43,44} %1% scenariusze|]4,Inf] %1% scenariuszy',
'steps_count' => '{0} Brak kroków|{1} 1 krok|{2,3,4,22,23,24,32,33,34,42,43,44} %1% kroki|]4,Inf] %1% kroków',
'passed_count' => '{1} %1% udany|{2,3,4,22,23,24,32,33,34,42,43,44} %1% udane|]4,Inf] %1% udanych',
'failed_count' => '{1} %1% nieudany|{2,3,4,22,23,24,32,33,34,42,43,44} %1% nieudane|]4,Inf] %1% nieudanych',
'pending_count' => '{1} %1% oczekujÄ…cy|{2,3,4,22,23,24,32,33,34,42,43,44} %1% oczekujÄ…ce|]4,Inf] %1% oczekujÄ…cych',
'undefined_count' => '{1} %1% niezdefiniowany|{2,3,4,22,23,24,32,33,34,42,43,44} %1% niezdefiniowane|]4,Inf] %1% niezdefiniowanych',
'skipped_count' => '{1} %1% pominięty|{2,3,4,22,23,24,32,33,34,42,43,44} %1% pominięte|]4,Inf] %1% pominiętych',
),
'pt' =>
array (
'proposal_title' => 'Você pode implementar definições de passos para aqueles ainda não definidos utilizando-se destes trechos:',
'failed_steps_title' => 'passos que falharam',
'pending_steps_title' => 'passos pendentes',
'scenarios_count' => '{0} Nenhum cenário|{1} 1 cenário|]1,Inf] %1% cenários',
'steps_count' => '{0} Nenhum passo|{1} 1 passo|]1,Inf] %1% passos',
'passed_count' => '{1} passou|]1,Inf] %1% passaram',
'failed_count' => '{1} falhou|]1,Inf] %1% falharam ',
'pending_count' => '{1} pendente|]1,Inf] %1% pendentes',
'undefined_count' => '{1} indefinido|]1,Inf] %1% indefinidos',
'skipped_count' => '{1} ignorado|]1,Inf] %1% ignorados',
),
'ru' =>
array (
'proposal_title' => 'Ð’Ñ‹ можете реализовать определениÑ<C2B8> длÑ<C2BB> новых шагов Ñ<> помощью Ñ<>Ñих шаблонов:',
'failed_steps_title' => 'проваленные шаги',
'pending_steps_title' => 'шаги в ожидании',
'scenarios_count' => '{0} Ð<>ÐµÑ Ñ<>ценариев|{1,21,31} %1% Ñ<>ценарий|{2,3,4,22,23,24} %1% Ñ<>ценариÑ<C2B8>|]4,Inf] %1% Ñ<>ценариев',
'steps_count' => '{0} Ð<>ÐµÑ ÑˆÐ°Ð³Ð¾Ð²|{1,21,31} %1% шаг|{2,3,4,22,23,24} %1% шага|]4,Inf] %1% шагов',
'passed_count' => '{1,21,31} %1% пройден|]1,Inf] %1% пройдено',
'failed_count' => '{1,21,31} %1% провален|]1,Inf] %1% провалено',
'pending_count' => '[1,Inf] %1% в ожидании',
'undefined_count' => '{1,21,31} %1% не определен|]1,Inf] %1% не определено',
'skipped_count' => '{1,21,31} %1% пропущен|]1,Inf] %1% пропущено',
),
);
E0Õ•ÙøšÞ+X<>SèÖàâ ®GBMB