├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── AUTHORS ├── Console └── ApplicationFactory.php ├── Contract └── Executer │ └── CommandExecuterInterface.php ├── Controller └── ConsoleController.php ├── CoreSphereConsoleBundle.php ├── DataCollector └── DataCollector.php ├── DependencyInjection └── Extension │ └── CoreSphereConsoleExtension.php ├── Executer └── CommandExecuter.php ├── Formatter └── HtmlOutputFormatterDecorator.php ├── LICENSE ├── Output └── StringOutput.php ├── README.md ├── Resources ├── config │ ├── routing.yml │ └── services.yml ├── public │ ├── css │ │ ├── base.css │ │ └── console.css │ └── js │ │ ├── console.js │ │ └── jquery-1.8.3.min.js ├── translations │ ├── messages.bg.yml │ ├── messages.de.yml │ ├── messages.en.yml │ ├── messages.es.yml │ ├── messages.fr.yml │ ├── messages.it.yml │ ├── messages.nl.yml │ ├── messages.pl.yml │ └── messages.ru.yml └── views │ ├── Console │ ├── console.html.twig │ ├── htmlTemplates.html.twig │ ├── result.json.twig │ └── terminal.html.twig │ ├── Toolbar │ └── toolbar.html.twig │ └── base.html.twig ├── Routing └── Loader.php ├── Tests ├── Console │ └── ApplicationFactoryTest.php ├── Controller │ └── ConsoleControllerTest.php ├── DataCollector │ └── DataCollectorTest.php ├── DependencyInjection │ └── Extension │ │ └── CoreSphereConsoleExtensionTest.php ├── Executer │ ├── CommandExecuterTest.php │ └── CommandExecutorSource │ │ └── SomeKernel.php ├── Formatter │ └── HtmlOutputFormatterDecoratorTest.php ├── Output │ └── StringOutputTest.php ├── Routing │ └── LoaderTest.php └── Source │ └── KernelWithBundlesWithCommands.php ├── composer.json └── phpunit.xml.dist /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | composer.lock 3 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | before_commands: 2 | - "composer install --prefer-source" 3 | 4 | tools: 5 | external_code_coverage: 6 | timeout: 900 7 | sensiolabs_security_checker: true 8 | php_code_coverage: 9 | enabled: true 10 | php_analyzer: 11 | config: 12 | verify_php_doc_comments: 13 | suggest_more_specific_types: false 14 | 15 | checks: 16 | php: 17 | code_rating: true 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5 5 | - 5.6 6 | - 7.0 7 | - hhvm 8 | 9 | install: 10 | - composer install 11 | 12 | before_script: 13 | - if [[ $TRAVIS_PHP_VERSION = '5.6' ]]; then PHPUNIT_FLAGS="--coverage-clover coverage.xml"; fi 14 | - if [[ $TRAVIS_PHP_VERSION = '5.6' ]]; then wget http://get.sensiolabs.org/php-cs-fixer.phar -O php-cs-fixer; fi 15 | 16 | script: 17 | - phpunit $PHPUNIT_FLAGS 18 | - if [[ $TRAVIS_PHP_VERSION = '5.6' ]]; then php php-cs-fixer fix . --diff --dry-run -v --rules=@Symfony; fi 19 | 20 | after_script: 21 | - if [[ $TRAVIS_PHP_VERSION = '5.6' ]]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.xml; fi 22 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | CoreSphere ConsoleBundle is written and maintained by the CoreSphere Team and various contributors: 2 | 3 | Developers: 4 | 5 | Laszlo Korte 6 | Markus Ullmann 7 | 8 | Contributors: 9 | 10 | Alexandre "winzou" Bacco 11 | 12 | Translators: 13 | 14 | Alexandre "winzou" Bacco 15 | -------------------------------------------------------------------------------- /Console/ApplicationFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Console; 13 | 14 | use Symfony\Bundle\FrameworkBundle\Console\Application; 15 | use Symfony\Component\HttpKernel\Bundle\Bundle; 16 | use Symfony\Component\HttpKernel\KernelInterface; 17 | 18 | class ApplicationFactory 19 | { 20 | /** 21 | * @return Application 22 | */ 23 | public function create(KernelInterface $kernel) 24 | { 25 | $application = new Application($kernel); 26 | $application = $this->registerCommandsToApplication($application, $kernel); 27 | 28 | return $application; 29 | } 30 | 31 | /** 32 | * @return Application 33 | */ 34 | private function registerCommandsToApplication(Application $application, KernelInterface $kernel) 35 | { 36 | chdir($kernel->getRootDir().'/..'); 37 | 38 | foreach ($this->getBundlesFromKernel($kernel) as $bundle) { 39 | $bundle->registerCommands($application); 40 | } 41 | 42 | return $application; 43 | } 44 | 45 | /** 46 | * @return Bundle[] 47 | */ 48 | private function getBundlesFromKernel(KernelInterface $kernel) 49 | { 50 | if ($bundles = $kernel->getBundles()) { 51 | return $bundles; 52 | } 53 | 54 | return $kernel->registerBundles(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Contract/Executer/CommandExecuterInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Contract\Executer; 13 | 14 | /** 15 | * Takes a string to execute as console command. 16 | */ 17 | interface CommandExecuterInterface 18 | { 19 | /** 20 | * @param string $commandString 21 | * 22 | * @return array 23 | */ 24 | public function execute($commandString); 25 | } 26 | -------------------------------------------------------------------------------- /Controller/ConsoleController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Controller; 13 | 14 | use CoreSphere\ConsoleBundle\Contract\Executer\CommandExecuterInterface; 15 | use Symfony\Bundle\FrameworkBundle\Console\Application; 16 | use Symfony\Component\HttpFoundation\Request; 17 | use Symfony\Component\HttpFoundation\Response; 18 | use Symfony\Component\Templating\EngineInterface; 19 | 20 | class ConsoleController 21 | { 22 | /** 23 | * @var EngineInterface 24 | */ 25 | private $templating; 26 | 27 | /** 28 | * @var CommandExecuterInterface 29 | */ 30 | private $commandExecuter; 31 | 32 | /** 33 | * @var Application 34 | */ 35 | private $application; 36 | 37 | /** 38 | * @var string 39 | */ 40 | private $environment; 41 | 42 | public function __construct( 43 | EngineInterface $templating, 44 | CommandExecuterInterface $commandExecuter, 45 | Application $application, 46 | $environment 47 | ) { 48 | $this->templating = $templating; 49 | $this->commandExecuter = $commandExecuter; 50 | $this->application = $application; 51 | $this->environment = $environment; 52 | } 53 | 54 | public function consoleAction() 55 | { 56 | return new Response( 57 | $this->templating->render('CoreSphereConsoleBundle:Console:console.html.twig', [ 58 | 'working_dir' => getcwd(), 59 | 'environment' => $this->environment, 60 | 'commands' => $this->application->all(), 61 | ]) 62 | ); 63 | } 64 | 65 | public function execAction(Request $request) 66 | { 67 | $commands = $request->request->get('commands'); 68 | $executedCommandsOutput = []; 69 | 70 | foreach ($commands as $command) { 71 | $result = $this->commandExecuter->execute($command); 72 | $executedCommandsOutput[] = $result; 73 | 74 | if (0 !== $result['error_code']) { 75 | break; 76 | } 77 | } 78 | 79 | return new Response( 80 | $this->templating->render( 81 | 'CoreSphereConsoleBundle:Console:result.json.twig', 82 | ['commands' => $executedCommandsOutput] 83 | ) 84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /CoreSphereConsoleBundle.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle; 13 | 14 | use CoreSphere\ConsoleBundle\DependencyInjection\Extension\CoreSphereConsoleExtension; 15 | use Symfony\Component\HttpKernel\Bundle\Bundle; 16 | 17 | class CoreSphereConsoleBundle extends Bundle 18 | { 19 | /** 20 | * {@inheritdoc} 21 | */ 22 | public function getContainerExtension() 23 | { 24 | return new CoreSphereConsoleExtension(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DataCollector/DataCollector.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\DataCollector; 13 | 14 | use Symfony\Component\HttpFoundation\Request; 15 | use Symfony\Component\HttpFoundation\Response; 16 | use Symfony\Component\HttpKernel\DataCollector\DataCollector as DataCollectorBase; 17 | 18 | final class DataCollector extends DataCollectorBase 19 | { 20 | /** 21 | * {@inheritdoc} 22 | */ 23 | public function collect(Request $request, Response $response, \Exception $exception = null) 24 | { 25 | } 26 | 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | public function getName() 31 | { 32 | return 'coresphere_console'; 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function reset() 39 | { 40 | $this->data = []; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DependencyInjection/Extension/CoreSphereConsoleExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\DependencyInjection\Extension; 13 | 14 | use Symfony\Component\DependencyInjection\ContainerBuilder; 15 | use Symfony\Component\DependencyInjection\Extension\Extension; 16 | use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; 17 | use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; 18 | use Symfony\Component\Config\FileLocator; 19 | 20 | final class CoreSphereConsoleExtension extends Extension implements PrependExtensionInterface 21 | { 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function load(array $configs, ContainerBuilder $container) 26 | { 27 | $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../../Resources/config')); 28 | $loader->load('services.yml'); 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function prepend(ContainerBuilder $containerBuilder) 35 | { 36 | $containerBuilder->prependExtensionConfig($this->getAlias(), [ 37 | 'resource' => '.', 38 | 'type' => 'extra', 39 | ]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Executer/CommandExecuter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Executer; 13 | 14 | use CoreSphere\ConsoleBundle\Contract\Executer\CommandExecuterInterface; 15 | use CoreSphere\ConsoleBundle\Output\StringOutput; 16 | use CoreSphere\ConsoleBundle\Formatter\HtmlOutputFormatterDecorator; 17 | use ReflectionClass; 18 | use Symfony\Bundle\FrameworkBundle\Console\Application as FrameworkConsoleApplication; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Input\StringInput; 21 | use Symfony\Component\HttpKernel\KernelInterface; 22 | 23 | final class CommandExecuter implements CommandExecuterInterface 24 | { 25 | /** 26 | * @var KernelInterface 27 | */ 28 | private $baseKernel; 29 | 30 | public function __construct(KernelInterface $baseKernel) 31 | { 32 | $this->baseKernel = $baseKernel; 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function execute($commandString) 39 | { 40 | $input = new StringInput($commandString); 41 | $output = new StringOutput(); 42 | 43 | $application = $this->getApplication($input); 44 | $formatter = $output->getFormatter(); 45 | $kernel = $application->getKernel(); 46 | 47 | chdir($kernel->getRootDir().'/..'); 48 | 49 | $input->setInteractive(false); 50 | $formatter->setDecorated(true); 51 | $output->setFormatter(new HtmlOutputFormatterDecorator($formatter)); 52 | $application->setAutoExit(false); 53 | 54 | $errorCode = $application->run($input, $output); 55 | 56 | return [ 57 | 'input' => $commandString, 58 | 'output' => $output->getBuffer(), 59 | 'environment' => $kernel->getEnvironment(), 60 | 'error_code' => $errorCode, 61 | ]; 62 | } 63 | 64 | /** 65 | * @return FrameworkConsoleApplication 66 | */ 67 | private function getApplication(InputInterface $input) 68 | { 69 | $kernel = $this->getKernel($input); 70 | 71 | return new FrameworkConsoleApplication($kernel); 72 | } 73 | 74 | /** 75 | * @return KernelInterface 76 | */ 77 | private function getKernel(InputInterface $input) 78 | { 79 | $env = $input->getParameterOption(['--env', '-e'], $this->baseKernel->getEnvironment()); 80 | $debug = !$input->hasParameterOption(['--no-debug', '']); 81 | 82 | if ($env === $this->baseKernel->getEnvironment() && $debug === $this->baseKernel->isDebug()) { 83 | return $this->baseKernel; 84 | } 85 | 86 | $kernelClass = new ReflectionClass($this->baseKernel); 87 | 88 | return $kernelClass->newInstance($env, $debug); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Formatter/HtmlOutputFormatterDecorator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Formatter; 13 | 14 | use Symfony\Component\Console\Formatter\OutputFormatterInterface; 15 | use Symfony\Component\Console\Formatter\OutputFormatterStyleInterface; 16 | 17 | final class HtmlOutputFormatterDecorator implements OutputFormatterInterface 18 | { 19 | const CLI_COLORS_PATTERN = '/\033\[(([\d+];?)*)m(.*?)\033\[(([\d+];?)*)m/i'; 20 | 21 | /** 22 | * @var string[] 23 | */ 24 | private $styles = [ 25 | '30' => 'color:rgba(0,0,0,1)', 26 | '31' => 'color:rgba(230,50,50,1)', 27 | '32' => 'color:rgba(50,230,50,1)', 28 | '33' => 'color:rgba(230,230,50,1)', 29 | '34' => 'color:rgba(50,50,230,1)', 30 | '35' => 'color:rgba(230,50,150,1)', 31 | '36' => 'color:rgba(50,230,230,1)', 32 | '37' => 'color:rgba(250,250,250,1)', 33 | '40' => 'color:rgba(0,0,0,1)', 34 | '41' => 'background-color:rgba(230,50,50,1)', 35 | '42' => 'background-color:rgba(50,230,50,1)', 36 | '43' => 'background-color:rgba(230,230,50,1)', 37 | '44' => 'background-color:rgba(50,50,230,1)', 38 | '45' => 'background-color:rgba(230,50,150,1)', 39 | '46' => 'background-color:rgba(50,230,230,1)', 40 | '47' => 'background-color:rgba(250,250,250,1)', 41 | '1' => 'font-weight:bold', 42 | '4' => 'text-decoration:underline', 43 | '8' => 'visibility:hidden', 44 | ]; 45 | 46 | /** 47 | * @var OutputFormatterInterface 48 | */ 49 | private $formatter; 50 | 51 | public function __construct(OutputFormatterInterface $formatter) 52 | { 53 | $this->formatter = $formatter; 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function setDecorated($decorated) 60 | { 61 | return $this->formatter->setDecorated($decorated); 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | public function isDecorated() 68 | { 69 | return $this->formatter->isDecorated(); 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | public function setStyle($name, OutputFormatterStyleInterface $style) 76 | { 77 | return $this->formatter->setStyle($name, $style); 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | */ 83 | public function hasStyle($name) 84 | { 85 | return $this->formatter->hasStyle($name); 86 | } 87 | 88 | /** 89 | * {@inheritdoc} 90 | */ 91 | public function getStyle($name) 92 | { 93 | return $this->formatter->getStyle($name); 94 | } 95 | 96 | /** 97 | * {@inheritdoc} 98 | */ 99 | public function format($message) 100 | { 101 | if (!$this->isDecorated()) { 102 | return $message; 103 | } 104 | $formatted = $this->formatter->format($message); 105 | $escaped = htmlspecialchars($formatted, ENT_QUOTES, 'UTF-8'); 106 | $converted = preg_replace_callback(self::CLI_COLORS_PATTERN, function ($matches) { 107 | return $this->replaceFormat($matches); 108 | }, $escaped); 109 | 110 | return $converted; 111 | } 112 | 113 | /** 114 | * @return string 115 | */ 116 | private function replaceFormat(array $matches) 117 | { 118 | $text = $matches[3]; 119 | $styles = explode(';', $matches[1]); 120 | 121 | $css = array_intersect_key($this->styles, array_flip($styles)); 122 | 123 | return sprintf( 124 | '%s', 125 | implode(';', $css), 126 | $text 127 | ); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 CoreSphere Team, see AUTHORS for details 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | * Neither the name CoreSphere nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Output/StringOutput.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Output; 13 | 14 | use Symfony\Component\Console\Output\Output; 15 | 16 | /** 17 | * Collects console output into a string. 18 | */ 19 | class StringOutput extends Output 20 | { 21 | /** 22 | * @var string 23 | */ 24 | protected $buffer = ''; 25 | 26 | /** 27 | * {@inheritdoc} 28 | */ 29 | public function doWrite($message, $newline) 30 | { 31 | $this->buffer .= $message.(true === $newline ? PHP_EOL : ''); 32 | } 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function getBuffer() 38 | { 39 | return $this->buffer; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ConsoleBundle 2 | ============= 3 | 4 | [![Build Status](https://img.shields.io/travis/CoreSphere/ConsoleBundle.svg?style=flat-square)](https://travis-ci.org/CoreSphere/ConsoleBundle) 5 | [![Quality Score](https://img.shields.io/scrutinizer/g/CoreSphere/ConsoleBundle.svg?style=flat-square)](https://scrutinizer-ci.com/g/CoreSphere/ConsoleBundle) 6 | [![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/CoreSphere/ConsoleBundle.svg?style=flat-square)](https://scrutinizer-ci.com/g/CoreSphere/ConsoleBundle) 7 | 8 | 9 | This bundle allows you accessing the Symfony2 console via your browser. 10 | 11 | Features 12 | -------- 13 | 14 | * Colored output 15 | * Autocompletion for command names 16 | * Local command history (localStorage) 17 | * ```cache:clear``` works 18 | 19 | Installation 20 | ------------ 21 | 22 | 0. Make sure you have php 5.5 or newer installed. Make sure your composer file does not override the required php version of your project with in older one via the `config.plattform.php` setting. 23 | 24 | 1. Install the latest version via composer: 25 | 26 | ```sh 27 | composer require coresphere/console-bundle 28 | ``` 29 | 30 | 2. Register the bundle in you AppKernel in the development section 31 | 32 | ```php 33 | // app/AppKernel.php 34 | public function registerBundles() 35 | { 36 | $bundles = [ 37 | // other bundles here... 38 | ]; 39 | 40 | if (in_array($this->getEnvironment(), ['dev', 'test'])) { 41 | // ... 42 | $bundles[] = new CoreSphere\ConsoleBundle\CoreSphereConsoleBundle(); 43 | } 44 | 45 | return $bundles; 46 | } 47 | ``` 48 | 49 | 3. Add the bundle's route to your app/config/routing_dev.yml 50 | 51 | ```yaml 52 | # app/config/routing_dev.yml 53 | 54 | # ... 55 | _main: 56 | resource: routing.yml 57 | 58 | coresphere_console: 59 | resource: . 60 | type: extra 61 | ``` 62 | 63 | 64 | 4. run the assets:install command to install the css and js files 65 | 66 | ```sh 67 | ./app/console assets:install web 68 | ``` 69 | 70 | Tips 71 | ---- 72 | 73 | * Type ```.clear``` to clear the console window 74 | 75 | Preview 76 | ------- 77 | 78 | Screenshot 79 | 80 | Dependencies 81 | ------------ 82 | 83 | * jQuery 84 | * Twig 85 | 86 | Compatibility 87 | ------------- 88 | 89 | Tested with: 90 | 91 | * Chrome 92 | * Firefox 4 93 | * Opera 11 94 | * Safari 5 95 | -------------------------------------------------------------------------------- /Resources/config/routing.yml: -------------------------------------------------------------------------------- 1 | console: 2 | path: /_console 3 | defaults: { _controller: coresphere_console.controller:consoleAction } 4 | methods: [GET] 5 | 6 | console_exec: 7 | path: /_console/commands.{_format} 8 | defaults: { _controller: coresphere_console.controller:execAction, _format: json } 9 | methods: [POST] 10 | requirements: 11 | _format: json 12 | -------------------------------------------------------------------------------- /Resources/config/services.yml: -------------------------------------------------------------------------------- 1 | services: 2 | coresphere_console.controller: 3 | class: CoreSphere\ConsoleBundle\Controller\ConsoleController 4 | arguments: 5 | - "@templating" 6 | - "@coresphere_console.executer" 7 | - "@coresphere_console.application" 8 | - "%kernel.environment%" 9 | 10 | coresphere_console.executer: 11 | class: CoreSphere\ConsoleBundle\Executer\CommandExecuter 12 | arguments: 13 | - "@kernel" 14 | 15 | coresphere_console.routing: 16 | class: CoreSphere\ConsoleBundle\Routing\Loader 17 | arguments: 18 | - "@routing.loader.yml" 19 | tags: 20 | - { name: routing.loader } 21 | 22 | coresphere_console.toolbar: 23 | class: CoreSphere\ConsoleBundle\DataCollector\DataCollector 24 | tags: 25 | - { name: data_collector, template: "CoreSphereConsoleBundle:Toolbar:toolbar", id: "coresphere_console" } 26 | 27 | # console application 28 | coresphere_console.application.factory: 29 | class: CoreSphere\ConsoleBundle\Console\ApplicationFactory 30 | 31 | coresphere_console.application: 32 | class: Symfony\Bundle\FrameworkBundle\Console\Application 33 | factory: ["@coresphere_console.application.factory", create] 34 | arguments: 35 | - "@kernel" 36 | -------------------------------------------------------------------------------- /Resources/public/css/base.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | padding: 1em; 4 | } 5 | -------------------------------------------------------------------------------- /Resources/public/css/console.css: -------------------------------------------------------------------------------- 1 | .console { 2 | position: relative; 3 | padding: 3px; 4 | background-color: rgba(50,50,50,1); 5 | color: rgba(240,240,240,1); 6 | font-family: Consolas, "Liberation Mono", Courier, monospace; 7 | font-size: 0.9em; 8 | border: 5px solid rgba(210,210,210,1); 9 | margin: 0 0 0 0; 10 | } 11 | 12 | .console::after { 13 | clear: both; 14 | content: ''; 15 | } 16 | 17 | .console_info_bar { 18 | margin: 0; 19 | padding: 0.2em 15px 0.2em 0.2em; 20 | background-color: rgba(5,5,5,1); 21 | } 22 | 23 | .console_log_container { 24 | height: 25em; 25 | overflow: auto; 26 | overflow-y: scroll; 27 | } 28 | 29 | .console_log { 30 | padding: 0 0.8em; 31 | } 32 | 33 | .console_error { 34 | color: rgba(255, 160, 160, 1); 35 | } 36 | 37 | .console_prompt { 38 | clear: both; 39 | background-color: rgba(255,255,255, 1); 40 | color: rgba(30, 30, 30,1); 41 | position: relative; 42 | } 43 | 44 | .console_prompt::before { 45 | position: absolute; 46 | left:0; 47 | right: 0; 48 | top: 0; 49 | bottom: 0; 50 | content: '$ '; 51 | line-height: 1.5em; 52 | padding: 0.5em; 53 | } 54 | 55 | .console_input { 56 | background-color: transparent; 57 | border: none; 58 | font-family: inherit; 59 | color: inherit; 60 | outline: none; 61 | 62 | line-height: 1.5em; 63 | min-height: 1.5em; 64 | padding: 0.5em 0.5em 0.5em 1.5em; 65 | position: relative; 66 | z-index: 10; 67 | } 68 | 69 | [data-before]::before { 70 | content: attr(data-before); 71 | color: inherit; 72 | background: inherit; 73 | text-decoration: underline; 74 | opacity: 0.1; 75 | } 76 | 77 | .console_input_background { 78 | line-height: 1.5em; 79 | min-height: 1.5em; 80 | padding: 0.5em 0.5em 0.5em 1.5em; 81 | background-color: transparent; 82 | border: none; 83 | font-family: inherit; 84 | color: inherit; 85 | outline: none; 86 | position: absolute; 87 | top: 0; 88 | left: 0; 89 | right: 0; 90 | bottom: 0; 91 | color: inherit; 92 | opacity: 0.7; 93 | z-index: 0; 94 | } 95 | 96 | .console_input * { 97 | background-color: transparent !important; 98 | color: inherit !important; 99 | } 100 | 101 | .console_log_input { 102 | margin: 0.5em 0 0 0; 103 | padding: 0.4em 0.5em; 104 | background-color: rgba(0,0,0,0.4); 105 | border-color: rgba(240,240,240,0.3); 106 | border-width: 1px 1px 1px 1px; 107 | border-style: solid; 108 | line-height: 1.3; 109 | 110 | cursor: pointer; 111 | border-radius: 0.3em 0.3em 0 0; 112 | } 113 | 114 | .console_log_input:hover { 115 | background-color: rgba(0,0,0,0.7); 116 | } 117 | 118 | .console_log_input:before { 119 | content: "> "; 120 | } 121 | 122 | .console_log_output { 123 | white-space: pre-wrap; 124 | margin: 0; 125 | margin: 0 0 0.5em 0; 126 | padding: 1em 0.5em 2em 2em; 127 | background-color: rgba(60,60,60,0.4); 128 | border-color: rgba(240,240,240,0.3); 129 | border-width: 0 1px 1px 1px; 130 | border-style: solid; 131 | line-height: 1; 132 | border-radius: 0 0 0.3em 0.3em; 133 | } 134 | 135 | .console_command { 136 | background-color: rgba(1,1,1,0.3); 137 | padding: 3px; 138 | border: 1px solid transparent; 139 | cursor: pointer; 140 | } 141 | 142 | .console_command:hover { 143 | border: 1px solid rgba(140,140,140,0.6); 144 | } 145 | 146 | .console_suggestion_head { 147 | font-weight: bold; 148 | margin: 0; 149 | padding: 0.5em; 150 | color: rgba(40,40,40,1); 151 | background-color: rgba(255,255,255,1); 152 | font-size: 1em; 153 | font-family: sans-serif; 154 | border-bottom: 2px solid #777; 155 | } 156 | 157 | .match { 158 | font-weight: bold; 159 | background-color: rgba(261, 223, 15, 0.8); 160 | border-radius: 0.3em; 161 | padding: 0.2em; 162 | box-shadow: 1px 1px 3px rgba(40,40,40,0.4); 163 | } 164 | 165 | .console_suggestions { 166 | position: absolute; 167 | bottom: 2.7em; 168 | left: 0; 169 | right: 0; 170 | z-index: 100; 171 | overflow: hidden; 172 | border: 3px solid rgba(50,50,50,1); 173 | } 174 | 175 | .console_suggestions ul { 176 | margin: 0; padding: 0; 177 | 178 | background-color: rgba(250,250,250, 1); 179 | color: rgba(5,5,5,1); 180 | max-height: 10em; 181 | overflow-y: auto; 182 | } 183 | 184 | .console_suggestions li { 185 | list-style: none; 186 | line-height: 1.5; 187 | padding: 0.3em 3em 0.3em 0.5em; 188 | cursor: pointer; 189 | } 190 | 191 | .console_suggestions li:hover { 192 | background-color: rgba(80,80,80,0.1); 193 | } 194 | 195 | .console_suggestions .active { 196 | background-color: rgba(50,50,50,0.1); 197 | font-weight: bold; 198 | } 199 | 200 | .console_env_info { 201 | color: rgba(200,200,200,0.7); 202 | float: right; 203 | } 204 | -------------------------------------------------------------------------------- /Resources/public/js/console.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the CoreSphereConsoleBundle. 3 | * 4 | * (c) Laszlo Korte 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | window.CoreSphereConsole = (function (window) { 11 | "use strict"; 12 | 13 | if (typeof window.jQuery === "undefined") { 14 | window.alert('jQuery has not been loaded'); 15 | return; 16 | } 17 | 18 | var $ = window.jQuery, 19 | 20 | default_options = { 21 | 'filters' : { 22 | 'clear' : function () { 23 | this.log.html(''); 24 | 25 | return ''; 26 | } 27 | }, 28 | 29 | 'active_suggestion_class' : 'active', 30 | 31 | 'command_splitter' : '|' 32 | }, 33 | 34 | helpers = { 35 | 36 | htmlEscape : function (input) { 37 | return input 38 | .replace(/&/g, '&') 39 | .replace(//g, '>'); 41 | }, 42 | 43 | isInteger : function(n) { 44 | return n===+n && n===(n|0); 45 | }, 46 | 47 | regexpEscape : (function () { 48 | var regexp = new RegExp( 49 | '(\\' + [ 50 | '.', '*', '+', '?', '|', 51 | '^', '$', 52 | '(', ')', '[', ']', '{', '}', '\\' 53 | ].join('|\\') + ')', 54 | 'g' 55 | ); 56 | 57 | return function (input) { 58 | return input.replace(regexp, '\\$1'); 59 | }; 60 | }()), 61 | 62 | focusInput : function (el) { 63 | var range, sel, textRange; 64 | el.focus(); 65 | if (typeof window.getSelection !== "undefined" 66 | && typeof window.document.createRange !== "undefined") { 67 | range = window.document.createRange(); 68 | sel = window.getSelection(); 69 | range.selectNodeContents(el); 70 | range.collapse(false); 71 | sel.removeAllRanges(); 72 | sel.addRange(range); 73 | } else if (typeof window.document.body.createTextRange !== "undefined") { 74 | textRange = window.document.body.createTextRange(); 75 | textRange.moveToElementText(el); 76 | textRange.collapse(false); 77 | textRange.select(); 78 | } 79 | } 80 | 81 | }, 82 | 83 | keys = { 84 | 'tab' : 9, 85 | 'enter' : 13, 86 | 'escape' : 27, 87 | 'left' : 37, 88 | 'up' : 38, 89 | 'right' : 39, 90 | 'down': 40 91 | }, 92 | 93 | ConsoleBackend = function() { 94 | 95 | }, 96 | 97 | Console = function (base_element, options) { 98 | this.options = $.extend(default_options, options); 99 | 100 | this.base = base_element; 101 | this.input = base_element.find('.console_input'); 102 | this.input_background = base_element.find('.console_input_background'); 103 | this.log_container = base_element.find('.console_log_container'); 104 | this.log = base_element.find('.console_log'); 105 | this.suggestion_box = base_element.find('.console_suggestions'); 106 | this.active_suggestion = null; 107 | 108 | this.initHistory(); 109 | this.bindEvents(); 110 | this.unlock(); 111 | this.focus(); 112 | this.welcome(); 113 | }; 114 | 115 | ConsoleBackend.prototype.knownCommands = []; 116 | ConsoleBackend.prototype.history = []; 117 | ConsoleBackend.prototype.historyPosition = 0; 118 | ConsoleBackend.prototype.currentInput = []; 119 | ConsoleBackend.prototype.currentSuggestions = []; 120 | ConsoleBackend.prototype.focusedSuggestion = 0; 121 | 122 | ConsoleBackend.prototype.init = function() { 123 | var that = this; 124 | 125 | that.knownCommands = []; 126 | that.history = []; 127 | that.historyPosition = 0; 128 | that.currentInput = []; 129 | that.currentSuggestions = []; 130 | that.focusedSuggestion = 0; 131 | }; 132 | 133 | ConsoleBackend.prototype.focusSuggestionAt = function(idx) { 134 | var that = this; 135 | 136 | if(!isInteger(idx)) { 137 | throw "Index to be focused must be an integer."; 138 | } 139 | if(idx<0 || idx+1 > that.currentSuggestions.length) { 140 | throw "Suggestion focus is out of range."; 141 | } 142 | 143 | that.focusedSuggestion = idx; 144 | }; 145 | 146 | ConsoleBackend.prototype.focusNextSuggestion = function() { 147 | var that = this 148 | , mod = that.currentSuggestions.length; 149 | 150 | that.focusedSuggestion = (that.focusedSuggestion+1)%mod; 151 | }; 152 | 153 | ConsoleBackend.prototype.focusPrevSuggestion = function() { 154 | var that = this 155 | , mod = that.currentSuggestions.length; 156 | 157 | that.focusedSuggestion = (that.focusedSuggestion+mod-1)%mod; 158 | }; 159 | 160 | ConsoleBackend.prototype.pushHistory = function(value) { 161 | var that = this; 162 | 163 | that.history.push(value); 164 | }; 165 | 166 | ConsoleBackend.prototype.clearHistory = function() { 167 | var that = this; 168 | 169 | that.history.length = 0; 170 | }; 171 | 172 | ConsoleBackend.prototype.setRawInput = function() { 173 | var that = this; 174 | }; 175 | 176 | ConsoleBackend.prototype.setInputList = function() { 177 | var that = this; 178 | }; 179 | 180 | Console.prototype.focus = function () { 181 | helpers.focusInput(this.input[0]); 182 | }; 183 | 184 | Console.prototype.initHistory = function () { 185 | if (!window.localStorage.coresphere_console_history) { 186 | window.localStorage.coresphere_console_history = '[]'; 187 | } 188 | 189 | this.history = JSON.parse(window.localStorage.coresphere_console_history).slice(-20); 190 | this.history_position = this.history.length; 191 | }; 192 | 193 | Console.prototype.pushHistory = function (val) { 194 | if (val.length && this.history[this.history.length - 1] !== val) { 195 | this.history.push(val); 196 | window.localStorage.coresphere_console_history = JSON.stringify(this.history); 197 | } 198 | 199 | this.history_position = this.history.length; 200 | }; 201 | 202 | Console.prototype.clearHistory = function () { 203 | window.localStorage.removeKey('coresphere_console_history'); 204 | }; 205 | 206 | Console.prototype.bindEvents = function () { 207 | var enable_suggestions = true, 208 | this_console = this; 209 | 210 | this.base 211 | 212 | .on('click.coresphere_console', '.console_command', function (e) { 213 | enable_suggestions = true; 214 | this_console.setValue($(this).text()).trigger('keyup'); 215 | this_console.focus(); 216 | }) 217 | 218 | .on('click.coresphere_console', '.console_suggestions li', function (e) { 219 | e.stopPropagation(); 220 | var $this = $(this); 221 | this_console.setCurrentCommand($this.text()); 222 | this_console.clearSuggestions(); 223 | this_console.focus(); 224 | }) 225 | 226 | .on('click.coresphere_console', '.console_log_input', function (e) { 227 | $(this).next('.console_log_output').stop().slideToggle(100); 228 | }) 229 | 230 | .on('keydown.coresphere_console', '.console_input', function (e) { 231 | var val, 232 | command, 233 | filter, 234 | current_suggestions, 235 | active_suggestion, 236 | next, 237 | scrollToEl; 238 | 239 | if (this_console.isLocked()) { 240 | return; 241 | } 242 | 243 | val = this_console.getValue(); 244 | 245 | if (e.which === keys.tab) { 246 | 247 | e.preventDefault(); 248 | 249 | if (this_console.active_suggestion) { 250 | this_console.setCurrentCommand(this_console.active_suggestion); 251 | } 252 | 253 | this_console.focus(); 254 | 255 | } else if (e.which === keys.enter && !e.shiftKey) { 256 | 257 | if (this_console.active_suggestion) { 258 | if (val !== this_console.active_suggestion) { 259 | this_console.setCurrentCommand(val = this_console.active_suggestion); 260 | this_console.clearSuggestions(); 261 | this_console.focus(); 262 | 263 | e.preventDefault(); 264 | return; 265 | } 266 | } 267 | 268 | command = val; 269 | 270 | this_console.setValue(''); 271 | 272 | this_console.pushHistory(val); 273 | 274 | if (command.substr(0, 1) === '.') { 275 | filter = command.substr(1); 276 | 277 | if (this_console.options.filters[filter]) { 278 | command = this_console.options.filters[filter].call(this_console); 279 | } 280 | } 281 | 282 | if (command.length) { 283 | this_console.lock(); 284 | 285 | this_console.log.find('li:not(.console_loading) .console_log_output').last().hide(); 286 | 287 | this_console.log.append(this_console.options.templates.loading 288 | .replace('%command%', helpers.htmlEscape(val)) 289 | .replace('%message%', this_console.options.lang.loading) 290 | ); 291 | 292 | this_console.sendCommands(command.split(this_console.options.command_splitter)); 293 | } else { 294 | this_console.focus(); 295 | } 296 | 297 | e.preventDefault(); 298 | 299 | } else if (e.which === keys.up || e.which === keys.down) { 300 | e.preventDefault(); 301 | 302 | current_suggestions = this_console.suggestion_box.find('li'); 303 | active_suggestion = current_suggestions.filter('.' + this_console.options.active_suggestion_class); 304 | 305 | if (e.which === keys.up) { 306 | if (current_suggestions.size()) { 307 | next = active_suggestion.size() ? active_suggestion.removeClass(this_console.options.active_suggestion_class).prev() : current_suggestions.last(); 308 | next = next.size() ? next : current_suggestions.last(); 309 | this_console.setActiveSuggestion(next.addClass(this_console.options.active_suggestion_class).text()); 310 | scrollToEl = next[0]; 311 | } else { 312 | this_console.history_position -= 1; 313 | if (this_console.history_position < 0) { 314 | this_console.history_position = 0; 315 | } else { 316 | this_console.setValue(this_console.history[this_console.history_position]); 317 | } 318 | } 319 | } else { 320 | // DOWN 321 | 322 | if (current_suggestions.size()) { 323 | next = active_suggestion.size() ? active_suggestion.removeClass(this_console.options.active_suggestion_class).next() : current_suggestions.first(); 324 | next = next.size() ? next : current_suggestions.first(); 325 | 326 | this_console.setActiveSuggestion(next.addClass(this_console.options.active_suggestion_class).text()); 327 | scrollToEl = next[0]; 328 | } else { 329 | this_console.history_position += 1; 330 | if (this_console.history_position >= this_console.history.length) { 331 | this_console.history_position = this_console.history.length; 332 | this_console.setValue(''); 333 | } else { 334 | this_console.setValue(this_console.history[this_console.history_position]); 335 | } 336 | } 337 | 338 | } 339 | 340 | if(scrollToEl) { 341 | var rects = scrollToEl.getClientRects()[0]; 342 | if(document.elementFromPoint(Math.ceil(rects.left),Math.ceil(rects.top)) !== scrollToEl 343 | || document.elementFromPoint(Math.floor(rects.right),Math.floor(rects.bottom)) !== scrollToEl) { 344 | scrollToEl.scrollIntoView(false); 345 | } 346 | } 347 | this_console.focus(); 348 | enable_suggestions = false; 349 | 350 | 351 | } else if (e.which === keys.escape) { 352 | 353 | if (this_console.suggestion_box.find('li').size()) { 354 | this_console.suggestion_box.text(''); 355 | } else { 356 | this_console.popValue(); 357 | } 358 | enable_suggestions = false; 359 | this_console.focus(); 360 | } 361 | 362 | if ((e.which < keys.left || e.which > keys.down) && e.which !== keys.escape) { 363 | enable_suggestions = true; 364 | } 365 | }) 366 | 367 | .on('keyup.coresphere_console', '.console_input', function (e) { 368 | 369 | if (enable_suggestions) { 370 | var val = this_console.getValue(), 371 | best_suggestions = [], 372 | other_suggestions = [], 373 | suggestions, 374 | any = 0, 375 | htmlCode, 376 | index, 377 | j, 378 | tpl, 379 | suggestion, 380 | commands = val.split(this_console.options.command_splitter), 381 | currentCommand = commands[commands.length-1]; 382 | 383 | 384 | if (currentCommand.length) { 385 | for (index = 0, j = this_console.options.commands.length; index < j; index++) { 386 | if (new RegExp('^' + helpers.regexpEscape(currentCommand)).test(this_console.options.commands[index])) { 387 | best_suggestions.push(this_console.options.commands[index]); 388 | any += 1; 389 | } else if (new RegExp(helpers.regexpEscape(currentCommand)).test(this_console.options.commands[index])) { 390 | other_suggestions.push(this_console.options.commands[index]); 391 | any += 1; 392 | } 393 | if (this_console.options.commands[index] === currentCommand) { 394 | any -= 1; 395 | } 396 | } 397 | 398 | suggestions = best_suggestions.concat(other_suggestions); 399 | } 400 | 401 | if (any) { 402 | if (!this_console.active_suggestion || suggestions.indexOf(this_console.active_suggestion) < 0) { 403 | this_console.setActiveSuggestion(suggestions[0]); 404 | } else { 405 | this_console.setActiveSuggestion(this_console.active_suggestion); 406 | } 407 | 408 | enable_suggestions = false; 409 | htmlCode = ''; 410 | 411 | for (index = 0, j = suggestions.length; index < j; index++) { 412 | suggestion = suggestions[index].replace(currentCommand, this_console.options.templates.highlight.replace('%word%', currentCommand)); 413 | if(suggestions[index] === this_console.active_suggestion) { 414 | tpl = this_console.options.templates.suggestion_item_active; 415 | tpl = tpl.replace('%state%', this_console.options.active_suggestion_class); 416 | } else { 417 | tpl = this_console.options.templates.suggestion_item; 418 | } 419 | htmlCode += tpl.replace("%suggestion%", suggestion); 420 | } 421 | 422 | htmlCode = this_console.options.templates.suggestion_list 423 | .replace('%head%', this_console.options.lang.suggestion_head) 424 | .replace('%suggestions%', htmlCode) 425 | ; 426 | 427 | this_console.suggestion_box.html(htmlCode); 428 | } else { 429 | this_console.setActiveSuggestion(null); 430 | 431 | this_console.suggestion_box.text(''); 432 | } 433 | } 434 | 435 | }) 436 | 437 | .on('focus.coresphere_console', '.console_input', function (e) { 438 | this_console.suggestion_box.show(); 439 | }); 440 | 441 | $(window.document) 442 | 443 | .on('mousedown.coresphere_console', function (e) { 444 | var $target = $(e.target); 445 | this_console.focus(); 446 | if ($target.is('.console_input') 447 | || $target.closest('.console_suggestions').size() 448 | ) { 449 | return; 450 | } 451 | this_console.suggestion_box.hide(); 452 | }) 453 | 454 | .on('focus.coresphere_console', function (e) { 455 | this_console.focus(); 456 | }); 457 | }; 458 | 459 | Console.prototype.unbindEvents = function () { 460 | this.base.off('.coresphere_console'); 461 | $(window.document).off('.coresphere_console'); 462 | }; 463 | 464 | 465 | Console.prototype.lock = function () { 466 | this.locked = true; 467 | }; 468 | 469 | Console.prototype.unlock = function () { 470 | this.locked = false; 471 | }; 472 | 473 | Console.prototype.isLocked = function () { 474 | return this.locked === true; 475 | }; 476 | 477 | Console.prototype.getValue = function () { 478 | return this.input.text(); 479 | }; 480 | 481 | Console.prototype.setValue = function (val) { 482 | this.setActiveSuggestion(null); 483 | return this.input.text(val); 484 | }; 485 | 486 | Console.prototype.popValue = function () { 487 | var commands = this.getCommands(); 488 | commands.pop(); 489 | 490 | return this.setValue( commands.join(this.options.command_splitter) ); 491 | }; 492 | 493 | Console.prototype.setCurrentCommand = function (val) { 494 | var commands = this.getCommands(), 495 | i = this.getCurrentCommand(); 496 | 497 | commands[i] = val; 498 | this.setActiveSuggestion(null); 499 | return this.input.text(commands.join(this.options.command_splitter)); 500 | }; 501 | 502 | Console.prototype.getCommands = function() { 503 | var oldValue = this.getValue(), 504 | commands = oldValue.split(this.options.command_splitter); 505 | 506 | return commands; 507 | }; 508 | 509 | Console.prototype.getCurrentCommand = function() { 510 | return this.getCommands().length - 1; 511 | }; 512 | 513 | Console.prototype.getActiveSuggestion = function () { 514 | return this.active_suggestion; 515 | }; 516 | 517 | Console.prototype.setActiveSuggestion = function(suggestion) { 518 | this.active_suggestion = suggestion; 519 | 520 | if(this.getCommands().length < 2) { 521 | this.input_background.text(this.active_suggestion || ''); 522 | 523 | if(suggestion) { 524 | this.input.attr('data-before', suggestion.substr(0, suggestion.indexOf(this.input.text()))); 525 | } else { 526 | this.input.attr('data-before', ''); 527 | } 528 | } else { 529 | this.input.attr('data-before', ''); 530 | this.input_background.text(''); 531 | } 532 | }; 533 | 534 | Console.prototype.clearSuggestions = function () { 535 | this.setActiveSuggestion(null); 536 | return this.suggestion_box.text(''); 537 | }; 538 | 539 | Console.prototype.welcome = function () { 540 | this.log.append('
  • ' + this.options.lang.welcome_message + '
  • '); 541 | }; 542 | 543 | Console.prototype.commandComplete = function (response) { 544 | var answer, htmlCode, cmd, 545 | results = response.results, 546 | tplCmd = this.options.templates.command, 547 | tplEnv = this.options.templates.environment; 548 | 549 | for (var i = 0, len = results.length; i < len; i++) { 550 | cmd = results[i]; 551 | answer = cmd.output.replace(/^\s+|\s+$/g, ""); 552 | htmlCode = tplCmd 553 | .replace("%command%", helpers.htmlEscape(cmd.command)) 554 | .replace("%status%", 0 == cmd.error_code ? 'ok' : 'error') 555 | .replace("%environment%", cmd.environment !== this.options.environment 556 | ? tplEnv.replace("%label%", this.options.lang.environment).replace("%environment%", cmd.environment) 557 | : '' 558 | ) 559 | .replace("%output%", answer.length ? answer : this.options.lang.empty_response) 560 | ; 561 | 562 | this.log.append(htmlCode); 563 | } 564 | }; 565 | 566 | Console.prototype.commandError = function (xhr, msg, error) { 567 | this.log.append( 568 | this.options.templates.error 569 | .replace("%message%", msg) 570 | .replace("%error%", error) 571 | .replace("%command%", '') 572 | ); 573 | }; 574 | 575 | Console.prototype.commandAfter = function () { 576 | this.log.find('.console_loading').remove(); 577 | this.unlock(); 578 | this.log_container.scrollTop(this.log.outerHeight()); 579 | this.focus(); 580 | }; 581 | 582 | Console.prototype.sendCommands = function (commands) { 583 | 584 | var this_console = this; 585 | 586 | return $.ajax({ 587 | url: this.options.post_path, 588 | type: "POST", 589 | data: ({"commands" : commands}), 590 | dataType: "json" 591 | }) 592 | 593 | .done(this.commandComplete.bind(this)) 594 | 595 | .fail(this.commandError.bind(this)) 596 | 597 | .always(this.commandAfter.bind(this)); 598 | }; 599 | 600 | return Console; 601 | 602 | }(window)); 603 | -------------------------------------------------------------------------------- /Resources/public/js/jquery-1.8.3.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v1.8.3 jquery.com | jquery.org/license */ 2 | (function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
    a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
    t
    ",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
    ",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
    ",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

    ",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
    ","
    "]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
    ").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); 3 | -------------------------------------------------------------------------------- /Resources/translations/messages.bg.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Конзола" 4 | working_directory: 'Работна папка' 5 | environment: 'Среда (dev,test,prod)' 6 | welcome_message: 'Напиши %command% за да видиш всички команди.' 7 | loading: 'Зареждам...' 8 | suggestion_head: 'Може би имахте предвид:' 9 | empty_response: 'Свърших! :)' 10 | -------------------------------------------------------------------------------- /Resources/translations/messages.de.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Konsole" 4 | working_directory: 'Arbeitsverzeichnis' 5 | environment: 'Umgebung' 6 | welcome_message: 'Schreibe %command% um eine Liste mit allen verfügbaren Befehlen zu bekommen.' 7 | loading: 'Lade...' 8 | suggestion_head: 'Meintest du:' 9 | empty_response: 'Fertig!' -------------------------------------------------------------------------------- /Resources/translations/messages.en.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Console" 4 | working_directory: 'Working directory' 5 | environment: 'Environment' 6 | welcome_message: 'Type %command% to get a list of all commands.' 7 | loading: 'Loading...' 8 | suggestion_head: 'Did you mean:' 9 | empty_response: 'Complete!' -------------------------------------------------------------------------------- /Resources/translations/messages.es.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Consola" 4 | working_directory: 'Directorio de trabajo' 5 | environment: 'Entorno' 6 | welcome_message: 'Escriba %command% para obtener una lista de los comandos.' 7 | loading: 'Cargando...' 8 | suggestion_head: 'Quieres decir:' 9 | empty_response: 'Terminado!' 10 | -------------------------------------------------------------------------------- /Resources/translations/messages.fr.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Console" 4 | working_directory: 'Répertoire de travail' 5 | environment: 'Environnement' 6 | welcome_message: 'Tapez %command% pour obtenir la liste de toutes les commandes.' 7 | loading: 'Chargement en cours...' 8 | suggestion_head: 'Essayez plutôt :' 9 | empty_response: 'Commande exécutée ! (Mais réponse vide)' 10 | -------------------------------------------------------------------------------- /Resources/translations/messages.it.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Console" 4 | working_directory: 'Cartella corrente' 5 | environment: 'Ambiente' 6 | welcome_message: 'Digitare %command% per ottenere una lista di tutti i comandi' 7 | loading: 'Caricamento...' 8 | suggestion_head: 'Intendevi:' 9 | empty_response: 'Completato!' 10 | -------------------------------------------------------------------------------- /Resources/translations/messages.nl.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Console" 4 | working_directory: 'Werkdirectory' 5 | environment: 'Omgeving' 6 | welcome_message: 'Typ %command% om een lijst te krijgen van alle commandos.' 7 | loading: 'Laden...' 8 | suggestion_head: 'Bedoelde u:' 9 | empty_response: 'Voltooi!' -------------------------------------------------------------------------------- /Resources/translations/messages.pl.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Konsola" 4 | working_directory: 'Katalog roboczy' 5 | environment: 'Środowisko' 6 | welcome_message: 'Wpisz %command% aby otrzymać listę wszystkich komend.' 7 | loading: 'Ładowanie...' 8 | suggestion_head: 'Czy miałeś na myśli:' 9 | empty_response: 'Ukończono!' 10 | -------------------------------------------------------------------------------- /Resources/translations/messages.ru.yml: -------------------------------------------------------------------------------- 1 | coresphere_console: 2 | headline: 3 | index: "Консоль" 4 | working_directory: 'Рабочая директория' 5 | environment: 'Окружение' 6 | welcome_message: 'Наберите %command% для списка всех доступных комманд.' 7 | loading: 'Загрузка...' 8 | suggestion_head: 'Может вы имели ввиду:' 9 | empty_response: 'Завершено!' -------------------------------------------------------------------------------- /Resources/views/Console/console.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'CoreSphereConsoleBundle::base.html.twig' %} 2 | 3 | {% block title %}{{ 'coresphere_console.headline.index'|trans }}{% endblock %} 4 | 5 | {% block stylesheets %} 6 | {{ parent() }} 7 | 8 | {% endblock %} 9 | 10 | {% block body %} 11 | {% include 'CoreSphereConsoleBundle:Console:terminal.html.twig' %} 12 | {% include 'CoreSphereConsoleBundle:Console:htmlTemplates.html.twig' %} 13 | {% endblock %} 14 | 15 | {% block javascripts %} 16 | {{ parent() }} 17 | 18 | 47 | {% endblock %} 48 | -------------------------------------------------------------------------------- /Resources/views/Console/htmlTemplates.html.twig: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 18 | 19 | 25 | 26 | 30 | 31 | 34 | 35 | 38 | 39 | 42 | -------------------------------------------------------------------------------- /Resources/views/Console/result.json.twig: -------------------------------------------------------------------------------- 1 | {% autoescape false %} 2 | {"results" : [ 3 | {% for command in commands %} 4 | { 5 | "command" : {{ command.input|escape|json_encode }}, 6 | "output" : {{ command.output|json_encode }}, 7 | "environment": {{ command.environment|escape|json_encode }}, 8 | "error_code": {{ command.error_code|escape|json_encode }} 9 | }{{ loop.last ? '' : ',' }} 10 | {% endfor %} 11 | ] } 12 | {% endautoescape %} 13 | -------------------------------------------------------------------------------- /Resources/views/Console/terminal.html.twig: -------------------------------------------------------------------------------- 1 |

    {{ 'coresphere_console.headline.index'|trans }}

    2 |
    3 |
    4 | {{ 'coresphere_console.working_directory'|trans }}: {{ working_dir }} 5 | {{ 'coresphere_console.environment'|trans }}: {{ environment }} 6 |
    7 |
    8 |
      9 | 10 |
    11 |
    12 |
    13 |
    14 |
    15 |
    16 |
    17 |
    18 | -------------------------------------------------------------------------------- /Resources/views/Toolbar/toolbar.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'WebProfilerBundle:Profiler:layout.html.twig' %} 2 | 3 | {% block toolbar %} 4 | {% set icon %} 5 | 6 | Console 10 | 11 | {% endset %} 12 | {% set text %}Console{% endset %} 13 | 14 | {% include 'WebProfilerBundle:Profiler:toolbar_item.html.twig' with { 'link': false } %} 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /Resources/views/base.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title 'CoreSphere Console' %} 6 | {% block stylesheets %} 7 | 8 | {% endblock %} 9 | 10 | 11 | 12 | {% block body '' %} 13 | {% block javascripts %} 14 | {# Load jQuery from Google CDN with a local fallback when not laded yet #} 15 | 18 | 21 | {% endblock %} 22 | 23 | 24 | -------------------------------------------------------------------------------- /Routing/Loader.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Routing; 13 | 14 | use Symfony\Component\Config\Loader\LoaderInterface; 15 | use Symfony\Component\Config\Loader\LoaderResolverInterface; 16 | use Symfony\Component\Routing\Loader\YamlFileLoader; 17 | use Symfony\Component\Routing\RouteCollection; 18 | 19 | final class Loader implements LoaderInterface 20 | { 21 | /** 22 | * @var YamlFileLoader 23 | */ 24 | private $yamlFileLoader; 25 | 26 | public function __construct(YamlFileLoader $yamlFileLoader) 27 | { 28 | $this->yamlFileLoader = $yamlFileLoader; 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function load($resource, $type = null) 35 | { 36 | $collection = new RouteCollection(); 37 | $collection->addCollection( 38 | $this->yamlFileLoader->import(__DIR__.'/../Resources/config/routing.yml') 39 | ); 40 | 41 | return $collection; 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function supports($resource, $type = null) 48 | { 49 | return 'extra' === $type; 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function getResolver() 56 | { 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | */ 62 | public function setResolver(LoaderResolverInterface $resolver) 63 | { 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Tests/Console/ApplicationFactoryTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\Console; 13 | 14 | use CoreSphere\ConsoleBundle\Console\ApplicationFactory; 15 | use CoreSphere\ConsoleBundle\Tests\Source\KernelWithBundlesWithCommands; 16 | use PHPUnit_Framework_TestCase; 17 | use Symfony\Bundle\FrameworkBundle\Console\Application; 18 | 19 | final class ApplicationFactoryTest extends PHPUnit_Framework_TestCase 20 | { 21 | public function testCreate() 22 | { 23 | $kernel = new KernelWithBundlesWithCommands('prod', true); 24 | 25 | $this->assertInstanceOf( 26 | Application::class, 27 | (new ApplicationFactory())->create($kernel) 28 | ); 29 | } 30 | 31 | /** 32 | * @dataProvider provideTestCommandRegistration() 33 | * 34 | * @param string $environment 35 | * @param int $commandCount 36 | */ 37 | public function testCommandsRegistration($environment, $commandCount) 38 | { 39 | $kernel = new KernelWithBundlesWithCommands($environment, false); 40 | $application = (new ApplicationFactory())->create($kernel); 41 | 42 | $commands = $application->all(); 43 | $this->assertCount($commandCount, $commands); 44 | } 45 | 46 | /** 47 | * @return string[] 48 | */ 49 | public function provideTestCommandRegistration() 50 | { 51 | return [ 52 | ['prod', 9], 53 | ['dev', 3], 54 | ['test', 2], 55 | ]; 56 | } 57 | 58 | public function testCommandsRegistrationWithAlreadyRegisteredCommands() 59 | { 60 | $kernel = new KernelWithBundlesWithCommands('prod', false); 61 | $kernel->boot(); 62 | $application = (new ApplicationFactory())->create($kernel); 63 | 64 | $this->assertCount(9, $application->all()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Tests/Controller/ConsoleControllerTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\Controller; 13 | 14 | use CoreSphere\ConsoleBundle\Console\ApplicationFactory; 15 | use CoreSphere\ConsoleBundle\Contract\Executer\CommandExecuterInterface; 16 | use CoreSphere\ConsoleBundle\Controller\ConsoleController; 17 | use CoreSphere\ConsoleBundle\Tests\Source\KernelWithBundlesWithCommands; 18 | use PHPUnit_Framework_TestCase; 19 | use Prophecy\Argument; 20 | use Prophecy\Prophecy\ObjectProphecy; 21 | use Symfony\Bundle\FrameworkBundle\Console\Application; 22 | use Symfony\Component\HttpFoundation\Request; 23 | use Symfony\Component\Templating\EngineInterface; 24 | 25 | final class ConsoleControllerTest extends PHPUnit_Framework_TestCase 26 | { 27 | /** 28 | * @var array 29 | */ 30 | private $renderArguments = []; 31 | 32 | public function testConsoleActionWorkingDir() 33 | { 34 | $controller = $this->createControllerWithEnvironment('prod'); 35 | $controller->consoleAction(); 36 | $this->assertSame(getcwd(), $this->renderArguments[1]['working_dir']); 37 | } 38 | 39 | public function testConsoleActionEnvironment() 40 | { 41 | $controller = $this->createControllerWithEnvironment('prod'); 42 | $controller->consoleAction(); 43 | $this->assertSame('prod', $this->renderArguments[1]['environment']); 44 | 45 | $controller = $this->createControllerWithEnvironment('dev'); 46 | $controller->consoleAction(); 47 | $this->assertSame('dev', $this->renderArguments[1]['environment']); 48 | } 49 | 50 | public function testConsoleActionCommands() 51 | { 52 | $controller = $this->createControllerWithEnvironment('prod'); 53 | $controller->consoleAction(); 54 | 55 | $this->assertCount(9, $this->renderArguments[1]['commands']); 56 | } 57 | 58 | public function testExecAction() 59 | { 60 | $controller = $this->createControllerWithEnvironment('prod'); 61 | $request = new Request([], ['commands' => ['help', 'list']]); 62 | $controller->execAction($request); 63 | 64 | $commandsOutput = $this->renderArguments[1]['commands']; 65 | $this->assertSame([ 66 | [ 67 | 'output' => 'help-output', 68 | 'error_code' => 0, 69 | ], 70 | [ 71 | 'output' => 'list-output', 72 | 'error_code' => 0, 73 | ], 74 | ], $commandsOutput); 75 | } 76 | 77 | public function testExecActionWithError() 78 | { 79 | $controller = $this->createControllerWithEnvironment('prod'); 80 | $request = new Request([], ['commands' => ['error-command', 'help']]); 81 | $controller->execAction($request); 82 | 83 | $this->assertSame([[ 84 | 'error_code' => 1, 85 | ]], $this->renderArguments[1]['commands']); 86 | } 87 | 88 | /** 89 | * @param string $environment 90 | * 91 | * @return ConsoleController 92 | */ 93 | private function createControllerWithEnvironment($environment) 94 | { 95 | $templatingMock = $this->createTemplatingMock(); 96 | $commandExecuterMock = $this->createCommandExecuterMock(); 97 | $application = $this->createApplicationWithEnvironment($environment); 98 | 99 | return new ConsoleController( 100 | $templatingMock->reveal(), 101 | $commandExecuterMock->reveal(), 102 | $application, 103 | $environment 104 | ); 105 | } 106 | 107 | /** 108 | * @return ObjectProphecy 109 | */ 110 | private function createTemplatingMock() 111 | { 112 | $templatingMock = $this->prophesize(EngineInterface::class); 113 | $that = $this; 114 | $templatingMock->render(Argument::type('string'), Argument::type('array'))->will( 115 | function ($args) use ($that) { 116 | $that->renderArguments = $args; 117 | } 118 | ); 119 | 120 | return $templatingMock; 121 | } 122 | 123 | /** 124 | * @return ObjectProphecy 125 | */ 126 | private function createCommandExecuterMock() 127 | { 128 | $commandExecuterMock = $this->prophesize(CommandExecuterInterface::class); 129 | $commandExecuterMock->execute(Argument::exact('error-command')) 130 | ->willReturn([ 131 | 'error_code' => 1, 132 | ]); 133 | $commandExecuterMock->execute(Argument::exact('help')) 134 | ->willReturn([ 135 | 'output' => 'help-output', 136 | 'error_code' => 0, 137 | ]); 138 | $commandExecuterMock->execute(Argument::exact('list')) 139 | ->willReturn([ 140 | 'output' => 'list-output', 141 | 'error_code' => 0, 142 | ]); 143 | 144 | return $commandExecuterMock; 145 | } 146 | 147 | /** 148 | * @param string $environment 149 | * 150 | * @return Application 151 | */ 152 | private function createApplicationWithEnvironment($environment) 153 | { 154 | $kernel = new KernelWithBundlesWithCommands($environment, true); 155 | $application = (new ApplicationFactory())->create($kernel); 156 | 157 | return $application; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Tests/DataCollector/DataCollectorTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\DataCollector; 13 | 14 | use CoreSphere\ConsoleBundle\DataCollector\DataCollector; 15 | use PHPUnit_Framework_TestCase; 16 | use Symfony\Component\HttpFoundation\Request; 17 | use Symfony\Component\HttpFoundation\Response; 18 | 19 | final class DataCollectorTest extends PHPUnit_Framework_TestCase 20 | { 21 | public function testWhole() 22 | { 23 | $dataCollector = new DataCollector(); 24 | $requestMock = $this->prophesize(Request::class); 25 | $responseMock = $this->prophesize(Response::class); 26 | $dataCollector->collect($requestMock->reveal(), $responseMock->reveal()); 27 | 28 | $this->assertSame('coresphere_console', $dataCollector->getName()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Extension/CoreSphereConsoleExtensionTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\DependencyInjection\Extension; 13 | 14 | use CoreSphere\ConsoleBundle\Contract\Executer\CommandExecuterInterface; 15 | use CoreSphere\ConsoleBundle\DependencyInjection\Extension\CoreSphereConsoleExtension; 16 | use CoreSphere\ConsoleBundle\Tests\Executer\CommandExecutorSource\SomeKernel; 17 | use PHPUnit_Framework_TestCase; 18 | use Symfony\Component\DependencyInjection\ContainerBuilder; 19 | use Symfony\Component\DependencyInjection\Definition; 20 | 21 | final class CoreSphereConsoleExtensionTest extends PHPUnit_Framework_TestCase 22 | { 23 | public function testLoad() 24 | { 25 | $containerBuilder = $this->createAndPrepareContainerBuilder(); 26 | 27 | $extension = new CoreSphereConsoleExtension(); 28 | $extension->load([], $containerBuilder); 29 | 30 | $commandExecuter = $containerBuilder->get('coresphere_console.executer'); 31 | $this->assertInstanceOf(CommandExecuterInterface::class, $commandExecuter); 32 | } 33 | 34 | public function testPrepend() 35 | { 36 | $containerBuilder = new ContainerBuilder(); 37 | 38 | $extension = new CoreSphereConsoleExtension(); 39 | $extension->prepend($containerBuilder); 40 | 41 | $extensionConfig = $containerBuilder->getExtensionConfig($extension->getAlias()); 42 | $this->assertSame([ 43 | 'resource' => '.', 44 | 'type' => 'extra', 45 | ], $extensionConfig[0]); 46 | } 47 | 48 | /** 49 | * @return ContainerBuilder 50 | */ 51 | private function createAndPrepareContainerBuilder() 52 | { 53 | $containerBuilder = new ContainerBuilder(); 54 | $containerBuilder->setDefinition('kernel', new Definition(SomeKernel::class)) 55 | ->setArguments(['prod', true]); 56 | 57 | return $containerBuilder; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Tests/Executer/CommandExecuterTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\Executer; 13 | 14 | use CoreSphere\ConsoleBundle\Executer\CommandExecuter; 15 | use CoreSphere\ConsoleBundle\Tests\Executer\CommandExecutorSource\SomeKernel; 16 | use PHPUnit_Framework_TestCase; 17 | 18 | class CommandExecuterTest extends PHPUnit_Framework_TestCase 19 | { 20 | public function testExecute() 21 | { 22 | $executer = $this->createExecuterWithKernel('prod', true); 23 | $result = $executer->execute('list'); 24 | 25 | $this->assertSame('list', $result['input']); 26 | $this->assertContains('Lists commands', $result['output']); 27 | $this->assertSame('prod', $result['environment']); 28 | $this->assertSame(0, $result['error_code']); 29 | } 30 | 31 | public function testExecuteWithExplicitEnvironment() 32 | { 33 | $executer = $this->createExecuterWithKernel('prod', true); 34 | $result = $executer->execute('list --env=dev'); 35 | 36 | $this->assertSame('list --env=dev', $result['input']); 37 | $this->assertContains('Lists commands', $result['output']); 38 | $this->assertSame('dev', $result['environment']); 39 | $this->assertSame(0, $result['error_code']); 40 | } 41 | 42 | public function testExecuteNonExistingCommand() 43 | { 44 | $executer = $this->createExecuterWithKernel('dev', true); 45 | $result = $executer->execute('someNonExistingCommand'); 46 | 47 | $this->assertSame('someNonExistingCommand', $result['input']); 48 | $this->assertContains('Command "someNonExistingCommand" is not defined.', $result['output']); 49 | $this->assertSame('dev', $result['environment']); 50 | $this->assertSame(1, $result['error_code']); 51 | } 52 | 53 | /** 54 | * @param string $env 55 | * @param bool $debug 56 | * 57 | * @return CommandExecuter 58 | */ 59 | private function createExecuterWithKernel($env, $debug) 60 | { 61 | $kernel = new SomeKernel($env, $debug); 62 | 63 | return new CommandExecuter($kernel); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Tests/Executer/CommandExecutorSource/SomeKernel.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\Executer\CommandExecutorSource; 13 | 14 | use Symfony\Bundle\FrameworkBundle\FrameworkBundle; 15 | use Symfony\Component\Config\Loader\LoaderInterface; 16 | use Symfony\Component\DependencyInjection\ContainerBuilder; 17 | use Symfony\Component\HttpKernel\Kernel; 18 | 19 | final class SomeKernel extends Kernel 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | public function registerBundles() 25 | { 26 | return [ 27 | new FrameworkBundle(), 28 | ]; 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function registerContainerConfiguration(LoaderInterface $loader) 35 | { 36 | $loader->load(function (ContainerBuilder $containerBuilder) { 37 | $containerBuilder->setParameter('kernel.secret', 123); 38 | }); 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function getCacheDir() 45 | { 46 | return sys_get_temp_dir().'/_console_tests/temp'; 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function getLogDir() 53 | { 54 | return sys_get_temp_dir().'/_console_tests/log'; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Tests/Formatter/HtmlOutputFormatterDecoratorTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\Formatter; 13 | 14 | use CoreSphere\ConsoleBundle\Formatter\HtmlOutputFormatterDecorator; 15 | use PHPUnit_Framework_TestCase; 16 | use Symfony\Component\Console\Formatter\OutputFormatter; 17 | use Symfony\Component\Console\Formatter\OutputFormatterStyle; 18 | 19 | final class HtmlOutputFormatterDecoratorTest extends PHPUnit_Framework_TestCase 20 | { 21 | /** 22 | * @var HtmlOutputFormatterDecorator 23 | */ 24 | private $decoratedFormatter; 25 | 26 | protected function setUp() 27 | { 28 | $this->decoratedFormatter = new HtmlOutputFormatterDecorator(new OutputFormatter(true)); 29 | } 30 | 31 | public function testEscapingOutput() 32 | { 33 | $this->decoratedFormatter->setStyle('error', new OutputFormatterStyle('white', 'red')); 34 | $this->decoratedFormatter->setStyle('info', new OutputFormatterStyle('green')); 35 | $this->decoratedFormatter->setStyle('comment', new OutputFormatterStyle('yellow')); 36 | $this->decoratedFormatter->setStyle('question', new OutputFormatterStyle('black', 'cyan')); 37 | 38 | $this->assertSame( 39 | 'a<script>evil();</script>a', $this->decoratedFormatter->format( 40 | 'aa' 41 | ) 42 | ); 43 | 44 | $this->assertSame( 45 | '<script>evil();</script>', $this->decoratedFormatter->format( 46 | '' 47 | ) 48 | ); 49 | 50 | $this->assertSame( 51 | 'a'. 52 | '<script>'. 53 | 'evil();'. 54 | '</script>', $this->decoratedFormatter->format( 55 | 'a' 56 | ) 57 | ); 58 | 59 | $this->assertSame( 60 | 'a&lt;'. 61 | '<script>'. 62 | 'evil();'. 63 | '</script>', $this->decoratedFormatter->format( 64 | 'a<' 65 | ) 66 | ); 67 | } 68 | 69 | public function testDecorated() 70 | { 71 | $this->assertTrue($this->decoratedFormatter->isDecorated()); 72 | 73 | $this->decoratedFormatter->setDecorated(false); 74 | $this->assertFalse($this->decoratedFormatter->isDecorated()); 75 | } 76 | 77 | public function testUndecorated() 78 | { 79 | $this->decoratedFormatter->setStyle('info', new OutputFormatterStyle('green')); 80 | 81 | $this->decoratedFormatter->setDecorated(false); 82 | 83 | $this->assertSame( 84 | 'Do not change', 85 | $this->decoratedFormatter->format( 86 | 'Do not change' 87 | ) 88 | ); 89 | } 90 | 91 | public function testStyle() 92 | { 93 | $this->assertFalse($this->decoratedFormatter->hasStyle('nonExisting')); 94 | 95 | $outputFormatterStyle = new OutputFormatterStyle('blue'); 96 | $this->decoratedFormatter->setStyle('blue', $outputFormatterStyle); 97 | $this->assertTrue($this->decoratedFormatter->hasStyle('blue')); 98 | 99 | $this->assertSame($outputFormatterStyle, $this->decoratedFormatter->getStyle('blue')); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Tests/Output/StringOutputTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\Output; 13 | 14 | use CoreSphere\ConsoleBundle\Output\StringOutput; 15 | use PHPUnit_Framework_TestCase; 16 | 17 | final class StringOutputTest extends PHPUnit_Framework_TestCase 18 | { 19 | public function testWriteRead() 20 | { 21 | $output = new StringOutput(); 22 | 23 | $text = 'foo'; 24 | 25 | $output->write($text); 26 | $this->assertSame($text, $output->getBuffer()); 27 | 28 | $output->write($text, true); 29 | $this->assertSame($text.$text.PHP_EOL, $output->getBuffer()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/Routing/LoaderTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\Routing; 13 | 14 | use CoreSphere\ConsoleBundle\Routing\Loader; 15 | use PHPUnit_Framework_TestCase; 16 | use Symfony\Component\Config\FileLocator; 17 | use Symfony\Component\Config\Loader\LoaderResolverInterface; 18 | use Symfony\Component\Routing\Loader\YamlFileLoader; 19 | use Symfony\Component\Routing\Route; 20 | use Symfony\Component\Routing\RouteCollection; 21 | 22 | final class LoaderTest extends PHPUnit_Framework_TestCase 23 | { 24 | /** 25 | * @var Loader 26 | */ 27 | private $loader; 28 | 29 | protected function setUp() 30 | { 31 | $this->loader = new Loader(new YamlFileLoader(new FileLocator())); 32 | } 33 | 34 | public function testLoading() 35 | { 36 | $routes = $this->loader->load(null, null); 37 | $this->assertInstanceOf(RouteCollection::class, $routes); 38 | 39 | /** @var Route $route */ 40 | $route = $routes->get('console'); 41 | $this->assertSame('/_console', $route->getPath()); 42 | $this->assertSame('coresphere_console.controller:consoleAction', $route->getDefault('_controller')); 43 | 44 | /** @var Route $route */ 45 | $route = $routes->get('console_exec'); 46 | $this->assertSame('/_console/commands.{_format}', $route->getPath()); 47 | $this->assertSame('coresphere_console.controller:execAction', $route->getDefault('_controller')); 48 | } 49 | 50 | public function testSupports() 51 | { 52 | $this->assertTrue($this->loader->supports(null, 'extra')); 53 | $this->assertFalse($this->loader->supports(null, 'other')); 54 | } 55 | 56 | public function testResolver() 57 | { 58 | $this->assertNull($this->loader->getResolver()); 59 | 60 | $resolverMock = $this->prophesize(LoaderResolverInterface::class); 61 | $this->loader->setResolver($resolverMock->reveal()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Tests/Source/KernelWithBundlesWithCommands.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace CoreSphere\ConsoleBundle\Tests\Source; 13 | 14 | use Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle; 15 | use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle; 16 | use Symfony\Component\Config\Loader\LoaderInterface; 17 | use Symfony\Component\HttpKernel\Kernel; 18 | 19 | final class KernelWithBundlesWithCommands extends Kernel 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | public function registerBundles() 25 | { 26 | $bundles = []; 27 | 28 | if (in_array($this->getEnvironment(), ['prod'])) { 29 | $bundles[] = new DoctrineMigrationsBundle(); 30 | } 31 | 32 | if (in_array($this->getEnvironment(), ['dev'])) { 33 | $bundles[] = new DoctrineFixturesBundle(); 34 | } 35 | 36 | return $bundles; 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function registerContainerConfiguration(LoaderInterface $loader) 43 | { 44 | } 45 | 46 | /** 47 | * {@inheritdoc} 48 | */ 49 | public function getCacheDir() 50 | { 51 | return sys_get_temp_dir().'/_console_tests/temp'; 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function getLogDir() 58 | { 59 | return sys_get_temp_dir().'/_console_tests/log'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coresphere/console-bundle", 3 | "description": "This bundle allows you accessing the symfony2 console via your browser", 4 | "keywords": ["console","javascript","symfony"], 5 | "type": "symfony-bundle", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Laszlo Korte", 10 | "email": "coresphere@laszlokorte.de" 11 | }, 12 | { 13 | "name": "Marmus Ullman", 14 | "email": "mail@markus-ullmann.de" 15 | } 16 | ], 17 | "require": { 18 | "php": "^5.5|^7.0", 19 | "symfony/console": "~2.7|~3.0|~4.0", 20 | "symfony/dependency-injection": "~2.7|~3.0|~4.0", 21 | "symfony/event-dispatcher": "~2.7|~3.0|~4.0", 22 | "symfony/framework-bundle": "~2.7|~3.0|~4.0", 23 | "symfony/http-kernel": "~2.7|~3.0|~4.0" 24 | }, 25 | "require-dev": { 26 | "doctrine/doctrine-fixtures-bundle": "^2.2", 27 | "doctrine/doctrine-migrations-bundle": "^1.0", 28 | "phpunit/phpunit": "^4.8", 29 | "symfony/finder": "^2.7|~4.0", 30 | "symfony/templating": "^3.2|~4.0" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "CoreSphere\\ConsoleBundle\\": "" 35 | }, 36 | "exclude-from-classmap": [ 37 | "Tests/" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | . 18 | 19 | Tests 20 | vendor 21 | 22 | 23 | 24 | 25 | 26 | 27 | Tests 28 | 29 | 30 | 31 | 32 | --------------------------------------------------------------------------------