Browse Source

Adding 3 symfony components ClassLoader, Console, Yaml (just for tests)

Julio Montoya 13 năm trước cách đây
mục cha
commit
6fbf853f79
52 tập tin đã thay đổi với 7682 bổ sung0 xóa
  1. 96 0
      main/inc/lib/symfony/symfony/Component/ClassLoader/ApcUniversalClassLoader.php
  2. 222 0
      main/inc/lib/symfony/symfony/Component/ClassLoader/ClassCollectionLoader.php
  3. 62 0
      main/inc/lib/symfony/symfony/Component/ClassLoader/DebugUniversalClassLoader.php
  4. 19 0
      main/inc/lib/symfony/symfony/Component/ClassLoader/LICENSE
  5. 76 0
      main/inc/lib/symfony/symfony/Component/ClassLoader/MapClassLoader.php
  6. 60 0
      main/inc/lib/symfony/symfony/Component/ClassLoader/README.md
  7. 265 0
      main/inc/lib/symfony/symfony/Component/ClassLoader/UniversalClassLoader.php
  8. 25 0
      main/inc/lib/symfony/symfony/Component/ClassLoader/composer.json
  9. 855 0
      main/inc/lib/symfony/symfony/Component/Console/Application.php
  10. 601 0
      main/inc/lib/symfony/symfony/Component/Console/Command/Command.php
  11. 83 0
      main/inc/lib/symfony/symfony/Component/Console/Command/HelpCommand.php
  12. 81 0
      main/inc/lib/symfony/symfony/Component/Console/Command/ListCommand.php
  13. 192 0
      main/inc/lib/symfony/symfony/Component/Console/Formatter/OutputFormatter.php
  14. 83 0
      main/inc/lib/symfony/symfony/Component/Console/Formatter/OutputFormatterInterface.php
  15. 218 0
      main/inc/lib/symfony/symfony/Component/Console/Formatter/OutputFormatterStyle.php
  16. 72 0
      main/inc/lib/symfony/symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php
  17. 129 0
      main/inc/lib/symfony/symfony/Component/Console/Helper/DialogHelper.php
  18. 97 0
      main/inc/lib/symfony/symfony/Component/Console/Helper/FormatterHelper.php
  19. 42 0
      main/inc/lib/symfony/symfony/Component/Console/Helper/Helper.php
  20. 49 0
      main/inc/lib/symfony/symfony/Component/Console/Helper/HelperInterface.php
  21. 104 0
      main/inc/lib/symfony/symfony/Component/Console/Helper/HelperSet.php
  22. 308 0
      main/inc/lib/symfony/symfony/Component/Console/Input/ArgvInput.php
  23. 190 0
      main/inc/lib/symfony/symfony/Component/Console/Input/ArrayInput.php
  24. 211 0
      main/inc/lib/symfony/symfony/Component/Console/Input/Input.php
  25. 132 0
      main/inc/lib/symfony/symfony/Component/Console/Input/InputArgument.php
  26. 524 0
      main/inc/lib/symfony/symfony/Component/Console/Input/InputDefinition.php
  27. 107 0
      main/inc/lib/symfony/symfony/Component/Console/Input/InputInterface.php
  28. 184 0
      main/inc/lib/symfony/symfony/Component/Console/Input/InputOption.php
  29. 79 0
      main/inc/lib/symfony/symfony/Component/Console/Input/StringInput.php
  30. 19 0
      main/inc/lib/symfony/symfony/Component/Console/LICENSE
  31. 47 0
      main/inc/lib/symfony/symfony/Component/Console/Output/ConsoleOutput.php
  32. 34 0
      main/inc/lib/symfony/symfony/Component/Console/Output/NullOutput.php
  33. 184 0
      main/inc/lib/symfony/symfony/Component/Console/Output/Output.php
  34. 109 0
      main/inc/lib/symfony/symfony/Component/Console/Output/OutputInterface.php
  35. 113 0
      main/inc/lib/symfony/symfony/Component/Console/Output/StreamOutput.php
  36. 48 0
      main/inc/lib/symfony/symfony/Component/Console/README.md
  37. 136 0
      main/inc/lib/symfony/symfony/Component/Console/Shell.php
  38. 100 0
      main/inc/lib/symfony/symfony/Component/Console/Tester/ApplicationTester.php
  39. 100 0
      main/inc/lib/symfony/symfony/Component/Console/Tester/CommandTester.php
  40. 25 0
      main/inc/lib/symfony/symfony/Component/Console/composer.json
  41. 54 0
      main/inc/lib/symfony/symfony/Component/Yaml/Dumper.php
  42. 88 0
      main/inc/lib/symfony/symfony/Component/Yaml/Escaper.php
  43. 23 0
      main/inc/lib/symfony/symfony/Component/Yaml/Exception/DumpException.php
  44. 23 0
      main/inc/lib/symfony/symfony/Component/Yaml/Exception/ExceptionInterface.php
  45. 143 0
      main/inc/lib/symfony/symfony/Component/Yaml/Exception/ParseException.php
  46. 406 0
      main/inc/lib/symfony/symfony/Component/Yaml/Inline.php
  47. 19 0
      main/inc/lib/symfony/symfony/Component/Yaml/LICENSE
  48. 556 0
      main/inc/lib/symfony/symfony/Component/Yaml/Parser.php
  49. 17 0
      main/inc/lib/symfony/symfony/Component/Yaml/README.md
  50. 145 0
      main/inc/lib/symfony/symfony/Component/Yaml/Unescaper.php
  51. 102 0
      main/inc/lib/symfony/symfony/Component/Yaml/Yaml.php
  52. 25 0
      main/inc/lib/symfony/symfony/Component/Yaml/composer.json

+ 96 - 0
main/inc/lib/symfony/symfony/Component/ClassLoader/ApcUniversalClassLoader.php

@@ -0,0 +1,96 @@
+<?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\ClassLoader;
+
+/**
+ * ApcUniversalClassLoader implements a "universal" autoloader cached in APC for PHP 5.3.
+ *
+ * It is able to load classes that use either:
+ *
+ *  * The technical interoperability standards for PHP 5.3 namespaces and
+ *    class names (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md);
+ *
+ *  * The PEAR naming convention for classes (http://pear.php.net/).
+ *
+ * Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be
+ * looked for in a list of locations to ease the vendoring of a sub-set of
+ * classes for large projects.
+ *
+ * Example usage:
+ *
+ *     require 'vendor/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
+ *     require 'vendor/symfony/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php';
+ *
+ *     use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
+ *
+ *     $loader = new ApcUniversalClassLoader('apc.prefix.');
+ *
+ *     // register classes with namespaces
+ *     $loader->registerNamespaces(array(
+ *         'Symfony\Component' => __DIR__.'/component',
+ *         'Symfony'           => __DIR__.'/framework',
+ *         'Sensio'            => array(__DIR__.'/src', __DIR__.'/vendor'),
+ *     ));
+ *
+ *     // register a library using the PEAR naming convention
+ *     $loader->registerPrefixes(array(
+ *         'Swift_' => __DIR__.'/Swift',
+ *     ));
+ *
+ *     // activate the autoloader
+ *     $loader->register();
+ *
+ * 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.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Kris Wallsmith <kris@symfony.com>
+ *
+ * @api
+ */
+class ApcUniversalClassLoader extends UniversalClassLoader
+{
+    private $prefix;
+
+    /**
+     * Constructor.
+     *
+     * @param string $prefix A prefix to create a namespace in APC
+     *
+     * @api
+     */
+    public function __construct($prefix)
+    {
+        if (!extension_loaded('apc')) {
+            throw new \RuntimeException('Unable to use ApcUniversalClassLoader as APC is not enabled.');
+        }
+
+        $this->prefix = $prefix;
+    }
+
+    /**
+     * Finds a file by class name while caching lookups to APC.
+     *
+     * @param string $class A class name to resolve to file
+     */
+    public function findFile($class)
+    {
+        if (false === $file = apc_fetch($this->prefix.$class)) {
+            apc_store($this->prefix.$class, $file = parent::findFile($class));
+        }
+
+        return $file;
+    }
+}

+ 222 - 0
main/inc/lib/symfony/symfony/Component/ClassLoader/ClassCollectionLoader.php

@@ -0,0 +1,222 @@
+<?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\ClassLoader;
+
+/**
+ * ClassCollectionLoader.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class ClassCollectionLoader
+{
+    static private $loaded;
+
+    /**
+     * Loads a list of classes and caches them in one big file.
+     *
+     * @param array   $classes    An array of classes to load
+     * @param string  $cacheDir   A cache directory
+     * @param string  $name       The cache name prefix
+     * @param Boolean $autoReload Whether to flush the cache when the cache is stale or not
+     * @param Boolean $adaptive   Whether to remove already declared classes or not
+     * @param string  $extension  File extension of the resulting file
+     *
+     * @throws \InvalidArgumentException When class can't be loaded
+     */
+    static public function load($classes, $cacheDir, $name, $autoReload, $adaptive = false, $extension = '.php')
+    {
+        // each $name can only be loaded once per PHP process
+        if (isset(self::$loaded[$name])) {
+            return;
+        }
+
+        self::$loaded[$name] = true;
+
+        if ($adaptive) {
+            // don't include already declared classes
+            $classes = array_diff($classes, get_declared_classes(), get_declared_interfaces());
+
+            // the cache is different depending on which classes are already declared
+            $name = $name.'-'.substr(md5(implode('|', $classes)), 0, 5);
+        }
+
+        $cache = $cacheDir.'/'.$name.$extension;
+
+        // auto-reload
+        $reload = false;
+        if ($autoReload) {
+            $metadata = $cacheDir.'/'.$name.$extension.'.meta';
+            if (!file_exists($metadata) || !file_exists($cache)) {
+                $reload = true;
+            } else {
+                $time = filemtime($cache);
+                $meta = unserialize(file_get_contents($metadata));
+
+                if ($meta[1] != $classes) {
+                    $reload = true;
+                } else {
+                    foreach ($meta[0] as $resource) {
+                        if (!file_exists($resource) || filemtime($resource) > $time) {
+                            $reload = true;
+
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!$reload && file_exists($cache)) {
+            require_once $cache;
+
+            return;
+        }
+
+        $files = array();
+        $content = '';
+        foreach ($classes as $class) {
+            if (!class_exists($class) && !interface_exists($class) && (!function_exists('trait_exists') || !trait_exists($class))) {
+                throw new \InvalidArgumentException(sprintf('Unable to load class "%s"', $class));
+            }
+
+            $r = new \ReflectionClass($class);
+            $files[] = $r->getFileName();
+
+            $c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($r->getFileName()));
+
+            // add namespace declaration for global code
+            if (!$r->inNamespace()) {
+                $c = "\nnamespace\n{\n".self::stripComments($c)."\n}\n";
+            } else {
+                $c = self::fixNamespaceDeclarations('<?php '.$c);
+                $c = preg_replace('/^\s*<\?php/', '', $c);
+            }
+
+            $content .= $c;
+        }
+
+        // cache the core classes
+        if (!is_dir(dirname($cache))) {
+            mkdir(dirname($cache), 0777, true);
+        }
+        self::writeCacheFile($cache, '<?php '.$content);
+
+        if ($autoReload) {
+            // save the resources
+            self::writeCacheFile($metadata, serialize(array($files, $classes)));
+        }
+    }
+
+    /**
+     * Adds brackets around each namespace if it's not already the case.
+     *
+     * @param string $source Namespace string
+     *
+     * @return string Namespaces with brackets
+     */
+    static public function fixNamespaceDeclarations($source)
+    {
+        if (!function_exists('token_get_all')) {
+            return $source;
+        }
+
+        $output = '';
+        $inNamespace = false;
+        $tokens = token_get_all($source);
+
+        for ($i = 0, $max = count($tokens); $i < $max; $i++) {
+            $token = $tokens[$i];
+            if (is_string($token)) {
+                $output .= $token;
+            } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
+                // strip comments
+                continue;
+            } elseif (T_NAMESPACE === $token[0]) {
+                if ($inNamespace) {
+                    $output .= "}\n";
+                }
+                $output .= $token[1];
+
+                // namespace name and whitespaces
+                while (($t = $tokens[++$i]) && is_array($t) && in_array($t[0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) {
+                    $output .= $t[1];
+                }
+                if (is_string($t) && '{' === $t) {
+                    $inNamespace = false;
+                    --$i;
+                } else {
+                    $output .= "\n{";
+                    $inNamespace = true;
+                }
+            } else {
+                $output .= $token[1];
+            }
+        }
+
+        if ($inNamespace) {
+            $output .= "}\n";
+        }
+
+        return $output;
+    }
+
+    /**
+     * Writes a cache file.
+     *
+     * @param string $file Filename
+     * @param string $content Temporary file content
+     *
+     * @throws \RuntimeException when a cache file cannot be written
+     */
+    static private function writeCacheFile($file, $content)
+    {
+        $tmpFile = tempnam(dirname($file), basename($file));
+        if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {
+            chmod($file, 0644);
+
+            return;
+        }
+
+        throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file));
+    }
+
+    /**
+     * Removes comments from a PHP source string.
+     *
+     * We don't use the PHP php_strip_whitespace() function
+     * as we want the content to be readable and well-formatted.
+     *
+     * @param string $source A PHP string
+     *
+     * @return string The PHP string with the comments removed
+     */
+    static private function stripComments($source)
+    {
+        if (!function_exists('token_get_all')) {
+            return $source;
+        }
+
+        $output = '';
+        foreach (token_get_all($source) as $token) {
+            if (is_string($token)) {
+                $output .= $token;
+            } elseif (!in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
+                $output .= $token[1];
+            }
+        }
+
+        // replace multiple new lines with a single newline
+        $output = preg_replace(array('/\s+$/Sm', '/\n+/S'), "\n", $output);
+
+        return $output;
+    }
+}

+ 62 - 0
main/inc/lib/symfony/symfony/Component/ClassLoader/DebugUniversalClassLoader.php

@@ -0,0 +1,62 @@
+<?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\ClassLoader;
+
+/**
+ * Checks that the class is actually declared in the included file.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class DebugUniversalClassLoader extends UniversalClassLoader
+{
+    /**
+     * Replaces all regular UniversalClassLoader instances by a DebugUniversalClassLoader ones.
+     */
+    static public function enable()
+    {
+        if (!is_array($functions = spl_autoload_functions())) {
+            return;
+        }
+
+        foreach ($functions as $function) {
+            spl_autoload_unregister($function);
+        }
+
+        foreach ($functions as $function) {
+            if (is_array($function) && $function[0] instanceof UniversalClassLoader) {
+                $loader = new static();
+                $loader->registerNamespaceFallbacks($function[0]->getNamespaceFallbacks());
+                $loader->registerPrefixFallbacks($function[0]->getPrefixFallbacks());
+                $loader->registerNamespaces($function[0]->getNamespaces());
+                $loader->registerPrefixes($function[0]->getPrefixes());
+
+                $function[0] = $loader;
+            }
+
+            spl_autoload_register($function);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function loadClass($class)
+    {
+        if ($file = $this->findFile($class)) {
+            require $file;
+
+            if (!class_exists($class, false) && !interface_exists($class, false) && (!function_exists('trait_exists') || !trait_exists($class, false))) {
+                throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
+            }
+        }
+    }
+}

+ 19 - 0
main/inc/lib/symfony/symfony/Component/ClassLoader/LICENSE

@@ -0,0 +1,19 @@
+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.

+ 76 - 0
main/inc/lib/symfony/symfony/Component/ClassLoader/MapClassLoader.php

@@ -0,0 +1,76 @@
+<?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\ClassLoader;
+
+/**
+ * A class loader that uses a mapping file to look up paths.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class MapClassLoader
+{
+    private $map = array();
+
+    /**
+     * Constructor.
+     *
+     * @param array $map A map where keys are classes and values the absolute file path
+     */
+    public function __construct(array $map)
+    {
+        $this->map = $map;
+    }
+
+    /**
+     * 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];
+        }
+    }
+}

+ 60 - 0
main/inc/lib/symfony/symfony/Component/ClassLoader/README.md

@@ -0,0 +1,60 @@
+ClassLoader Component
+=====================
+
+ClassLoader loads your project classes automatically if they follow some
+standard PHP conventions.
+
+The Universal ClassLoader is able to autoload classes that implement the PSR-0
+standard or the PEAR naming convention.
+
+First, register the autoloader:
+
+    require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
+
+    use Symfony\Component\ClassLoader\UniversalClassLoader;
+
+    $loader = new UniversalClassLoader();
+    $loader->register();
+
+Then, register some namespaces with the `registerNamespace()` method:
+
+    $loader->registerNamespace('Symfony', __DIR__.'/src');
+    $loader->registerNamespace('Monolog', __DIR__.'/vendor/monolog/src');
+
+The `registerNamespace()` method takes a namespace prefix and a path where to
+look for the classes as arguments.
+
+You can also register a sub-namespaces:
+
+    $loader->registerNamespace('Doctrine\\Common', __DIR__.'/vendor/doctrine-common/lib');
+
+The order of registration is significant and the first registered namespace
+takes precedence over later registered one.
+
+You can also register more than one path for a given namespace:
+
+    $loader->registerNamespace('Symfony', array(__DIR__.'/src', __DIR__.'/symfony/src'));
+
+Alternatively, you can use the `registerNamespaces()` method to register more
+than one namespace at once:
+
+    $loader->registerNamespaces(array(
+        'Symfony'          => array(__DIR__.'/src', __DIR__.'/symfony/src'),
+        'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib',
+        'Doctrine'         => __DIR__.'/vendor/doctrine/lib',
+        'Monolog'          => __DIR__.'/vendor/monolog/src',
+    ));
+
+For better performance, you can use the APC based version of the universal
+class loader:
+
+    require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
+    require_once __DIR__.'/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php';
+
+    use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
+
+    $loader = new ApcUniversalClassLoader('apc.prefix.');
+
+Furthermore, the component provides tools to aggregate classes into a single
+file, which is especially useful to improve performance on servers that do not
+provide byte caches.

+ 265 - 0
main/inc/lib/symfony/symfony/Component/ClassLoader/UniversalClassLoader.php

@@ -0,0 +1,265 @@
+<?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\ClassLoader;
+
+/**
+ * UniversalClassLoader implements a "universal" autoloader for PHP 5.3.
+ *
+ * It is able to load classes that use either:
+ *
+ *  * The technical interoperability standards for PHP 5.3 namespaces and
+ *    class names (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md);
+ *
+ *  * The PEAR naming convention for classes (http://pear.php.net/).
+ *
+ * Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be
+ * looked for in a list of locations to ease the vendoring of a sub-set of
+ * classes for large projects.
+ *
+ * Example usage:
+ *
+ *     $loader = new UniversalClassLoader();
+ *
+ *     // register classes with namespaces
+ *     $loader->registerNamespaces(array(
+ *         'Symfony\Component' => __DIR__.'/component',
+ *         'Symfony'           => __DIR__.'/framework',
+ *         'Sensio'            => array(__DIR__.'/src', __DIR__.'/vendor'),
+ *     ));
+ *
+ *     // register a library using the PEAR naming convention
+ *     $loader->registerPrefixes(array(
+ *         'Swift_' => __DIR__.'/Swift',
+ *     ));
+ *
+ *     // activate the autoloader
+ *     $loader->register();
+ *
+ * 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.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class UniversalClassLoader
+{
+    private $namespaces = array();
+    private $prefixes = array();
+    private $namespaceFallbacks = array();
+    private $prefixFallbacks = array();
+
+    /**
+     * Gets the configured namespaces.
+     *
+     * @return array A hash with namespaces as keys and directories as values
+     */
+    public function getNamespaces()
+    {
+        return $this->namespaces;
+    }
+
+    /**
+     * Gets the configured class prefixes.
+     *
+     * @return array A hash with class prefixes as keys and directories as values
+     */
+    public function getPrefixes()
+    {
+        return $this->prefixes;
+    }
+
+    /**
+     * Gets the directory(ies) to use as a fallback for namespaces.
+     *
+     * @return array An array of directories
+     */
+    public function getNamespaceFallbacks()
+    {
+        return $this->namespaceFallbacks;
+    }
+
+    /**
+     * Gets the directory(ies) to use as a fallback for class prefixes.
+     *
+     * @return array An array of directories
+     */
+    public function getPrefixFallbacks()
+    {
+        return $this->prefixFallbacks;
+    }
+
+    /**
+     * Registers the directory to use as a fallback for namespaces.
+     *
+     * @param array $dirs An array of directories
+     *
+     * @api
+     */
+    public function registerNamespaceFallbacks(array $dirs)
+    {
+        $this->namespaceFallbacks = $dirs;
+    }
+
+    /**
+     * Registers the directory to use as a fallback for class prefixes.
+     *
+     * @param array $dirs An array of directories
+     *
+     * @api
+     */
+    public function registerPrefixFallbacks(array $dirs)
+    {
+        $this->prefixFallbacks = $dirs;
+    }
+
+    /**
+     * Registers an array of namespaces
+     *
+     * @param array $namespaces An array of namespaces (namespaces as keys and locations as values)
+     *
+     * @api
+     */
+    public function registerNamespaces(array $namespaces)
+    {
+        foreach ($namespaces as $namespace => $locations) {
+            $this->namespaces[$namespace] = (array) $locations;
+        }
+    }
+
+    /**
+     * Registers a namespace.
+     *
+     * @param string       $namespace The namespace
+     * @param array|string $paths     The location(s) of the namespace
+     *
+     * @api
+     */
+    public function registerNamespace($namespace, $paths)
+    {
+        $this->namespaces[$namespace] = (array) $paths;
+    }
+
+    /**
+     * Registers an array of classes using the PEAR naming convention.
+     *
+     * @param array $classes An array of classes (prefixes as keys and locations as values)
+     *
+     * @api
+     */
+    public function registerPrefixes(array $classes)
+    {
+        foreach ($classes as $prefix => $locations) {
+            $this->prefixes[$prefix] = (array) $locations;
+        }
+    }
+
+    /**
+     * Registers a set of classes using the PEAR naming convention.
+     *
+     * @param string       $prefix  The classes prefix
+     * @param array|string $paths   The location(s) of the classes
+     *
+     * @api
+     */
+    public function registerPrefix($prefix, $paths)
+    {
+        $this->prefixes[$prefix] = (array) $paths;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param Boolean $prepend Whether to prepend the autoloader or not
+     *
+     * @api
+     */
+    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 ($file = $this->findFile($class)) {
+            require $file;
+        }
+    }
+
+    /**
+     * 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 (false !== $pos = strrpos($class, '\\')) {
+            // namespaced class name
+            $namespace = substr($class, 0, $pos);
+            foreach ($this->namespaces as $ns => $dirs) {
+                if (0 !== strpos($namespace, $ns)) {
+                    continue;
+                }
+
+                foreach ($dirs as $dir) {
+                    $className = substr($class, $pos + 1);
+                    $file = $dir.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $className).'.php';
+                    if (file_exists($file)) {
+                        return $file;
+                    }
+                }
+            }
+
+            foreach ($this->namespaceFallbacks as $dir) {
+                $file = $dir.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
+                if (file_exists($file)) {
+                    return $file;
+                }
+            }
+        } else {
+            // PEAR-like class name
+            foreach ($this->prefixes as $prefix => $dirs) {
+                if (0 !== strpos($class, $prefix)) {
+                    continue;
+                }
+
+                foreach ($dirs as $dir) {
+                    $file = $dir.DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';
+                    if (file_exists($file)) {
+                        return $file;
+                    }
+                }
+            }
+
+            foreach ($this->prefixFallbacks as $dir) {
+                $file = $dir.DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';
+                if (file_exists($file)) {
+                    return $file;
+                }
+            }
+        }
+    }
+}

+ 25 - 0
main/inc/lib/symfony/symfony/Component/ClassLoader/composer.json

@@ -0,0 +1,25 @@
+{
+    "name": "symfony/class-loader",
+    "type": "library",
+    "description": "Symfony ClassLoader Component",
+    "keywords": [],
+    "homepage": "http://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Fabien Potencier",
+            "email": "fabien@symfony.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "http://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.2"
+    },
+    "autoload": {
+        "psr-0": { "Symfony\\Component\\ClassLoader": "" }
+    },
+    "target-dir": "Symfony/Component/ClassLoader"
+}

+ 855 - 0
main/inc/lib/symfony/symfony/Component/Console/Application.php

@@ -0,0 +1,855 @@
+<?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 catched 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);
+            $lines = array();
+            foreach (explode("\n", $e->getMessage()) as $line) {
+                $lines[] = sprintf('  %s  ', $line);
+                $len = max($strlen($line) + 4, $len);
+            }
+
+            $messages = array(str_repeat(' ', $len), $title.str_repeat(' ', $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("");
+        }
+    }
+
+    /**
+     * 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));
+    }
+}

+ 601 - 0
main/inc/lib/symfony/symfony/Component/Console/Command/Command.php

@@ -0,0 +1,601 @@
+<?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
+     *
+     * @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));
+        }
+    }
+}

+ 83 - 0
main/inc/lib/symfony/symfony/Component/Console/Command/HelpCommand.php

@@ -0,0 +1,83 @@
+<?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;
+    }
+}

+ 81 - 0
main/inc/lib/symfony/symfony/Component/Console/Command/ListCommand.php

@@ -0,0 +1,81 @@
+<?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'),
+        ));
+    }
+}

+ 192 - 0
main/inc/lib/symfony/symfony/Component/Console/Formatter/OutputFormatter.php

@@ -0,0 +1,192 @@
+<?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;
+    }
+}

+ 83 - 0
main/inc/lib/symfony/symfony/Component/Console/Formatter/OutputFormatterInterface.php

@@ -0,0 +1,83 @@
+<?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);
+}

+ 218 - 0
main/inc/lib/symfony/symfony/Component/Console/Formatter/OutputFormatterStyle.php

@@ -0,0 +1,218 @@
+<?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     style foreground color name
+     * @param   string  $background     style background color name
+     * @param   array   $options        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  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  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     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     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);
+    }
+}

+ 72 - 0
main/inc/lib/symfony/symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php

@@ -0,0 +1,72 @@
+<?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  color name
+     *
+     * @api
+     */
+    function setForeground($color = null);
+
+    /**
+     * Sets style background color.
+     *
+     * @param   string  $color  color name
+     *
+     * @api
+     */
+    function setBackground($color = null);
+
+    /**
+     * Sets some specific style option.
+     *
+     * @param   string  $option     option name
+     *
+     * @api
+     */
+    function setOption($option);
+
+    /**
+     * Unsets some specific style option.
+     *
+     * @param   string  $option     option 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);
+}

+ 129 - 0
main/inc/lib/symfony/symfony/Component/Console/Helper/DialogHelper.php

@@ -0,0 +1,129 @@
+<?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.
+     */
+    public function getName()
+    {
+        return 'dialog';
+    }
+}

+ 97 - 0
main/inc/lib/symfony/symfony/Component/Console/Helper/FormatterHelper.php

@@ -0,0 +1,97 @@
+<?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
+     */
+    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';
+    }
+}

+ 42 - 0
main/inc/lib/symfony/symfony/Component/Console/Helper/Helper.php

@@ -0,0 +1,42 @@
+<?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;
+    }
+}

+ 49 - 0
main/inc/lib/symfony/symfony/Component/Console/Helper/HelperInterface.php

@@ -0,0 +1,49 @@
+<?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();
+}

+ 104 - 0
main/inc/lib/symfony/symfony/Component/Console/Helper/HelperSet.php

@@ -0,0 +1,104 @@
+<?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;
+    }
+}

+ 308 - 0
main/inc/lib/symfony/symfony/Component/Console/Input/ArgvInput.php

@@ -0,0 +1,308 @@
+<?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;
+    }
+}

+ 190 - 0
main/inc/lib/symfony/symfony/Component/Console/Input/ArrayInput.php

@@ -0,0 +1,190 @@
+<?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;
+    }
+}

+ 211 - 0
main/inc/lib/symfony/symfony/Component/Console/Input/Input.php

@@ -0,0 +1,211 @@
+<?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);
+    }
+}

+ 132 - 0
main/inc/lib/symfony/symfony/Component/Console/Input/InputArgument.php

@@ -0,0 +1,132 @@
+<?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;
+    }
+}

+ 524 - 0
main/inc/lib/symfony/symfony/Component/Console/Input/InputDefinition.php

@@ -0,0 +1,524 @@
+<?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();
+    }
+}

+ 107 - 0
main/inc/lib/symfony/symfony/Component/Console/Input/InputInterface.php

@@ -0,0 +1,107 @@
+<?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();
+}

+ 184 - 0
main/inc/lib/symfony/symfony/Component/Console/Input/InputOption.php

@@ -0,0 +1,184 @@
+<?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;
+    }
+}

+ 79 - 0
main/inc/lib/symfony/symfony/Component/Console/Input/StringInput.php

@@ -0,0 +1,79 @@
+<?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
+     *
+     * @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;
+    }
+}

+ 19 - 0
main/inc/lib/symfony/symfony/Component/Console/LICENSE

@@ -0,0 +1,19 @@
+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.

+ 47 - 0
main/inc/lib/symfony/symfony/Component/Console/Output/ConsoleOutput.php

@@ -0,0 +1,47 @@
+<?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)
+    {
+        parent::__construct(fopen('php://stdout', 'w'), $verbosity, $decorated, $formatter);
+    }
+}

+ 34 - 0
main/inc/lib/symfony/symfony/Component/Console/Output/NullOutput.php

@@ -0,0 +1,34 @@
+<?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)
+    {
+    }
+}

+ 184 - 0
main/inc/lib/symfony/symfony/Component/Console/Output/Output.php

@@ -0,0 +1,184 @@
+<?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);
+}

+ 109 - 0
main/inc/lib/symfony/symfony/Component/Console/Output/OutputInterface.php

@@ -0,0 +1,109 @@
+<?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();
+}

+ 113 - 0
main/inc/lib/symfony/symfony/Component/Console/Output/StreamOutput.php

@@ -0,0 +1,113 @@
+<?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
+    }
+}

+ 48 - 0
main/inc/lib/symfony/symfony/Component/Console/README.md

@@ -0,0 +1,48 @@
+Console Component
+=================
+
+Console eases the creation of beautiful and testable command line interfaces.
+
+The Application object manages the CLI application:
+
+    use Symfony\Component\Console\Application;
+
+    $console = new Application();
+    $console->run();
+
+The ``run()`` method parses the arguments and options passed on the command
+line and executes the right command.
+
+Registering a new command can easily be done via the ``register()`` method,
+which returns a ``Command`` instance:
+
+    use Symfony\Component\Console\Input\InputInterface;
+    use Symfony\Component\Console\Input\InputArgument;
+    use Symfony\Component\Console\Input\InputOption;
+    use Symfony\Component\Console\Output\OutputInterface;
+
+    $console
+        ->register('ls')
+        ->setDefinition(array(
+            new InputArgument('dir', InputArgument::REQUIRED, 'Directory name'),
+        ))
+        ->setDescription('Displays the files in the given directory')
+        ->setCode(function (InputInterface $input, OutputInterface $output) {
+            $dir = $input->getArgument('dir');
+
+            $output->writeln(sprintf('Dir listing for <info>%s</info>', $dir));
+        })
+    ;
+
+You can also register new commands via classes.
+
+The component provides a lot of features like output coloring, input and
+output abstractions (so that you can easily unit-test your commands),
+validation, automatic help messages, ...
+
+Resources
+---------
+
+Unit tests:
+
+https://github.com/symfony/symfony/tree/master/tests/Symfony/Tests/Component/Console

+ 136 - 0
main/inc/lib/symfony/symfony/Component/Console/Shell.php

@@ -0,0 +1,136 @@
+<?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
+     */
+    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;
+    }
+}

+ 100 - 0
main/inc/lib/symfony/symfony/Component/Console/Tester/ApplicationTester.php

@@ -0,0 +1,100 @@
+<?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;
+
+/**
+ * @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;
+    }
+}

+ 100 - 0
main/inc/lib/symfony/symfony/Component/Console/Tester/CommandTester.php

@@ -0,0 +1,100 @@
+<?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;
+
+/**
+ * @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;
+    }
+}

+ 25 - 0
main/inc/lib/symfony/symfony/Component/Console/composer.json

@@ -0,0 +1,25 @@
+{
+    "name": "symfony/console",
+    "type": "library",
+    "description": "Symfony Console Component",
+    "keywords": [],
+    "homepage": "http://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Fabien Potencier",
+            "email": "fabien@symfony.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "http://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.2"
+    },
+    "autoload": {
+        "psr-0": { "Symfony\\Component\\Console": "" }
+    },
+    "target-dir": "Symfony/Component/Console"
+}

+ 54 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Dumper.php

@@ -0,0 +1,54 @@
+<?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;
+    }
+}

+ 88 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Escaper.php

@@ -0,0 +1,88 @@
+<?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));
+    }
+}

+ 23 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Exception/DumpException.php

@@ -0,0 +1,23 @@
+<?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
+{
+}

+ 23 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Exception/ExceptionInterface.php

@@ -0,0 +1,23 @@
+<?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
+{
+}

+ 143 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Exception/ParseException.php

@@ -0,0 +1,143 @@
+<?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 .= '.';
+        }
+    }
+}

+ 406 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Inline.php

@@ -0,0 +1,406 @@
+<?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;
+    }
+}

+ 19 - 0
main/inc/lib/symfony/symfony/Component/Yaml/LICENSE

@@ -0,0 +1,19 @@
+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.

+ 556 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Parser.php

@@ -0,0 +1,556 @@
+<?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;
+    }
+}

+ 17 - 0
main/inc/lib/symfony/symfony/Component/Yaml/README.md

@@ -0,0 +1,17 @@
+Yaml Component
+==============
+
+YAML implements most of the YAML 1.2 specification.
+
+    use Symfony\Component\Yaml\Yaml;
+
+    $array = Yaml::parse($file);
+
+    print Yaml::dump($array);
+
+Resources
+---------
+
+Unit tests:
+
+https://github.com/symfony/symfony/tree/master/tests/Symfony/Tests/Component/Yaml

+ 145 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Unescaper.php

@@ -0,0 +1,145 @@
+<?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).');
+    }
+}

+ 102 - 0
main/inc/lib/symfony/symfony/Component/Yaml/Yaml.php

@@ -0,0 +1,102 @@
+<?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);
+    }
+}

+ 25 - 0
main/inc/lib/symfony/symfony/Component/Yaml/composer.json

@@ -0,0 +1,25 @@
+{
+    "name": "symfony/yaml",
+    "type": "library",
+    "description": "Symfony Yaml Component",
+    "keywords": [],
+    "homepage": "http://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Fabien Potencier",
+            "email": "fabien@symfony.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "http://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.2"
+    },
+    "autoload": {
+        "psr-0": { "Symfony\\Component\\Yaml": "" }
+    },
+    "target-dir": "Symfony/Component/Yaml"
+}