diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..181ec08 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +vendor +build +cache +.cache +.config +.local +*.phar \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6281ef2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM cloudobjects/php-app-base:latest + +# Add application code +ADD / /var/www/app/ + +# Add an executable to the Docker container for CLI use +RUN mv /var/www/app/phpmae.docker /usr/local/bin/phpmae && chmod +x /usr/local/bin/phpmae + +# Have default config.php ready for CLI where init may not run +RUN cp /var/www/app/config.php.default /var/www/app/config.php + +# Launch init script +CMD ["/bin/sh", "/var/www/app/init.sh"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index ee6256c..a612ad9 100644 --- a/LICENSE +++ b/LICENSE @@ -35,7 +35,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" @@ -357,7 +357,7 @@ Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at https://mozilla.org/MPL/2.0/. + file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE diff --git a/README.md b/README.md index 7127bb6..85d4be3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,122 @@ # phpMAE +phpMAE, the *PHP* *M*icro *A*PI *E*ngine, is an opinionated serverless framework for the development, execution, and deployment of small-sized stateless Web APIs, so-called "Micro APIs". + +The framework is partially built on top of the [Slim micro-framework](https://www.slimframework.com/) and leverages [PHPSandbox](https://phpsandbox.org/) to provide a safe runtime environment. + +The configuration and source code for Micro APIs can be stored in [CloudObjects Core](https://cloudobjects.io/) and are deployed just-in-time to a running phpMAE instance via the [CloudObjects SDK](https://packagist.org/packages/cloudobjects/sdk) when a request for a specific API is received. + +CloudObjects currently provides a preview release of a public hosted version of phpMAE. For development or if you wish to run your own Micro API engine, you can run phpMAE as a PHAR file, using our Docker container or directly from the source. + +## Installation + +**Note:** The installation steps below were tested on _macOS_, which has PHP installed by default. If you are on Linux, you may have to install PHP through your distribution's package manager first. phpMAE has not yet been tested on Windows, but support is on the roadmap. + +### PHAR + +This is the recommended installation method for developers to create, validate and deploy their Micro APIs. + +You can grab the latest PHAR (PHp ARchive) from the [phpMAE Releases on Codeberg](https://codeberg.org/CloudObjects/phpMAE/releases). + +Type `php phpmae.phar` to get a list of available CLI commands. Any commands or options that interact with CloudObjects require the [CloudObjects CLI Tool](https://cloudobjects.io/clitool) to be installed as a prerequisite. + +To make the `phpmae` CLI tool globally available on your system run the following commands from the directory in which you downloaded `phpmae.phar`: + + cp phpmae.phar /usr/local/bin/phpmae + chmod +x /usr/local/bin/phpmae + +### Docker + +This is the recommended installation method if you want to run Micro APIs for staging and production on your own servers (local or cloud). + +A prebuilt-image is available [from the Docker Hub](https://hub.docker.com/r/cloudobjects/phpmae/). You can download it via CLI: + + docker pull cloudobjects/phpmae + +When running the container you need to provide the _CO_AUTH_NS_ and _CO_AUTH_SECRET_ environment variables so that the phpMAE can authenticate itself against CloudObjects. Otherwise, only Micro APIs with [co:isVisibleTo](https://coid.link/cloudobjects.io/isVisibleTo) set to [co:Public](https://coid.link/cloudobjects.io/Public) can be run: + + docker run -e CO_AUTH_NS=example.com -e CO_AUTH_SECRET=XXXXXXXX -p 8080:80 cloudobjects/phpmae + +For _CO_AUTH_NS_ use a domain that you have added to CloudObjects and that you want to use as the identity for this phpMAE instance. For _CO_AUTH_SECRET_ you need to retrieve the shared secret between that domain and _cloudobjects.io_. You can retrieve this secret with the [CloudObjects CLI Tool](https://cloudobjects.io/clitool) using the following command: + + cloudobjects domain-providers:secret example.com cloudobjects.io + +### Source + +This installation method is only recommended if you want to "look under the hood" of phpMAE or run with particular options. + +You need to have [Composer](https://getcomposer.org) installed globally on your system to download and install the dependencies. + +You can download or `git clone` this repository from Codeberg, then run `composer install` (or `make`) to install dependencies. + +It's recommended to use composer to download and install with a single command: + + composer create-project cloudobjects/phpmae + +You can customize your installation of phpMAE by copying `config.php.default` to `config.php` and then editing the file as per your requirements. + +phpMAE comes with unit tests. You can run them after installing the source to validate that any changes you made did not break the tests: + + vendor/bin/phpunit + +## Getting Started Guide + +### Create a class + +Micro APIs compatible with phpMAE are implemented as PHP classes. They are represented as objects on CloudObjects with the type [phpmae:Class](https://coid.link/phpmae.dev/Class). All public methods on these classes are made accessible via RPC protocols (currently [JSON-RPC](https://www.jsonrpc.org/specification)) and other classes that add your class as a dependency. If you want your class to expose a single entry point you can add [PHP's magic __invoke()](https://secure.php.net/manual/en/language.oop5.magic.php#object.invoke) to it and make its object an instance of the type [phpmae:HTTPInvokableClass](https://coid.link/phpmae.dev/HTTPInvokableClass). + +Like all objects, phpMAE classes are uniquely identified with COIDs (*C*loud *O*bject *ID*entifiers). COIDs are namespaced into domains, and you can create objects with COIDs only for domains that you have created or been assigned to in CloudObjects. You can see those domains in the [CloudObjects Dashboard](https://cloudobjects.io/dashboard). + +To create a new class, choose a COID and then run the following command: + + phpmae class:create --confjob coid://NAMESPACE/NAME/VERSION + +If you want to create an HTTP-invokable class, add the option `--http-invokable`. + +This command writes two files into the current directory, namely `NAME.VERSION.xml` and `NAME.VERSION.php`. The `.xml` file contains the basic object description for CloudObjects in RDF/XML format and the `.php` file contains the skeleton code for the PHP class. It also creates a configuration job to register the COID. + +Open the `.php` file and start inserting your code. + +### Validate and test locally + +To check whether your code is valid PHP and also respects the constraints of phpMAE regarding whitelisted functions and classes run the following command: + + phpmae class:validate coid://NAMESPACE/NAME/VERSION + +You can add `--watch` to continuously watch for changes in the file and automatically revalidate. + +To run your class, you can launch a local web server. Open a second terminal window or tab and run the following command: + + phpmae testenv:start + +The web server runs in the foreground and can be stopped with _Ctrl + C_ (or _Cmd + C_). Go back to the first tab and run the following command: + + phpmae class:testenv coid://NAMESPACE/NAME/VERSION + +Apart from deploying your code to the local web server this command also prints out the base URL of your Micro API which you can then open in a browser or query from a tool such as `curl`. The `--watch` option is supported for continuous redeployment. + +### Deploy your class + +Use the following command to deploy your class: + + phpmae class:deploy coid://NAMESPACE/NAME/VERSION + +Internally, this command first validates the class, then calls the CloudObjects CLI to upload the `.php` source file as an attachment to CloudObjects Core and, if necessary, update the `.xml` file with a configuration job. Deployed classes are available for phpMAE instances within moments. + +The output of the deploy command shows you the base URL of your Micro API on the public phpMAE instances. These instances require you to use HTTP Basic authentication to access your class. You have to use the namespace as the username, and the CloudObjects shared secret between that domain and _phpmae.dev_ as the password. The command for retrieving this secret is shown to you as well. + +### Use your class on custom instances + +You can use your class on your own private instances as well. Start an instance,e.g., using Docker as described above, and replace _phpmae.dev_ in the URL with our own instance's URL. + +## Help&Support + +You can report bugs or suggest features through [our Codeberg Issues](https://codeberg.org/CloudObjects/phpMAE/issues). We also accept PRs with bug fixes; if you wish to contribute features, please create an issue first or discuss on chat. If you found a potential security issue, e.g., with the sandboxing feature, please do not use the public issue tracker but send an email to phpmae-security@cloudobjects.io. + +Make sure you follow the [CloudObjects Blog](https://blog.cloudobjects.io/) and [@CloudObjectsIO](https://twitter.com/CloudObjectsIO) for the latest updates, guides, and tutorials. + +Commercial support and hosted private instances are available from [CloudObjects Consulting](https://cloudobjects.io/consulting). + +## License + +phpMAE is licensed under the Mozilla Public License (see LICENSE file). \ No newline at end of file diff --git a/RoboFile.php b/RoboFile.php new file mode 100644 index 0000000..c2249ee --- /dev/null +++ b/RoboFile.php @@ -0,0 +1,198 @@ +taskPackPhar('phpmae.phar') + ->compress() + ->addFile('phpmae.php', 'phpmae.php') + ->addFile('config.php', 'config.php') + ->addFile('web/index.php', 'web/index.php') + ->stub('stub.php'); + + $finder = Finder::create() + ->name('*.php') + ->in('classes'); + + foreach ($finder as $file) { + $pharTask->addFile('classes/'.$file->getRelativePathname(), $file->getRealPath()); + } + + $finder = Finder::create()->files() + ->name('*.php') + ->in('vendor'); + + foreach ($finder as $file) { + $pharTask->addStripped('vendor/'.$file->getRelativePathname(), $file->getRealPath()); + } + + $finder = Finder::create()->files() + ->name('*.php') + ->name('*.json') + ->in('stacks'); + + foreach ($finder as $file) { + $pharTask->addStripped('stacks/'.$file->getRelativePathname(),$file->getRealPath()); + } + + $pharTask->run(); + + // Verify Phar is packed correctly + $code = $this->_exec('php phpmae.phar'); + } + + public function sanitizeDependencies($directory) { + require_once "vendor/autoload.php"; + + $finder = Finder::create()->files() + ->name('*.php') + ->in($directory) + ->notPath('composer'); + + $forbiddenFunctions = [ 'file_get_contents', 'file_put_contents', 'fopen' ]; + + foreach ($finder as $file) { + try { + $content = file_get_contents($file); + foreach ($forbiddenFunctions as $func) { + $content = preg_replace('/\b(?)'.$func.'\(/', '\CloudObjects\PhpMAE\Sandbox\FunctionExecutor::returnNull(', $content); + $content = str_replace('\\\CloudObjects', '\CloudObjects', $content); + } + file_put_contents($file, $content); + } catch (\Exception $e) { + $this->say($file.': '.get_class($e).' '.$e->getMessage()); + } + } + } + + public function buildFunctionWhitelist() { + $allFunctions = get_defined_functions()['internal']; + $whitelisted = file_exists('data/function.whitelist.json') + ? json_decode(file_get_contents('data/function.whitelist.json'), true) : []; + $blacklisted = file_exists('data/function.blacklist.json') + ? json_decode(file_get_contents('data/function.blacklist.json'), true) : []; + + $client = new \GuzzleHttp\Client([ 'base_uri' => 'http://php.net/manual/en/' ]); + $autoBlacklistPrefix = ''; + + $progress = (count($whitelisted) + count($blacklisted)) / count($allFunctions) * 100; + $this->say($progress.'% of functions handled, let\'s do the rest ...'); + + foreach ($allFunctions as $f) { + // Ignore if already handled + if (in_array($f, $whitelisted) || in_array($f, $blacklisted)) + continue; + + $this->yell($f); + + if ($autoBlacklistPrefix != '' && substr($f, 0, strlen($autoBlacklistPrefix)) == $autoBlacklistPrefix) { + $this->say('Blacklisted automatically.'); + $blacklisted[] = $f; + continue; + } + $autoBlacklistPrefix = ''; + + try { + // Get and display documentation + $crawler = new \Symfony\Component\DomCrawler\Crawler( + $client->get('function.'.str_replace('_', '-', $f).'.php')->getBody()->getContents() + ); + $this->say($crawler->filter('.refpurpose')->text()); + $this->say($crawler->filter('.refsect1.description')->text()); + } catch (\Exception $e) { + $this->say('Error while retrieving information: '.$e->getMessage()); + } + // Ask what to do + $action = null; + while (!in_array($action, ['w','b','a','s','x'])) + $action = $this->ask('(w)hitelist, (b)lacklist, (a)ll blacklist, (s)kip, e(x)it'); + + switch ($action) { + case "w": + $whitelisted[] = $f; + break; + case "b": + $blacklisted[] = $f; + break; + case "a": + $blacklisted[] = $f; + $autoBlacklistPrefix = substr($f, 0, strpos($f, '_')+1); + break; + case "x": + file_put_contents('data/function.whitelist.json', json_encode($whitelisted)); + file_put_contents('data/function.blacklist.json', json_encode($blacklisted)); + exit(0); + } + // Save on every step to prevent data loss from crashes + file_put_contents('data/function.whitelist.json', json_encode($whitelisted)); + file_put_contents('data/function.blacklist.json', json_encode($blacklisted)); + } + } + + public function installStack($stack) { + require_once "vendor/autoload.php"; + + // Fetch stack definition from CloudObjects Core + $stackCoid = COIDParser::fromString($stack); + $retriever = new ObjectRetriever([ + 'auth_ns' => 'phpmae.dev', + 'auth_secret' => getenv('PHPMAE_SHARED_SECRET') + ]); + $stackObject = $retriever->getObject($stackCoid); + + $composerFileContent = $retriever->getAttachment($stackCoid, + $stackObject->getProperty('coid://phpmae.dev/hasAttachedComposerFile') + ->getId()); + Assert::startsWith($composerFileContent, '{'); + + $lockFileContent = $retriever->getAttachment($stackCoid, + $stackObject->getProperty('coid://phpmae.dev/hasAttachedLockFile') + ->getId()); + Assert::startsWith($lockFileContent, '{'); + + $stackDir = __DIR__.'/stacks/'.md5($stack); + + // Install stack + $this->taskFilesystemStack() + ->mkdir($stackDir) + ->run(); + $this->taskWriteToFile($stackDir.'/composer.json') + ->text($composerFileContent) + ->run(); + $this->taskWriteToFile($stackDir.'/composer.lock') + ->text($lockFileContent) + ->run(); + + // Find whitelisted classes + $whitelistedClasses = []; + foreach ($stackObject->getProperty('coid://phpmae.dev/whitelistsClassname') + as $whitelistedClass) + $whitelistedClasses[] = $whitelistedClass->getValue(); + + $this->taskWriteToFile($stackDir.'/meta.json') + ->text(json_encode([ + 'rev' => $stackObject->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue(), + 'whitelisted_classes' => $whitelistedClasses + ])) + ->run(); + + $this->taskComposerInstall(__DIR__.'/composer.phar') + ->dir($stackDir) + ->run(); + + // Sanitize stack + $this->sanitizeDependencies($stackDir); + } + +} diff --git a/classes/ClassRepository.php b/classes/ClassRepository.php new file mode 100644 index 0000000..294f4aa --- /dev/null +++ b/classes/ClassRepository.php @@ -0,0 +1,285 @@ +classMap[$classname])) { + include $this->classMap[$classname]; + } + } + + public function __construct(ContainerInterface $container) { + $this->options = [ + 'cache_dir' => $container->get('cache_dir') . '/classes', + 'uploads_dir' => $container->get('uploads_dir'), + 'uploads' => $container->get('uploads') + ]; + + $this->container = $container; + + $this->reader = new NodeReader([ + 'prefixes' => [ + 'phpmae' => 'coid://phpmae.dev/' + ] + ]); + + // Initialize autoloader + spl_autoload_register(array($this, 'loader')); + } + + private function getURIVars(IRI $uri) { + $vars = array('uri_hash' => strtoupper(md5((string)$uri))); + $vars['php_namespace'] = "CloudObjects\\PhpMAE\\Class_".$vars['uri_hash']; + $vars['php_classname_local'] = (COIDParser::getType($uri)==COIDParser::COID_VERSIONED) + ? substr($uri->getPath(), 1, strrpos($uri->getPath(), '/')-1) + : substr($uri->getPath(), 1); + $vars['php_classname'] = $vars['php_namespace'].'\\'.$vars['php_classname_local']; + $vars['cache_path'] = $this->options['cache_dir'].DIRECTORY_SEPARATOR.$vars['uri_hash']; + $vars['upload_filename'] = $this->options['uploads_dir'].DIRECTORY_SEPARATOR.$vars['uri_hash'].'.php'; + if ($this->options['uploads'] == true && !is_dir($this->options['uploads_dir'])) + mkdir($this->options['uploads_dir'], 0777, true); + return $vars; + } + + public function coidToClassName(IRI $uri) { + $vars = $this->getURIVars($uri); + return $vars['php_classname']; + } + + /** + * Get a path on which custom files can be cached for a object. + * @param Node $object + */ + public function getCustomFilesCachePath(Node $object) { + $path = $this->options['cache_dir'].DIRECTORY_SEPARATOR + .strtoupper(md5($object->getId())).DIRECTORY_SEPARATOR + .($object->getProperty(ObjectRetriever::REVISION_PROPERTY) + ? $object->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue() + : 'LocalConfig'); + if (!is_dir($path)) mkdir($path, 0777, true); + return $path; + } + + public function storeUploadedFile(Node $object, $content) { + $uri = new IRI($object->getId()); + $vars = $this->getURIVars($uri); + + // Fetch class description + $revision = $object->getProperty(ObjectRetriever::REVISION_PROPERTY) + ? $object->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue() + : 'LocalConfig'; + + // Clear cache if cached version exists + $cachedFilename = $vars['cache_path'].DIRECTORY_SEPARATOR.$revision.".php"; + if (file_exists($cachedFilename)) unlink($cachedFilename); + + // Store source + file_put_contents($vars['upload_filename'], $content); + return true; + } + + private function buildContainer($className, Node $object, $additionalDefinitions = []) { + $autowiring = new DI\WhitelistReflectionBasedAutowiring; + + $sources = [ + new DefinitionArray($this->container->get(DI\DependencyInjector::class) + ->getDependencies($object, $additionalDefinitions), $autowiring), + new DefinitionArray([ + Engine::SKEY => \DI\autowire($className) + ], $autowiring), + $autowiring + ]; + + $source = new SourceChain($sources); + $source->setMutableDefinitionSource(new DefinitionArray([], $autowiring)); + + // TODO: add compilation + + $container = new Container($source); + $sandboxedContainer = new DI\SandboxedContainer($container); + $container->set(ContainerInterface::class, $sandboxedContainer); + $container->set(Container::class, $sandboxedContainer); + $container->set(FactoryInterface::class, $sandboxedContainer); + $container->set(InvokerInterface::class, $sandboxedContainer); + return $sandboxedContainer; + } + + /** + * Create an instance of a class. Returns a container that includes the class itself as Engine::SKEY + * as well as all dependencies specified by the class. + * + * @param Node $object The object describing the class. + * @param RequestInterface $request The optional request, if it should be made available + * @param array $additionalDefinitions Definitions to add to the DI container for this class + * @param string $sourceCode Optional source code to use for the class implementation instead of retrieving. + */ + public function createInstance(Node $object, RequestInterface $request = null, + array $additionalDefinitions = [], string $sourceCode = null) { + // Check type + if (!TypeChecker::isClass($object)) + throw new PhpMAEException("<".$object->getId()."> must have a valid type."); + + $uri = new IRI($object->getId()); + $vars = $this->getURIVars($uri); + if (!isset($this->classMap[$vars['php_classname']])) { + $objectRetriever = $this->container->get(ObjectRetriever::class); + + // Get revision + $revision = $object->getProperty(ObjectRetriever::REVISION_PROPERTY) + ? $object->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue() + : 'LocalConfig'; + + // Build filename where cached version should exist + $filename = $vars['cache_path'].DIRECTORY_SEPARATOR.$revision.".php"; + $this->container->get(ErrorHandler::class) + ->addMapping($filename, $object); + + // Check for required implemented interfaces + $interfaces = []; + foreach (TypeChecker::getAdditionalTypes($object) as $i) { + $interfaceObject = $objectRetriever->get($i); + if (!TypeChecker::isInterface($interfaceObject)) + continue; + + $this->createInterfaceInstance($interfaceObject); + $interfaces[] = $i; + } + + // Load the stack that the class requires + $stack = $this->reader->getFirstValueString($object, 'phpmae:usesStack', + self::DEFAULT_STACK); + + $stackDir = __DIR__.'/../stacks/'.md5($stack); + if (!is_dir($stackDir)) + throw new PhpMAEException("The stack <".$stack."> is not installed on this phpMAE instance."); + + require_once $stackDir.'/vendor/autoload.php'; + + if (!file_exists($filename) || $sourceCode != null) { + if (!isset($sourceCode)) { + // File does not exist -> check in uploads first + if (file_exists($vars['upload_filename'])) { + $sourceCode = file_get_contents($vars['upload_filename']); + } else { + // Not found in local uploads -> download source from CloudObjects + $sourceUrl = $object->getProperty('coid://phpmae.dev/hasSourceFile'); + if (!$sourceUrl) throw new PhpMAEException("<".$object->getId()."> does not have an implementation source file."); + if (get_class($sourceUrl)=='ML\JsonLD\Node') + $sourceCode = $objectRetriever->getAttachment($uri, $sourceUrl->getId()); + else + $sourceCode = $objectRetriever->getAttachment($uri, $sourceUrl->getValue()); + } + } + + // Run source code through validator to ensure sanity + // and convert to sandbox + $validator = new ClassValidator; + $sourceCode = $validator->validate($sourceCode, $uri, $interfaces); + + // Add namespaces for dependencies and interfaces + $use = ''; + $classList = array_merge( + $this->container->get(DI\DependencyInjector::class)->getClassDependencyList($object), + $interfaces + ); + foreach ($classList as $cl) + $use .= " use ".$this->coidToClassName($cl).";"; + + // Add namespace declaration + $sourceCode = "classMap[$vars['php_classname']] = $filename; + } + + if (isset($request)) { + $additionalDefinitions['request'] = $request; + $additionalDefinitions[RequestInterface::class] = $request; + } + + return $this->buildContainer($vars['php_classname'], $object, $additionalDefinitions); + } + + /** + * Creates an instance of an interface. + * + * @param Node $object The object describing the interface. + */ + public function createInterfaceInstance(Node $object) { + // Check type + if (!TypeChecker::isInterface($object)) + throw new PhpMAEException("<".$object->getId()."> must have a valid type."); + + $uri = new IRI($object->getId()); + $vars = $this->getURIVars($uri); + if (!isset($this->classMap[$vars['php_classname']])) { + $objectRetriever = $this->container->get(ObjectRetriever::class); + + // Get revision + $revision = $object->getProperty(ObjectRetriever::REVISION_PROPERTY) + ? $object->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue() + : 'LocalConfig'; + + // Build filename where cached version should exist + $filename = $vars['cache_path'].DIRECTORY_SEPARATOR.$revision.".php"; + $this->container->get(ErrorHandler::class) + ->addMapping($filename, $object); + + if (!file_exists($filename)) { + // File does not exist -> check in uploads first + if (file_exists($vars['upload_filename'])) { + $sourceCode = file_get_contents($vars['upload_filename']); + } else { + // Not found in local uploads -> download source from CloudObjects + $sourceUrl = $object->getProperty('coid://phpmae.dev/hasDefinitionFile'); + if (!$sourceUrl) throw new PhpMAEException("<".$object->getId()."> does not have a definition file."); + if (get_class($sourceUrl)=='ML\JsonLD\Node') + $sourceCode = $objectRetriever->getAttachment($uri, $sourceUrl->getId()); + else + $sourceCode = $objectRetriever->getAttachment($uri, $sourceUrl->getValue()); + } + + // Run source code through validator to ensure sanity + $validator = new ClassValidator; + $validator->validateInterface($sourceCode, $uri); + + // Add namespace declaration + $sourceCode = str_replace("classMap[$vars['php_classname']] = $filename; + } + } +} diff --git a/classes/ClassValidator.php b/classes/ClassValidator.php new file mode 100644 index 0000000..59ba6d1 --- /dev/null +++ b/classes/ClassValidator.php @@ -0,0 +1,212 @@ +sandbox = new CustomizedSandbox; + + $this->whitelisted_interfaces = [ + 'Symfony\Component\EventDispatcher\EventSubscriberInterface', + 'Psr\Http\Message\RequestInterface', + 'Psr\Container\ContainerInterface', + 'Psr\SimpleCache\CacheInterface', + 'Psr\Http\Message\ResponseInterface', + 'Symfony\Component\Mailer\MailerInterface' + ]; + $this->whitelisted_types = [ + 'ArrayObject', 'DateInterval', 'DateTime', 'DateTimeImmutable', 'DateTimeZone', + 'DOMElement', 'Exception', + 'SimpleXMLElement', + 'ML\IRI\IRI', + 'ML\JsonLD\JsonLD', 'ML\JsonLD\Node', 'ML\JsonLD\Graph', 'ML\JsonLD\TypedValue', + 'GuzzleHttp\Client', + 'GuzzleHttp\HandlerStack', 'GuzzleHttp\Middleware', + 'GuzzleHttp\Handler\CurlHandler', + 'GuzzleHttp\Subscriber\Oauth\Oauth1', + 'GuzzleHttp\Promise', + 'Dflydev\FigCookies\SetCookie', + 'Symfony\Component\Mime\Email', + 'CloudObjects\PhpMAE\ConfigLoader', + 'CloudObjects\PhpMAE\TwigTemplateFactory', + 'CloudObjects\PhpMAE\DI\DynamicLoader', + 'CloudObjects\SDK\ObjectRetriever', + 'CloudObjects\SDK\NodeReader', + 'CloudObjects\SDK\AccountGateway\AccountContext', + 'CloudObjects\SDK\AccountGateway\AAUIDParser', + 'CloudObjects\SDK\COIDParser', + 'CloudObjects\SDK\Common\CryptoHelper', + 'Webmozart\Assert\Assert' + ]; + } + + public function isWhitelisted($name) { + return in_array($name, $this->whitelisted_types) + || in_array($name, $this->whitelisted_interfaces); + } + + private function initializeWhitelist($stack = ClassRepository::DEFAULT_STACK) { + // Generate whitelist based on alias names + $interfaces = []; + $types = []; + foreach ($this->whitelisted_interfaces as $i) { + $interfaces[] = (isset($this->aliases[$i])) + ? strtolower($this->aliases[$i]) : strtolower($i); + // Validation of some elements relies on interfaces also being added as types + $types[] = (isset($this->aliases[$i])) + ? strtolower($this->aliases[$i]) : strtolower($i); + } + foreach ($this->whitelisted_types as $t) { + $types[] = (isset($this->aliases[$t])) + ? strtolower($this->aliases[$t]) : strtolower($t); + } + + // Load and apply stack + $filename = __DIR__.'/../stacks/'.md5($stack).'/meta.json'; + if (!file_exists($filename)) + throw new PhpMAEException("The specified stack <".$stack."> is not installed."); + $stackMeta = json_decode(file_get_contents($filename), true); + if (isset($stackMeta['whitelisted_classes'])) { + foreach ($stackMeta['whitelisted_classes'] as $t) { + $types[] = (isset($this->aliases[$t])) + ? strtolower($this->aliases[$t]) : strtolower($t); + } + } + + // Apply to sandbox + $this->sandbox->whitelist([ + 'interfaces' => $interfaces, + 'types' => $types, + 'classes' => $types + ]); + } + + public function validate($sourceCode, IRI $coid, array $interfaceCoids = [], + $stack = ClassRepository::DEFAULT_STACK) { + + // Initialize parser and parse source code + $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); + $ast = $parser->parse($sourceCode); + + // Parse and dump use statements + $aliasMap = array(); + while (get_class($ast[0])=='PhpParser\Node\Stmt\Use_') { + foreach ($ast[0]->uses as $use) { + $name = (string)$use->name; + $aliasMap[$use->alias] = $name; + $this->aliases[$name] = $use->alias; + } + array_shift($ast); + } + + // Check for class definition and implemented interfaces + if (count($ast)==1 && get_class($ast[0])=='PhpParser\Node\Stmt\Class_' + && isset($ast[0]->implements)) { + + if ($ast[0]->name != COIDParser::getName($coid)) + throw new PhpMAEException("The PHP classname (".$ast[0]->name.") doesn't match the name segment of the COID (".COIDParser::getName($coid).")."); + + $interfaces = []; + foreach ($ast[0]->implements as $i) { + $name = (string)$i; + $interfaces[] = (isset($aliasMap[$name])) ? $aliasMap[$name] : $name; + } + + // Check for any interfaces and whitelist them for validation + foreach ($interfaceCoids as $coid) { + if (!COIDParser::isValidCOID($coid)) continue; + + $name = COIDParser::getName($coid); + $found = false; + foreach ($interfaces as $i) { + if ($i == $name) { + $this->whitelisted_interfaces[] = $i; + $found = true; + break; + } + } + if (!$found) + throw new PhpMAEException("Source code file must declare a class that implements <".$name.">."); + } + + // Allow self-references + $this->whitelisted_types[] = strtolower($ast[0]->name); + + // Initialize whitelist + $this->initializeWhitelist($stack); + + // Validate and prepare code in sandbox + return $this->sandbox->prepare($sourceCode); + + } else { + // Throw exeption if conditions are not met + throw new PhpMAEException("Source code file must include exactly one class declaration and must not contain further side effects."); + } + } + + public function validateInterface($sourceCode, IRI $coid) { + // Initialize parser and parse source code + $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); + $ast = $parser->parse($sourceCode); + + // Parse and dump use statements + $aliasMap = array(); + while (get_class($ast[0])=='PhpParser\Node\Stmt\Use_') { + foreach ($ast[0]->uses as $use) { + $name = (string)$use->name; + $aliasMap[$use->alias] = $name; + $this->aliases[$name] = $use->alias; + } + array_shift($ast); + } + + // Check for class definition and implemented interfaces + if (count($ast)==1 && get_class($ast[0])=='PhpParser\Node\Stmt\Interface_') { + + if ($ast[0]->name != COIDParser::getName($coid)) + throw new PhpMAEException("The PHP interface name (".$ast[0]->name.") doesn't match the name segment of the COID (".COIDParser::getName($coid).")."); + + // Allow self-references + $this->whitelisted_types[] = strtolower($ast[0]->name); + + // Initialize whitelist + $this->initializeWhitelist(); + + // Apply whitelist visitor + $traverser = new NodeTraverser; + $traverser->addVisitor(new SandboxWhitelistVisitor($this->sandbox)); + $traverser->addVisitor(new ValidatorVisitor($this->sandbox)); + $traverser->traverse($ast); + + return; + } else { + // Throw exeption if conditions are not met + throw new PhpMAEException("Source code file must include exactly one interface declaration and must not contain further side effects."); + } + } + + public static function isInvokableClass($class) { + return method_exists($class, '__invoke'); + } + +} diff --git a/classes/Commands/AbstractAddDependenciesCommand.php b/classes/Commands/AbstractAddDependenciesCommand.php new file mode 100644 index 0000000..d54ef38 --- /dev/null +++ b/classes/Commands/AbstractAddDependenciesCommand.php @@ -0,0 +1,90 @@ +addOption('confjob', null, InputOption::VALUE_NONE, 'Calls "cloudobjects" to create a configuration job for the updated class.'); + } + + protected function dependencyPrecheck() { + $this->assertRDF(); + $this->assertPHPExists(); + } + + protected function getObjectAndAssertType(string $coid, string $type) { + // Retrieve configuration + $config = shell_exec("cloudobjects get ".$coid); + if (!isset($config)) + throw new \Exception("Could not retrieve <".$coid.">."); + + // Parse and validate configuration + $parser = \ARC2::getRDFXMLParser(); + $parser->parse('', $config); + $index = $parser->getSimpleIndex(false); + if (!isset($index) || !isset($index[$coid]) + || !isset($index[$coid]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'])) + throw new \Exception("<".$coid."> is not a valid CloudObjects object."); + + $hasType = false; + foreach ($index[$coid]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] as $property => $values) { + if ($values['value'] == $type) { + $hasType = true; + break; + } + } + + if (!$hasType) + throw new \Exception("<".$coid."> must have the type <".$type.">."); + } + + protected function addDependency(string $key, string $type, array $valuesToMerge, + InputInterface $input, OutputInterface $output) { + + $this->index['_:dep-'.$key] = array_merge([ + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' => [ + [ 'type' => 'uri', 'value' => $type ] + ], + 'coid://phpmae.dev/hasKey' => [ + [ 'type' => 'literal', 'value' => $key ] + ] + ], $valuesToMerge); + + // Edit configuration + $object = $this->index[(string)$this->coid]; + if (isset($object['coid://phpmae.dev/hasDependency'])) { + foreach ($object['coid://phpmae.dev/hasDependency'] as $o) { + if ($o['type'] != 'bnode') continue; + $bnode = $this->index[$o['value']]; + if (isset($bnode['coid://phpmae.dev/hasKey']) && $bnode['coid://phpmae.dev/hasKey'][0]['value'] == $key) + throw new \Exception("A dependency with the key '".$key."' already exists."); + + foreach ($valuesToMerge as $k => $values) + if (isset($bnode[$k])) + foreach ($bnode[$k] as $a) + foreach ($valuesToMerge[$k] as $b) + if ($a['type'] == $b['type'] && $a['value'] == $b['value']) + throw new \Exception("This dependency was already added."); + } + $object['coid://phpmae.dev/hasDependency'][] = [ 'type' => 'bnode', 'value' => '_:dep-'.$key ]; + } else + $object['coid://phpmae.dev/hasDependency'] = [['type' => 'bnode', 'value' => '_:dep-'.$key ]]; + + // Persist configuration + $this->index[(string)$this->coid] = $object; + $this->updateRDFLocally($output); + + if ($input->getOption('confjob')) + $this->createConfigurationJob($output); + } + +} diff --git a/classes/Commands/AbstractObjectCommand.php b/classes/Commands/AbstractObjectCommand.php new file mode 100644 index 0000000..4c519d2 --- /dev/null +++ b/classes/Commands/AbstractObjectCommand.php @@ -0,0 +1,133 @@ +coid = COIDParser::fromString($coid); + + if (COIDParser::getType($this->coid)!=COIDParser::COID_VERSIONED + && COIDParser::getType($this->coid)!=COIDParser::COID_UNVERSIONED) + throw new Exception("Invalid COID: ".(string)$this->coid); + + $name = COIDParser::getName($this->coid); + $version = COIDParser::getVersion($this->coid); + $this->fullName = isset($version) ? $name.".".$version : $name; + $this->phpFileName = $this->fullName.'.php'; + $this->xmlFileName = $this->fullName.'.xml'; + } + + protected function assertRDF() { + if (!file_exists($this->xmlFileName)) + throw new Exception("File not found: ".$this->xmlFileName); + + $parser = \ARC2::getRDFXMLParser(); + $parser->parse('', file_get_contents($this->xmlFileName)); + $index = $parser->getSimpleIndex(false); + $id = (string)$this->coid; + if (!isset($index) || !isset($index[$id]) + || !isset($index[$id]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'])) + throw new Exception($this->xmlFileName." does not contain a valid RDF description of the object."); + + $this->rdfTypes = []; + foreach ($index[$id]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] as $o) + if ($o['type'] == 'uri') $this->rdfTypes[] = $o['value']; + $this->index = $index; + } + + protected function updateRDFLocally(OutputInterface $output) { + file_put_contents($this->xmlFileName, + $this->getSerializer()->getSerializedIndex($this->index)); + $output->writeln("Updated ".$this->xmlFileName); + } + + protected function createConfigurationJob(OutputInterface $output) { + $output->writeln("Calling cloudobjects configuration-job:create ..."); + passthru("cloudobjects configuration-job:create ".$this->xmlFileName); + } + + protected function ensureFilenameInConfig(OutputInterface $output, $interface = false) { + $property = ($interface ? 'coid://phpmae.dev/hasDefinitionFile' + : 'coid://phpmae.dev/hasSourceFile'); + $object = $this->index[(string)$this->coid]; + if (!isset($object[$property])) { + $object[$property] = [[ + 'value' => 'file:///'.$this->fullName.'.php', + 'type' => 'uri' + ]]; + $this->index[(string)$this->coid] = $object; + $this->updateRDFLocally($output); + return true; + } else + return false; + } + + protected function assertPHPExists() { + if (!file_exists($this->phpFileName)) + throw new Exception("File not found: ".$this->phpFileName); + } + + protected function getSerializer() { + return \ARC2::getRDFXMLSerializer(array( + 'serializer_type_nodes' => true, + 'ns' => array( + 'co' => 'coid://cloudobjects.io/', + 'phpmae' => 'coid://phpmae.dev/' + ) + )); + } + + protected function watchPHPFile(OutputInterface $output, callable $callable) { + $fileTime = filemtime($this->phpFileName); + $output->writeln('Watching for changes ...'); + set_time_limit(0); + while (true) { + clearstatcache(); + if (filemtime($this->phpFileName) != $fileTime) { + // File has changed ... + sleep(1); + $fileTime = filemtime($this->phpFileName); + $callable(); + $output->writeln('Watching for changes ...'); + } + sleep(0.5); + } + } + + protected function getAdditionalTypes() { + $coids = []; + foreach ($this->rdfTypes as $t) { + if (in_array($t, [ 'coid://phpmae.dev/Class', + 'coid://phpmae.dev/HTTPInvokableClass', + 'coid://phpmae.dev/Interface' ])) + continue; + $coids[] = new IRI($t); + } + + return $coids; + } +} \ No newline at end of file diff --git a/classes/Commands/ClassCreateCommand.php b/classes/Commands/ClassCreateCommand.php new file mode 100644 index 0000000..d8a5c13 --- /dev/null +++ b/classes/Commands/ClassCreateCommand.php @@ -0,0 +1,243 @@ +setName('class:create') + ->setDescription('Create a new class for the phpMAE.') + ->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.') + ->addOption('http-invokable', 'hi', InputOption::VALUE_NONE, 'Makes the class HTTP-invokable.') + ->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces new object creation and replaces existing files.') + ->addOption('public', null, InputOption::VALUE_NONE, 'Marks new object as public.') + ->addOption('confjob', null, InputOption::VALUE_NONE, 'Calls "cloudobjects" to create a configuration job for the new class.') + ->addOption('autowire', null, InputOption::VALUE_REQUIRED, 'Creates a constructor that autowires a PHP dependency.', null) + ->addOption('implements', null, InputOption::VALUE_REQUIRED, 'Make this class an implementation of the phpMAE interface with the specified COID.', null); + } + + private function getAndValidateInterfaceConfig($implements) { + // Check interface COID + $interfaceCoid = COIDParser::fromString($implements); + if (COIDParser::getType($interfaceCoid) != COIDParser::COID_VERSIONED + && COIDParser::getType($interfaceCoid) != COIDParser::COID_UNVERSIONED) + throw new \Exception("Invalid Interface COID: ".(string)$interfaceCoid); + + // Retrieve interface configuration + $implements = (string)$interfaceCoid; + $interfaceConfig = shell_exec("cloudobjects get ".$implements); + if (!isset($interfaceConfig)) + throw new \Exception("Could not retrieve interface configuration."); + + // Parse and validate interface configuration + $parser = \ARC2::getRDFXMLParser(); + $parser->parse('', $interfaceConfig); + $index = $parser->getSimpleIndex(false); + if (!isset($index) || !isset($index[$implements]) + || !isset($index[$implements]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'])) + throw new \Exception("<".$implements."> is not a valid CloudObjects object."); + + $isInterface = false; + foreach ($index[$implements]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] as $property => $values) { + if ($values['value'] == 'coid://phpmae.dev/Interface') + $isInterface = true; + } + + if (!$isInterface || !isset($index[$implements]['coid://phpmae.dev/hasDefinitionFile'])) + throw new \Exception("<".$implements."> is not a valid phpMAE interface."); + + return [ + 'classname' => COIDParser::getName($interfaceCoid), + 'filename' => basename($index[$implements]['coid://phpmae.dev/hasDefinitionFile'][0]['value']), + 'coid' => (string)$interfaceCoid, + ]; + } + + private function getAndParseInterfaceCode($interface, $filename) { + // Retrieve interface code + $interfaceCode = shell_exec("cloudobjects attachment:get ".$interface + ." ".$filename); + + // Run through validator + $validator = new ClassValidator; + $validator->validateInterface($interfaceCode, new IRI($interface)); + + // Find use statements + $matches = []; + preg_match_all("/use\s+(.+);/", $interfaceCode, $matches); + $use = $matches[1]; + + // Parse method definitions + // (this is the same algorithm as the DirectoryTemplateVariableGenerator, + // but less filtering on comment string) + $matches = []; + preg_match_all("/(?:\/\*\*((?:[\s\S](?!\/\*))*?)\*\/+\s*)?public\s+function\s+(\w+)\s*\((.+)\)/", + $interfaceCode, $matches); + + // The following groups are captured through RegExes: + // 0 - complete definition block + // 1 - comment string + // 2 - method name + // 3 - method parameters + + $methods = []; + for ($i = 0; $i < count($matches[0]); $i++) { + // List methods with parameters and comment + $methods[] = [ + 'name' => $matches[2][$i], + 'params' => trim($matches[3][$i]), + 'comment' => trim($matches[1][$i]) + ]; + } + + return [ + 'methods' => $methods, + 'use' => $use + ]; + } + + protected function execute(InputInterface $input, OutputInterface $output) { + if (!CredentialManager::isConfigured()) + throw new \Exception("The 'cloudobjects' CLI tool must be installed and authorized."); + + $coid = COIDParser::fromString($input->getArgument('coid')); + + if (COIDParser::getType($coid) != COIDParser::COID_VERSIONED + && COIDParser::getType($coid) != COIDParser::COID_UNVERSIONED) + throw new \Exception("Invalid COID: ".(string)$coid); + + $name = COIDParser::getName($coid); + $version = COIDParser::getVersion($coid); + $fullName = isset($version) ? $name.".".$version : $name; + $invokable = $input->getOption('http-invokable'); + + if ($input->getOption('implements') != null) { + if ($invokable) + throw new \Exception("The 'implements' option cannot be used with 'http-invokable'."); + + $implements = $input->getOption('implements'); + $output->writeln("Fetching configuration for ".$implements." ..."); + $interfaceData = $this->getAndValidateInterfaceConfig($implements); + } + + if (!file_exists($fullName.'.xml') || $input->getOption('force')) { + // Create RDF configuration file + $content = "\n" + . "\n" + . "\n" + . " \n"; + + // Mark as public if option was defined + if ($input->getOption('public')) + $content .= " \n" + . " \n"; + else + $content .= " \n"; + + if (isset($implements)) + $content .= " \n"; + $content .=" \n" + . ""; + file_put_contents($fullName.'.xml', $content); + $output->writeln("Written ".$fullName.".xml."); + } else { + // RDF configuration file already exists + $output->writeln($fullName.".xml already exists."); + } + + if (!file_exists($fullName.'.php') || $input->getOption('force') !== false) { + $useStatements = []; + $classVariables = []; + $constructor = ''; + + if ($input->getOption('autowire') != null) { + $fullyQualifiedClassname = $input->getOption('autowire'); + $validator = new ClassValidator; + if (!$validator->isWhitelisted($fullyQualifiedClassname)) + throw new PhpMAEException('Cannot autowire non-whitelisted type <'.$fullyQualifiedClassname.'>.'); + $useStatements[] = $fullyQualifiedClassname; + $className = substr($fullyQualifiedClassname, strrpos($fullyQualifiedClassname, '\\') + 1); + $variableName = strtolower($className[0]).substr($className, 1); + $classVariables[] = $variableName; + $constructor = " public function __construct(".$className." \$".$variableName.") {\n" + . " \$this->".$variableName." = \$".$variableName.";\n" + . " }\n\n"; + } + + if (isset($implements)) { + // Retrieve interface code + $output->writeln("Fetching code for ".$interfaceData['coid']." ..."); + $parsedInterface = $this->getAndParseInterfaceCode($interfaceData['coid'], $interfaceData['filename']); + // Add use statements + foreach ($parsedInterface['use'] as $u) + $useStatements[] = $u; + } + + // Create PHP source file + $content = " 0) + $content .= "\n"; + + $content .= "/**\n" + . " * Implementation for ".(string)$coid."\n" + . (isset($implements) ? " * Using interface ".$interfaceData['coid']."\n" : "") + . " */\n" + . "class ".$name." ".(isset($implements) ? "implements ".$interfaceData['classname']." " : "") + . "{\n" + . "\n"; + foreach ($classVariables as $v) + $content .= " private \$".$v.";\n"; + if (count($classVariables) > 0) + $content .= "\n" + . $constructor; + + if (isset($implements)) { + // Build PHP template with interface methods + foreach ($parsedInterface['methods'] as $m) { + $content .= ($m['comment'] != "" ? " /**\n ".$m['comment']."\n */\n" : "") + . " public function ".$m['name']."(".$m['params'].") {\n" + . " // TODO: Implement this\n" + . " }\n\n"; + } + } else { + // Build PHP template for standard or HTTP-invokable class + $content .= ($invokable + ? " public function __invoke(\$args) {\n // TODO: Add your code here\n }\n" + : " // TODO: Add methods here ...\n") + . "\n"; + } + + $content .= "}"; + + file_put_contents($fullName.'.php', $content); + $output->writeln("Written ".$fullName.".php."); + } else { + $output->writeln($fullName.".php already exists."); + } + + if ($input->getOption('confjob')) { + $output->writeln("Calling cloudobjects ..."); + passthru("cloudobjects configuration-job:create ".$fullName.".xml"); + } + } + +} diff --git a/classes/Commands/ClassDeployCommand.php b/classes/Commands/ClassDeployCommand.php new file mode 100644 index 0000000..4e38ec0 --- /dev/null +++ b/classes/Commands/ClassDeployCommand.php @@ -0,0 +1,72 @@ +setName('class:deploy') + ->setDescription('Validates a class for the phpMAE and uploads it into CloudObjects. Updates the configuration if necessary.') + ->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->requireCloudObjectsCLI(); + + $this->parse($input->getArgument('coid')); + $this->assertRDF(); + if (!in_array('coid://phpmae.dev/Class', $this->rdfTypes) + && !in_array('coid://phpmae.dev/HTTPInvokableClass', $this->rdfTypes)) + throw new \Exception("Object does not have a valid class type."); + $this->assertPHPExists(); + + // Running validator + $validator = new ClassValidator; + $validator->validate(file_get_contents($this->fullName.'.php'), + $this->coid, $this->getAdditionalTypes()); + $output->writeln("Validated successfully, calling cloudobjects ..."); + + passthru("cloudobjects attachment:put ".(string)$this->coid." ".$this->fullName.".php"); + + // Updates configuration if necessary + if ($this->ensureFilenameInConfig($output, false)) + $this->createConfigurationJob($output); + + // Print URL so developer can easily access it + $output->writeln(""); + $visibility = isset($object['coid://cloudobjects.io/isVisibleTo']) + ? $object['coid://cloudobjects.io/isVisibleTo'][0]['value'] + : 'coid://cloudobjects.io/Vendor'; + $path = $this->coid->getHost().$this->coid->getPath(); + + switch ($visibility) { + case "coid://cloudobjects.io/Private": + $output->writeln("Private URL for Class Execution:"); + $output->writeln("➡️ http://YOUR_PHPMAE_INSTANCE/".$path); + break; + case "coid://cloudobjects.io/Public": + $output->writeln("Public URL for Class Execution:"); + $output->writeln("➡️ https://phpmae.dev/".$path); + break; + case "coid://cloudobjects.io/Vendor": + $output->writeln("Authenticated URL for Class Execution:"); + $output->writeln("➡️ https://".$this->coid->getHost().":SECRET@phpmae.dev/".$path); + $output->writeln(""); + $output->writeln("To get value for SECRET:"); + $output->writeln("➡️ cloudobjects domain-providers:secret ".$this->coid->getHost()." phpmae.dev"); + break; + } + $output->writeln(""); + } + +} diff --git a/classes/Commands/ClassTestEnvCommand.php b/classes/Commands/ClassTestEnvCommand.php new file mode 100644 index 0000000..f956349 --- /dev/null +++ b/classes/Commands/ClassTestEnvCommand.php @@ -0,0 +1,98 @@ +container)) { + $this->container = TestEnvironmentManager::getContainer(); + } + + return $this->container; + } + + protected function configure() { + $this->setName('class:testenv') + ->setDescription('Uploads a class into the current test environment.') + ->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.') + ->addOption('config', null, InputOption::VALUE_NONE, 'Upload the local configuration of the class to the test environment instead of retrieving it from CloudObjects.') + ->addOption('watch', null, InputOption::VALUE_NONE, 'Keep watching for changes of the file and reupload automatically.'); + } + + private function upload(OutputInterface $output) { + try { + $this->validator->validate(file_get_contents($this->phpFileName), + $this->coid, $this->getAdditionalTypes()); + $this->getContainer()->get('testenv.client')->put('/uploadTestenv?type=source&coid='.urlencode((string)$this->coid), [ + 'body' => file_get_contents($this->phpFileName) + ]); + $output->writeln('File uploaded successfully!'); + } catch (BadResponseException $e) { + if ($e->getResponse()->getContentType()=='application/json') { + $errorMessage = $e->getResponse()->json(); + $output->writeln(''.$errorMessage['error_code'].': ' + .$errorMessage['error_message']); + } else + $output->writeln(''.get_class($e).' '.(string)$e->getResponse()); + } catch (\Exception $e) { + $output->writeln(''.get_class($e).' '.$e->getMessage()); + } + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->requireCloudObjectsCLI(); + + $container = $this->getContainer(); + if (!$container->has('testenv.client')) + throw new \Exception("No test environment configured."); + + $this->parse($input->getArgument('coid')); + $this->assertRDF(); + if (!in_array('coid://phpmae.dev/Class', $this->rdfTypes) + && !in_array('coid://phpmae.dev/HTTPInvokableClass', $this->rdfTypes)) + throw new \Exception("Object does not have a valid class type."); + $this->assertPHPExists(); + + // Print URL so developer can easily access it + $output->writeln("Test Environment Base URL for Class Execution:"); + $output->writeln("➡️ ".$container->get('testenv.url').$this->coid->getHost() + .$this->coid->getPath()); + $output->writeln(""); + + if ($input->getOption('config')) { + // Upload configuration before uploading implementation + $this->ensureFilenameInConfig($output); + $container->get('testenv.client')->put('/uploadTestenv?type=config&coid='.urlencode((string)$this->coid), [ + 'body' => file_get_contents($this->xmlFileName) + ]); + $output->writeln('Configuration uploaded successfully!'); + } + + $this->validator = new ClassValidator; + $this->upload($output); + + if ($input->getOption('watch')) { + $cmd = $this; + $this->watchPHPFile($output, function() use ($cmd, $output) { + $cmd->upload($output); + }); + } + } + +} diff --git a/classes/Commands/ClassTestEnvRPCCommand.php b/classes/Commands/ClassTestEnvRPCCommand.php new file mode 100644 index 0000000..a2ba5d7 --- /dev/null +++ b/classes/Commands/ClassTestEnvRPCCommand.php @@ -0,0 +1,73 @@ +container)) { + $this->container = TestEnvironmentManager::getContainer(); + } + + return $this->container; + } + + protected function configure() { + $this->setName('class:testenv-rpc') + ->setDescription('Executes a JSON-RPC method call on a class in the current test environment.') + ->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.') + ->addArgument('method', InputArgument::REQUIRED, 'The method name.') + ->addArgument('parameters', InputArgument::IS_ARRAY, 'The parameters for the method.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->requireCloudObjectsCLI(); + + $container = $this->getContainer(); + if (!$container->has('testenv.client')) + throw new \Exception("No test environment configured."); + + $this->parse($input->getArgument('coid')); + $this->assertRDF(); + if (!in_array('coid://phpmae.dev/Class', $this->rdfTypes) + && !in_array('coid://phpmae.dev/HTTPInvokableClass', $this->rdfTypes)) + throw new \Exception("Object does not have a valid class type."); + $this->assertPHPExists(); + + // Create JSON-RPC Client + $client = new Client($container->get('testenv.url') + .$this->coid->getHost().$this->coid->getPath()); + + // Check parameters and load files + $parameters = []; + foreach ($input->getArgument('parameters') as $p) { + if ($p[0] == '@') + $parameters[] = @file_get_contents(substr($p, 1)); + else + $parameters[] = $p; + } + + // Make RPC Call + if ($client->call($input->getArgument('method'), $parameters) + && isset($client->result)) + $output->writeln(is_string($client->result) + ? $client->result + : json_encode($client->result, JSON_PRETTY_PRINT)); + else + $output->writeln("RPC has failed!"); + } + +} diff --git a/classes/Commands/ClassValidateCommand.php b/classes/Commands/ClassValidateCommand.php new file mode 100644 index 0000000..400aa14 --- /dev/null +++ b/classes/Commands/ClassValidateCommand.php @@ -0,0 +1,57 @@ +setName('class:validate') + ->setAliases([ 'validate', 'v' ]) + ->setDescription('Validates a class for the phpMAE.') + ->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.') + ->addOption('watch', null, InputOption::VALUE_NONE, 'Keep watching for changes of the file and revalidate automatically.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->parse($input->getArgument('coid')); + $this->assertRDF(); + if (!in_array('coid://phpmae.dev/Class', $this->rdfTypes) + && !in_array('coid://phpmae.dev/HTTPInvokableClass', $this->rdfTypes)) + throw new \Exception("Object does not have a valid class type."); + $this->assertPHPExists(); + + // Running validator + $validator = new ClassValidator; + try { + $validator->validate(file_get_contents($this->phpFileName), + $this->coid, $this->getAdditionalTypes()); + $output->writeln("Validated successfully."); + } catch (\Exception $e) { + $output->writeln(''.get_class($e).' '.$e->getMessage()); + } + + if ($input->getOption('watch')) { + $cmd = $this; + $this->watchPHPFile($output, function() use ($validator, $cmd, $output) { + try { + $validator->validate(file_get_contents($cmd->phpFileName), + $this->coid, $this->getAdditionalTypes()); + $output->writeln("Validated successfully."); + } catch (\Exception $e) { + $output->writeln(''.get_class($e).' '.$e->getMessage()); + } + }); + } + } + +} diff --git a/classes/Commands/DependenciesAddAttachmentCommand.php b/classes/Commands/DependenciesAddAttachmentCommand.php new file mode 100644 index 0000000..0a8cd2f --- /dev/null +++ b/classes/Commands/DependenciesAddAttachmentCommand.php @@ -0,0 +1,63 @@ +setName('dependencies:add-attachment') + ->setDescription('Adds an attachment to the specification of a class.') + ->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.') + ->addArgument('filename', InputArgument::REQUIRED, 'The name of the file that should be attached.') + ->addOption('upload', null, InputOption::VALUE_NONE, 'Calls "cloudobjects" to actually upload the file to CloudObjects.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->requireCloudObjectsCLI(); + + $this->parse($input->getArgument('coid-target')); + $this->assertRDF(); + $this->assertPHPExists(); + + $filename = $input->getArgument('filename'); + if (!file_exists($filename)) + throw new \Exception("File not found: ".$filename); + + $fileUri = "file:///".basename($filename); + + // Edit configuration + $found = false; + $object = $this->index[(string)$this->coid]; + if (isset($object['coid://phpmae.dev/usesAttachedFile'])) { + foreach ($object['coid://phpmae.dev/usesAttachedFile'] as $o) { + if ($o['type'] != 'uri') continue; + if ($o['value'] == $fileUri) $found = true; + } + if (!$found) + $object['coid://phpmae.dev/usesAttachedFile'][] = [ 'type' => 'uri', 'value' => $fileUri ]; + } else + $object['coid://phpmae.dev/usesAttachedFile'] = [[ 'type' => 'uri', 'value' => $fileUri ]]; + + // Persist configuration + if (!$found) { + $this->index[(string)$this->coid] = $object; + $this->updateRDFLocally($output); + } + + if ($input->getOption('upload') !== null) { + $output->writeln("Calling cloudobjects ..."); + passthru("cloudobjects attachment:put ".(string)$this->coid." ".$filename); + } + } + +} diff --git a/classes/Commands/DependenciesAddClassCommand.php b/classes/Commands/DependenciesAddClassCommand.php new file mode 100644 index 0000000..9b43230 --- /dev/null +++ b/classes/Commands/DependenciesAddClassCommand.php @@ -0,0 +1,78 @@ +setName('dependencies:add-class') + ->setDescription('Adds a class dependency to the specification of a class.') + ->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.') + ->addOption('key', null, InputArgument::OPTIONAL, 'The key for dependency injection. Randomly generated if not provided.', null) + ->addArgument('coid-class', InputArgument::REQUIRED, 'The COID of the dependency class.'); + + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->requireCloudObjectsCLI(); + + $this->parse($input->getArgument('coid-target')); + $this->dependencyPrecheck(); + + // Check Class + $coidClass = COIDParser::fromString($input->getArgument('coid-class')); + if (COIDParser::getType($coidClass) != COIDParser::COID_VERSIONED + && COIDParser::getType($coidClass) != COIDParser::COID_UNVERSIONED) + throw new \Exception("Invalid COID: ".$coid); + + // Checking type + $output->writeln("Fetching configuration for ".(string)$coidClass." ..."); + $this->getObjectAndAssertType((string)$coidClass, 'coid://phpmae.dev/Class'); + + // Add dependency + $this->addDependency( + $input->getOption('key') ? $input->getOption('key') : uniqid('class-'), + 'coid://phpmae.dev/ClassDependency', + [ + 'coid://phpmae.dev/hasClass' => [ + [ 'type' => 'uri', 'value' => (string)$coidClass ] + ] + ], + $input, $output + ); + + // Print documentation + $className = COIDParser::getName($coidClass); + $key = $input->getOption('key') ? $input->getOption('key') + : strtolower($className[0]).substr($className, 1); + $output->writeln(""); + $output->writeln("Use your class dependency:"); + $output->writeln(""); + $output->writeln("1) Add the class ".$className." to your constructor parameters."); + $output->writeln("2) Assign the class to \$this->".$key."."); + $output->writeln(""); + $output->writeln(" private \$".$key.";"); + $output->writeln(""); + $output->writeln(" public function __construct(".$className." \$".$key.") {"); + $output->writeln(" \$this->".$key." = \$".$key.";"); + $output->writeln(" }"); + $output->writeln(""); + $output->writeln("3) Use \$this->".$key." wherever required."); + $output->writeln(""); + $output->writeln("You can find the documentation for the available class methods on this page:"); + $output->writeln("➡️ https://cloudobjects.io/".$coidClass->getHost().$coidClass->getPath()); + $output->writeln(""); + } + +} diff --git a/classes/Commands/DependenciesAddStaticTextCommand.php b/classes/Commands/DependenciesAddStaticTextCommand.php new file mode 100644 index 0000000..02b9a94 --- /dev/null +++ b/classes/Commands/DependenciesAddStaticTextCommand.php @@ -0,0 +1,63 @@ +setName('dependencies:add-text') + ->setDescription('Adds a static text dependency to the specification of a class.') + ->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.') + ->addArgument('key', InputArgument::REQUIRED, 'The key for dependency injection.') + ->addArgument('value', InputArgument::REQUIRED, 'The text value.'); + + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->requireCloudObjectsCLI(); + + $this->parse($input->getArgument('coid-target')); + $this->assertRDF(); + $this->dependencyPrecheck(); + + // Add dependency + $this->addDependency( + $input->getArgument('key'), + 'coid://phpmae.dev/StaticTextDependency', + [ + 'coid://phpmae.dev/hasValue' => [ + [ 'type' => 'literal', 'value' => $input->getArgument('value') ] + ] + ], + $input, $output + ); + + // Print documentation + $key = $input->getArgument('key'); + $output->writeln(""); + $output->writeln("Use your static text dependency:"); + $output->writeln(""); + $output->writeln("1) Make sure you have access to the dependency injection container by adding the container to your class constructor."); + $output->writeln("2) Request the value string from the container using the key \"".$key."\"."); + $output->writeln(""); + $output->writeln(" private \$".$key.";"); + $output->writeln(""); + $output->writeln(" public function __construct(\Psr\Container\ContainerInterface \$container) {"); + $output->writeln(" \$this->".$key." = \$container->get('".$key."');"); + $output->writeln(" }"); + $output->writeln(""); + $output->writeln("3) Use \$this->".$key." wherever required."); + $output->writeln(""); + } + +} diff --git a/classes/Commands/DependenciesAddTemplateCommand.php b/classes/Commands/DependenciesAddTemplateCommand.php new file mode 100644 index 0000000..d979d4d --- /dev/null +++ b/classes/Commands/DependenciesAddTemplateCommand.php @@ -0,0 +1,75 @@ +setName('dependencies:add-template') + ->setDescription('Adds a Twig template dependency to the specification of a class.') + ->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.') + ->addArgument('key', InputArgument::REQUIRED, 'The key for dependency injection.') + ->addArgument('filename', InputArgument::REQUIRED, 'The filename for the Twig template.') + ->addOption('upload', null, InputOption::VALUE_NONE, 'Calls "cloudobjects" to actually upload the template file to CloudObjects.'); + + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->requireCloudObjectsCLI(); + + $this->parse($input->getArgument('coid-target')); + $this->dependencyPrecheck(); + + // Check filename + $filename = $input->getArgument('filename'); + if (!file_exists($filename)) + throw new \Exception("File not found: ".$filename); + + // Upload file if requested + if ($input->getOption('upload')) { + $output->writeln("Calling cloudobjects for file upload ..."); + passthru("cloudobjects attachment:put ".(string)$this->coid." ".$filename); + } + + // Add dependency + $this->addDependency( + $input->getArgument('key'), + 'coid://phpmae.dev/TwigTemplateDependency', + [ + 'coid://phpmae.dev/usesAttachedTwigFile' => [ + [ 'type' => 'uri', 'value' => "file:///".basename($filename) ] + ] + ], + $input, $output + ); + + // Print documentation + $key = $input->getArgument('key'); + $output->writeln(""); + $output->writeln("Use your Twig template dependency:"); + $output->writeln(""); + $output->writeln("1) Make sure you have access to the dependency injection container by adding the container to your class constructor."); + $output->writeln("2) Request the template from the container using the key \"".$key."\"."); + $output->writeln(""); + $output->writeln(" private \$".$key."Template;"); + $output->writeln(""); + $output->writeln(" public function __construct(\Psr\Container\ContainerInterface \$container) {"); + $output->writeln(" \$this->".$key."Template = \$container->get('".$key."');"); + $output->writeln(" }"); + $output->writeln(""); + $output->writeln("3) Render your template by calling \$this->".$key."Template->render(\$context)."); + $output->writeln(""); + } + +} diff --git a/classes/Commands/DependenciesAddWebAPICommand.php b/classes/Commands/DependenciesAddWebAPICommand.php new file mode 100644 index 0000000..df8003c --- /dev/null +++ b/classes/Commands/DependenciesAddWebAPICommand.php @@ -0,0 +1,72 @@ +setName('dependencies:add-webapi') + ->setDescription('Adds a dependency to the specification of a class.') + ->addArgument('coid-target', InputArgument::REQUIRED, 'The COID of the target class.') + ->addArgument('key', InputArgument::REQUIRED, 'The key for dependency injection.') + ->addArgument('coid-webapi', InputArgument::REQUIRED, 'The COID of the Web API.'); + + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->requireCloudObjectsCLI(); + + $this->parse($input->getArgument('coid-target')); + $this->dependencyPrecheck(); + + // Check Web API + $coidWebAPI = COIDParser::fromString($input->getArgument('coid-webapi')); + if (COIDParser::getType($coidWebAPI) != COIDParser::COID_VERSIONED + && COIDParser::getType($coidWebAPI) != COIDParser::COID_UNVERSIONED) + throw new \Exception("Invalid COID: ".$coid); + + // Checking type + $output->writeln("Fetching configuration for ".(string)$coidWebAPI." ..."); + $this->getObjectAndAssertType((string)$coidWebAPI, 'coid://webapis.co-n.net/HTTPEndpoint'); + + // Add dependency + $this->addDependency( + $input->getArgument('key'), + 'coid://phpmae.dev/WebAPIDependency', + [ + 'coid://phpmae.dev/hasAPI' => [ + [ 'type' => 'uri', 'value' => (string)$coidWebAPI ] + ] + ], + $input, $output + ); + + // Print documentation + $key = $input->getArgument('key'); + $output->writeln(""); + $output->writeln("Use your WebAPI dependency:"); + $output->writeln(""); + $output->writeln("1) Make sure you have access to the dependency injection container by adding the container to your class constructor."); + $output->writeln("2) Request an API client from the container using the key \"".$key."\"."); + $output->writeln(""); + $output->writeln(" private \$".$key."Api;"); + $output->writeln(""); + $output->writeln(" public function __construct(\Psr\Container\ContainerInterface \$container) {"); + $output->writeln(" \$this->".$key."Api = \$container->get('".$key."');"); + $output->writeln(" }"); + $output->writeln(""); + $output->writeln("3) Make API requests in your class by calling methods on \$this->".$key."Api."); + $output->writeln(""); + } + +} diff --git a/classes/Commands/InterfaceCreateCommand.php b/classes/Commands/InterfaceCreateCommand.php new file mode 100644 index 0000000..7ba2e00 --- /dev/null +++ b/classes/Commands/InterfaceCreateCommand.php @@ -0,0 +1,84 @@ +setName('interface:create') + ->setDescription('Create a new interface for the phpMAE.') + ->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.') + ->addOption('force', 'f', InputOption::VALUE_OPTIONAL, 'Forces new object creation and replaces existing files.', false) + ->addOption('confjob', null, InputOption::VALUE_OPTIONAL, 'Calls "cloudobjects" to create a configuration job for the new interface.', false); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + if (!CredentialManager::isConfigured()) + throw new \Exception("The 'cloudobjects' CLI tool must be installed and authorized."); + + $coid = COIDParser::fromString($input->getArgument('coid')); + + if (COIDParser::getType($coid)!=COIDParser::COID_VERSIONED + && COIDParser::getType($coid)!=COIDParser::COID_UNVERSIONED) + throw new \Exception("Invalid COID: ".(string)$coid); + + $name = COIDParser::getName($coid); + $version = COIDParser::getVersion($coid); + $fullName = isset($version) ? $name.".".$version : $name; + + if (!file_exists($fullName.'.xml') || $input->getOption('force') !== false) { + // Create RDF configuration file + $content = "\n" + . "\n" + . "\n" + . " \n" + . " \n" + . " \n" + . ""; + file_put_contents($fullName.'.xml', $content); + $output->writeln("Written ".$fullName.".xml."); + } else { + // RDF configuration file already exists + $output->writeln($fullName.".xml already exists."); + } + + if (!file_exists($fullName.'.php') || $input->getOption('force') !== false) { + // Create PHP source file + $content = "writeln("Written ".$fullName.".php."); + } else { + $output->writeln($fullName.".php already exists."); + } + + if ($input->getOption('confjob') !== false) { + $output->writeln("Calling cloudobjects ..."); + passthru("cloudobjects configuration-job:create ".$fullName.".xml"); + } + } + +} diff --git a/classes/Commands/InterfaceDeployCommand.php b/classes/Commands/InterfaceDeployCommand.php new file mode 100644 index 0000000..4ae4ba4 --- /dev/null +++ b/classes/Commands/InterfaceDeployCommand.php @@ -0,0 +1,50 @@ +setName('interface:deploy') + ->setDescription('Validates an interface for the phpMAE and uploads it into CloudObjects. Updates the configuration if necessary.') + ->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->parse($input->getArgument('coid')); + $this->assertRDF(); + if (!in_array('coid://phpmae.dev/Interface', $this->rdfTypes)) + throw new \Exception("Object does not have athevalid interface type."); + $this->assertPHPExists(); + + // Running validator + $validator = new ClassValidator(); + $validator->validateInterface(file_get_contents($this->fullName.'.php'), $this->coid); + $output->writeln("Validated successfully, calling cloudobjects ..."); + + passthru("cloudobjects attachment:put ".(string)$this->coid." ".$this->fullName.".php"); + + // Updates configuration if necessary + if ($this->ensureFilenameInConfig($output, true)) { + $this->createConfigurationJob($output); + } + + // Print URL so developer can easily access it + $output->writeln(""); + $visibility = isset($object['coid://cloudobjects.io/isVisibleTo']) + ? $object['coid://cloudobjects.io/isVisibleTo'][0]['value'] + : 'coid://cloudobjects.io/Vendor'; + $path = $this->coid->getHost().$this->coid->getPath(); + } + +} diff --git a/classes/Commands/InterfaceValidateCommand.php b/classes/Commands/InterfaceValidateCommand.php new file mode 100644 index 0000000..2ca61ee --- /dev/null +++ b/classes/Commands/InterfaceValidateCommand.php @@ -0,0 +1,53 @@ +setName('interface:validate') + ->setDescription('Validates an interface for the phpMAE.') + ->addArgument('coid', InputArgument::REQUIRED, 'The COID of the object.') + ->addOption('watch', null, InputOption::VALUE_OPTIONAL, 'Keep watching for changes of the file and revalidate automatically.', null); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $this->parse($input->getArgument('coid')); + $this->assertRDF(); + if (!in_array('coid://phpmae.dev/Interface', $this->rdfTypes)) + throw new \Exception("Object does not have the valid interface type."); + $this->assertPHPExists(); + + // Running validator + $validator = new ClassValidator; + try { + $validator->validateInterface(file_get_contents($this->phpFileName), $this->coid); + $output->writeln("Validated successfully."); + } catch (\Exception $e) { + $output->writeln(''.get_class($e).' '.$e->getMessage()); + } + + if ($input->getOption('watch') !== null) { + $cmd = $this; + $this->watchPHPFile($output, function() use ($validator, $cmd, $output) { + try { + $validator->validateInterface(file_get_contents($cmd->phpFileName), $this->coid); + $output->writeln("Validated successfully."); + } catch (\Exception $e) { + $output->writeln(''.get_class($e).' '.$e->getMessage()); + } + }); + } + } + +} diff --git a/classes/Commands/TestEnvironmentStartCommand.php b/classes/Commands/TestEnvironmentStartCommand.php new file mode 100644 index 0000000..e34293e --- /dev/null +++ b/classes/Commands/TestEnvironmentStartCommand.php @@ -0,0 +1,54 @@ +setName('testenv:start') + ->setDescription('Starts a local test environment.') + ->addOption('port', null, InputOption::VALUE_OPTIONAL, 'Use this port for test environment.', 9000) + ->addOption('host', null, InputOption::VALUE_OPTIONAL, 'Bind test environment to this host.', '127.0.0.1'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + if (!CredentialManager::isConfigured()) + throw new \Exception("The 'cloudobjects' CLI tool must be installed and authorized."); + + $port = $input->getOption('port'); + $host = $input->getOption('host'); + + TestEnvironmentManager::setTestEnvironment('http://localhost:'.$port.'/'); + $output->writeln('Local webserver started on port '.$port.'.'); + $phar = \Phar::running(); + if (!$phar || $phar == "") { + // Run extracted version + $dir = realpath(__DIR__."/../../web/"); + passthru('cd '.$dir.'; php -S '.$host.':'.$port.' index.php'); + } else { + // Run from phar + if (strpos($phar, '.phar') !== false) { + // Run directly + passthru('php -S '.$host.':'.$port.' '.$phar.'/web/index.php'); + } else { + // Create copy with .phar extension because PHP might not recognize the file otherwise + $pharCp = sys_get_temp_dir().DIRECTORY_SEPARATOR.'phpmae.phar'; + copy(substr($phar, 7), $pharCp); + passthru('php -S '.$host.':'.$port.' phar://'.$pharCp.'/web/index.php'); + die("THRU!"); + } + } + } + +} diff --git a/classes/ConfigLoader.php b/classes/ConfigLoader.php new file mode 100644 index 0000000..177d8d4 --- /dev/null +++ b/classes/ConfigLoader.php @@ -0,0 +1,59 @@ +validSources = $validSources; + $this->retriever = $retriever; + $this->reader = new NodeReader([]); + } + + /** + * Get the value for a key, trying the sources in the order given by priorities. + */ + public function get($key, $priorities, $default = null) { + foreach ($priorities as $p) { + if (isset($this->validSources[$p])) { + $object = $this->retriever->getObject($this->validSources[$p]); + if (!isset($object)) + continue; + } else + if (substr($p, -10) == '.namespace' && isset($this->validSources[substr($p, 0, -10)])) { + $object = $this->retriever->getObject( + COIDParser::getNamespaceCOID($this->validSources[substr($p, 0, -10)])); + if (!isset($object)) + continue; + } + if (!isset($object)) + continue; + $value = $this->reader->getFirstValueString($object, $key); + if (isset($value)) + return $value; + } + + return $default; // not found + } + +} diff --git a/classes/Configurator.php b/classes/Configurator.php new file mode 100644 index 0000000..8353e2a --- /dev/null +++ b/classes/Configurator.php @@ -0,0 +1,73 @@ + 'file', + 'cache_provider.file.directory' => $config['cache_dir'] . '/config', + 'static_config_path' => $config['uploads_dir'] . '/config', + 'logger' => DI\get(Logger::class) + ]; + + if (!isset($config['co.auth_ns']) && CredentialManager::isConfigured()) { + // Access Object API via Account Gateway using local developer account + $objectRetrieverDefinition->constructor($orConstructorParameters) + ->method('setClient', function() { + return CredentialManager::getAccountContext()->getClient(); + }, '/ws/'); + } else { + // Access Object API with specified namespace credentials + $objectRetrieverDefinition->constructor(array_merge([ + 'auth_ns' => $config['co.auth_ns'], + 'auth_secret' => $config['co.auth_secret'], + ], $orConstructorParameters)); + } + + // Create Dependency Injection Container + $builder = new DI\ContainerBuilder(); + $builder->addDefinitions($config); + $builder->addDefinitions([ + Logger::class => function(ContainerInterface $config) { + $logger = new Logger('CO'); + switch ($config->get('log.target')) { + case "none": + $logger->pushHandler(new \Monolog\Handler\NullHandler); + break; + case "errorlog": + $logger->pushHandler(new \Monolog\Handler\ErrorLogHandler(0, $config->get('log.level'))); + break; + default: + throw new \Exception("Invalid log.target!"); + } + return $logger; + }, + ObjectRetriever::class => $objectRetrieverDefinition, + ObjectRetrieverPool::class => DI\autowire() + ->constructorParameter('baseHostname', @$config['co.auth_ns']) + ->constructorParameter('options', [ + 'cache_provider' => 'file', + 'cache_provider.file.directory' => $config['cache_dir'] . '/config', + 'static_config_path' => $config['uploads_dir'] . '/config', + 'logger' => DI\get(Logger::class) + ]) + ]); + + $builder->enableCompilation($config['cache_dir']); + return $builder->build(); + } + +} \ No newline at end of file diff --git a/classes/CredentialManager.php b/classes/CredentialManager.php new file mode 100644 index 0000000..2a2d4ab --- /dev/null +++ b/classes/CredentialManager.php @@ -0,0 +1,36 @@ +sandbox = $sandbox; + } + + public function leaveNode(Node $node) { + if ($node instanceof Node\Expr\FuncCall) { + if ($node->name instanceof Node\Expr\Variable) { + $this->sandbox->validationError("Sandboxed code attempted to call a variable method!", 0, $node); + } + } + } + +} \ No newline at end of file diff --git a/classes/DI/DependencyInjector.php b/classes/DI/DependencyInjector.php new file mode 100644 index 0000000..6c2d861 --- /dev/null +++ b/classes/DI/DependencyInjector.php @@ -0,0 +1,316 @@ +retrieverPool = $retrieverPool; + $this->classRepository = $classRepository; + $this->container = $container; + } + + /** + * Checks whether the request comes from a CloudObjects Account Gateway and, + * if so, configures an AccountContext for the class to use. + */ + private function configureAccountGateway(RequestInterface $request) { + $definitions = []; + + if ($request->hasHeader('C-AAUID') + && $request->hasHeader('C-Access-Token')) { + + $definitions[AccountContext::class] = function() use ($request) { + $context = AccountContext::fromPsrRequest($request); + + if ($this->container->get('agws.data_cache') == 'file') { + // Enable filesystem cache for account data + $cache = new FilesystemCache($this->container->get('cache_dir') . '/acct'); + $context->getDataLoader()->setCache($cache); + } + + return $context; + }; + } + + return $definitions; + } + + /** + * Get all dependencies for injection. + * + * @param Node $object The object representing the PHP class. + * @param array $additionalDefinitions Additional definitions to add to the container + */ + public function getDependencies(Node $object, array $additionalDefinitions = []) { + $reader = new NodeReader([ + 'prefixes' => [ 'phpmae' => 'coid://phpmae.dev/' ] + ]); + + $dependencies = $reader->getAllValuesNode($object, 'phpmae:hasDependency'); + + $objectCoid = new IRI($object->getId()); + $namespaceCoid = COIDParser::getNamespaceCOID($objectCoid); + if (substr($namespaceCoid->getHost(), -7) == '.phpmae') { + $originalHostname = $this->container->get(InteractiveRunController::class) + ->getOriginalHostname($namespaceCoid->getHost()); + $realNamespaceCoid = isset($originalHostname) ? new IRI('coid://'.$originalHostname) : $namespaceCoid; + } else + $realNamespaceCoid = $namespaceCoid; + + $definitions = [ + 'cookies' => \DI\create(ArrayCollection::class), + ObjectRetriever::class => function() use ($realNamespaceCoid) { + // Get or create an object retriever with the identity of the namespace of this object + return $this->retrieverPool->getObjectRetriever($realNamespaceCoid->getHost()); + }, + APIClientFactory::class => function(ContainerInterface $c) use ($realNamespaceCoid) { + // Get an API client factory + return new APIClientFactory($c->get(ObjectRetriever::class), $realNamespaceCoid); + }, + DynamicLoader::class => function() { + return new DynamicLoader($this->retrieverPool->getBaseObjectRetriever(), + $this->classRepository); + }, + ConfigLoader::class => function(ContainerInterface $c) use ($objectCoid, $additionalDefinitions) { + // Get a ConfigLoader that allows the class to read the configuration + // of various objects, including itself and additional definitions + $configDefinitions = [ + 'self' => $objectCoid + ]; + foreach ($additionalDefinitions as $key => $value) + if (is_a($value, IRI::class)) + $configDefinitions[$key] = $value; + + if (isset($additionalDefinitions[RequestInterface::class])) { + $request = $c->get(RequestInterface::class); + if ($request->hasHeader('C-Accessor')) + $configDefinitions['accessor'] = + new IRI($request->getHeaderLine('C-Accessor')); + } + + return new ConfigLoader($configDefinitions, $c->get(ObjectRetriever::class)); + }, + TwigTemplateFactory::class => function() use ($object) { + return new TwigTemplateFactory($this->classRepository + ->getCustomFilesCachePath($object)); + }, + CryptoHelper::class => function(ContainerInterface $c) use ($realNamespaceCoid) { + return new CryptoHelper($c->get(ObjectRetriever::class), $realNamespaceCoid); + }, + CacheInterface::class => function(ContainerInterface $c) use ($namespaceCoid) { + // Enable filesystem cache for custom data + return new CacheBridge( + new FilesystemCache($this->container->get('cache_dir') . '/custom'), + $namespaceCoid->getHost() + ); + }, + ResponseInterface::class => \DI\autowire(Response::class), + MailerInterface::class => function() use ($object, $realNamespaceCoid, $reader) { + // Find mailer DSN + $mailerDsn = $reader->getFirstValueString($object, 'phpmae:hasClassMailerDSN'); + + if (!isset($mailerDsn)) { + // Get DSN from namespace + $namespaceObject = $this->retrieverPool->getBaseObjectRetriever() + ->getObject($realNamespaceCoid); + $mailerDsn = $reader->getFirstValueString($namespaceObject, 'phpmae:hasGlobalMailerDSN'); + } + + if (!isset($mailerDsn)) + throw new PhpMAEException("Requires class or global mailer DSN."); + + if (substr($mailerDsn, 0, 5) != 'smtp:') + throw new PhpMAEException("Mailer DSN must start with smtp:."); + + $transport = Transport::fromDsn($mailerDsn); + return new Mailer($transport); + } + ]; + + $definitions = array_merge($definitions, $additionalDefinitions); + + if (isset($definitions[RequestInterface::class])) { + $definitions = array_merge($definitions, $this->configureAccountGateway($definitions[RequestInterface::class])); + } + + foreach ($dependencies as $d) { + $keyedDependency = null; + + if (!$d->getProperty('coid://phpmae.dev/hasKey')) + throw new PhpMAEException("<".$object->getId()."> has an invalid dependency: no key!"); + + if ($reader->hasType($d, 'phpmae:StaticTextDependency')) { + // Static Text Dependency + $value = $reader->getFirstValueString($d, 'phpmae:hasValue'); + if (!isset($value)) + throw new PhpMAEException("<".$object->getId()."> has an invalid dependency: StaticTextDependency without value!"); + + $keyedDependency = $value; + } else + if ($reader->hasType($d, 'phpmae:WebAPIDependency')) { + // Web API Dependency + $apiCoid = $reader->getFirstValueString($d, 'phpmae:hasAPI'); + if (isset($apiCoid)) { + // API is available to phpMAE, set up dependency + $keyedDependency = function(ContainerInterface $c) use ($apiCoid, $object) { + return $c->get(APIClientFactory::class) + ->getClientWithCOID(new IRI($apiCoid), true); + }; + } else { + // API might be a private API that wasn't shared with phpMAE, + // we accept the dependency for now and resolve it with a + // namespace-scoped retriever later + $lookupKey = $reader->getFirstValueString($d, 'phpmae:hasKey'); + $keyedDependency = function(ContainerInterface $c) use ($objectCoid, + $reader, $lookupKey, $realNamespaceCoid) { + + $object = $c->get(ObjectRetriever::class)->get($objectCoid); + $dependencies = $reader->getAllValuesNode($object, 'phpmae:hasDependency'); + foreach ($dependencies as $d) { + if ($reader->getFirstValueString($d, 'phpmae:hasKey') == $lookupKey) { + // Found dependency + $apiCoid = $reader->getFirstValueString($d, 'phpmae:hasAPI'); + if (!isset($apiCoid)) + throw new PhpMAEException("<".$object->getId()."> has an invalid dependency: WebAPIDependency without API!"); + + return $c->get(APIClientFactory::class) + ->getClientWithCOID(new IRI($apiCoid), true); + } + } + + throw new PhpMAEException("<".$object->getId()."> had problems during dependency resolution!"); + }; + } + } else + if ($reader->hasType($d, 'phpmae:ClassDependency')) { + // Class Dependency + $classCoid = $reader->getFirstValueIRI($d, 'phpmae:hasClass'); + if (!isset($classCoid)) + throw new PhpMAEException("<".$object->getId()."> has an invalid dependency: ClassDependency without class!"); + + // TODO: can we optimize this? only create dependency container in inject function + $dependencyContainer = $this->classRepository + ->createInstance($this->retrieverPool->getBaseObjectRetriever()->getObject($classCoid), null, [ 'callerClass' => $objectCoid ]); + $keyedDependency = function() use ($dependencyContainer) { + return $dependencyContainer->get(Engine::SKEY); + }; + + // Also add with classname to allow constructor autowiring + $definitions[$this->classRepository->coidToClassName($classCoid)] = $keyedDependency; + } else + if ($reader->hasType($d, 'phpmae:TwigTemplateDependency')) { + // Twig Template Dependency + $filename = $reader->getFirstValueString($d, 'phpmae:usesAttachedTwigFile'); + if (!isset($filename)) + throw new PhpMAEException("<".$object->getId()."> has an invalid dependency: TwigTemplateDependency without attachment!"); + + $keyedDependency = function() use ($object, $objectCoid, $filename) { + $content = $this->retrieverPool->getBaseObjectRetriever() + ->getAttachment($objectCoid, $filename); + $cachePath = $this->classRepository->getCustomFilesCachePath($object); + return new TwigTemplate($filename, $content, $cachePath); + }; + } else + throw new PhpMAEException("<".$object->getId()."> has an invalid dependency: unknown type!"); + + $definitions[$reader->getFirstValueString($d, 'phpmae:hasKey')] = $keyedDependency; + } + + $attachments = $reader->getAllValuesString($object, 'phpmae:usesAttachedFile'); + foreach ($attachments as $a) { + $filename = basename($a); + $definitions[$filename] = function() use ($objectCoid, $filename) { + $content = $this->retrieverPool->getBaseObjectRetriever() + ->getAttachment($objectCoid, $filename); + + if (substr($filename, -5) == '.json') + $content = json_decode($content, true); + + return $content; + }; + } + + if ($reader->hasProperty($object, 'phpmae:usesStaticAccountContext')) { + $accountDefinition = $reader->getFirstValueNode($object, 'phpmae:usesStaticAccountContext'); + if (!$reader->hasProperty($accountDefinition, 'phpmae:hasAAUID') + || !$reader->hasProperty($accountDefinition, 'phpmae:hasAccessToken')) + throw new PhpMAEException("Incomplete AccountContext definition."); + + $definitions[AccountContext::class] = function() use ($accountDefinition, $reader) { + return new AccountContext( + AAUIDParser::fromString($reader->getFirstValueString($accountDefinition, + 'phpmae:hasAAUID')), + $reader->getFirstValueString($accountDefinition, 'phpmae:hasAccessToken') + ); + }; + } + + return $definitions; + } + + /** + * Get a list of COIDs for class dependencies. + * + * @param Node $object The object representing the PHP class. + */ + public function getClassDependencyList(Node $object) { + $reader = new NodeReader([ + 'prefixes' => [ 'phpmae' => 'coid://phpmae.dev/' ] + ]); + + $dependencies = $reader->getAllValuesNode($object, 'phpmae:hasDependency'); + + $list = []; + + foreach ($dependencies as $d) { + if ($reader->hasType($d, 'phpmae:ClassDependency')) { + // Class Dependency + $classCoid = $reader->getFirstValueIRI($d, 'phpmae:hasClass'); + if (!isset($classCoid)) + throw new PhpMAEException("<".$object->getId()."> has an invalid dependency: ClassDependency without class!"); + + $list[] = $classCoid; + } + } + + return $list; + } + +} diff --git a/classes/DI/DynamicLoader.php b/classes/DI/DynamicLoader.php new file mode 100644 index 0000000..a3c3760 --- /dev/null +++ b/classes/DI/DynamicLoader.php @@ -0,0 +1,34 @@ +retriever = $retriever; + $this->repository = $repository; + } + + public function get($coid, RequestInterface $request = null) { + $object = $this->retriever->get($coid); + return isset($object) + ? $this->repository->createInstance($object, $request)->get(Engine::SKEY) + : null; + } + +} diff --git a/classes/DI/SandboxedContainer.php b/classes/DI/SandboxedContainer.php new file mode 100644 index 0000000..8126936 --- /dev/null +++ b/classes/DI/SandboxedContainer.php @@ -0,0 +1,31 @@ +container = $container; + } + + public function has($id) { + return $this->container->has($id); + } + + public function get($id) { + return $this->container->get($id); + } + +} diff --git a/classes/DI/WhitelistReflectionBasedAutowiring.php b/classes/DI/WhitelistReflectionBasedAutowiring.php new file mode 100644 index 0000000..c24493d --- /dev/null +++ b/classes/DI/WhitelistReflectionBasedAutowiring.php @@ -0,0 +1,23 @@ +objectRetriever = $objectRetriever; + $this->classRepository = $classRepository; + $this->slim = $slim; + $this->container = $container; + $this->reader = new NodeReader([ + 'prefixes' => [ + 'co' => 'coid://cloudobjects.io/', + 'phpmae' => 'coid://phpmae.dev/' + ] + ]); + + register_shutdown_function(function(ErrorHandler $handler) { + $handler->getErrorResponse(); + }, $errorHandler); // see: http://stackoverflow.com/questions/4410632/handle-fatal-errors-in-php-using-register-shutdown-function + } + + private function isObjectPublic() { + return ($this->reader->hasProperty($this->object, 'co:isVisibleTo') + && $this->reader->getFirstValueIRI($this->object, 'co:isVisibleTo') + ->equals(self::CO_PUBLIC) + && $this->reader->hasProperty($this->object, 'co:permitsUsageTo') + && $this->reader->getFirstValueIRI($this->object, 'co:permitsUsageTo') + ->equals(self::CO_PUBLIC)); + } + + private function getCORSMiddleware() { + $defaultConfig = [ + 'headers.allow' => [ 'Content-Type' ], + 'cache' => 600 + ]; + + if ($this->container->has('global_cors_origins') + && $this->container->get('global_cors_origins') == '*') + return new CorsMiddleware($defaultConfig); // every origin is allowed, globally + + if ($this->reader->getFirstValueString($this->object, 'phpmae:allowsCORSOrigin') == '*') + return new CorsMiddleware($defaultConfig); // every origin is allowed, by class + + $origins = $this->reader->getAllValuesString($this->object, 'phpmae:allowsCORSOrigin'); + + if ($this->container->has('global_cors_origins')) + $origins = array_merge($origins, explode('|', $this->container->get('global_cors_origins'))); + + if (count($origins) == 0 || trim($origins[0]) == '') + return null; // no CORS enabled + + return new CorsMiddleware(array_merge($defaultConfig, [ + 'origin' => $origins + ])); // configured CORS middleware + } + + private function getAuthenticationMiddleware() { + $authSchemes = explode('|', $this->container->get('client_authentication')); + if (in_array('none', $authSchemes)) + return null; // no authentication required + + if (in_array('none:public_only', $authSchemes) + && $this->isObjectPublic()) + return null; // no authentication required + + $object = $this->object; + return new HttpBasicAuthentication([ + 'secure' => !$this->container->has('client_authentication_must_be_secure') + || $this->container->get('client_authentication_must_be_secure'), + 'realm' => 'phpMAE', + 'authenticator' => function($args) use ($object, $authSchemes) { + $authenticated = false; + foreach ($authSchemes as $as) { + if (substr($as, 0, 14) == 'shared_secret:') { + $authResult = (SharedSecretAuthentication::verifyCredentials( + $this->objectRetriever, $args['user'], $args['password']) + == SharedSecretAuthentication::RESULT_OK); + if ($authResult != true) + continue; + + if (substr($as, 14) == 'runclass') + $authenticated = (substr($object->getId(), 7, strlen($args['user']) +1) == $args['user'].'/'); + else + $authenticated = (substr($as, 14) == 'coid://'.$args['user']); + } elseif (substr($as, 0, 4) != 'none') + throw new PhpMAEException("Unsupported authentication scheme!"); + + if ($authenticated == true) + break; + } + + return $authenticated; + } + ]); + } + + /** + * Executes an invokable class. + */ + private function executeInvokableClass(RequestInterface $request, $args = null) { + if (is_array($args) && count($args) > 0) { + $input = $args; + } else { + $input = $request->getParsedBody(); + if (!is_array($input)) + $input = []; + } + + set_time_limit($this->container->has('execution_time_limit') + ? $this->container->get('execution_time_limit') : self::CLASS_TIME_LIMIT); + $result = $this->runClass->get(self::SKEY)->__invoke($input); + + return $this->generateResponse($result); + } + + /** + * Generates an response with adequate Content Type based on the format of the content. + * @param mixed $content Content for the body of the response. + */ + public function generateResponse($content) { + $lowercaseContent = is_string($content) ? strtolower($content) : ''; + if (!isset($content)) + // Empty response + $response = new Response(204); + elseif (is_string($content) && (substr($lowercaseContent, 0, 5) == 'write($content); + elseif (is_string($content) && (substr($lowercaseContent, 0, 7) == 'http://' || substr($lowercaseContent, 0, 8) == 'https://')) + // Redirect response + $response = (new Response)->withRedirect($content); + elseif (is_string($content) || is_numeric($content)) + // Plain text response + $response = (new Response)->withHeader('Content-Type', 'text/plain')->write($content); + elseif (is_object($content) && in_array(ResponseInterface::class, class_implements($content))) + // Existing response to pass through + $response = $content; + else + // JSON response (default) + $response = (new Response)->withJson($content); + + // TODO: add support for XML + + // Add cookies if any + if (isset($this->runClass) && $this->runClass->has('cookies')) { + foreach ($this->runClass->get('cookies') as $cookie) { + if (is_a($cookie, SetCookie::class)) + $response = FigResponseCookies::set($response, $cookie); + } + } + + return $response; + } + + /** + * Executes a standard class using JSON-RPC. + */ + private function executeJsonRPC(RequestInterface $request) { + $transport = new JsonRPCTransport; + $server = new JsonRPCServer($this->runClass->get(self::SKEY), $transport); + set_time_limit($this->container->has('execution_time_limit') + ? $this->container->get('execution_time_limit') : self::CLASS_TIME_LIMIT); + $server->receive((string)$request->getBody()); + return $this->generateResponse($transport->getResponse()); + } + + /** + * Start execution of a request. + */ + public function execute(RequestInterface $request) { + $path = rtrim($request->getUri()->getBasePath().$request->getUri()->getPath(), '/'); + switch ($path) { + case "": + case "/": + // Display homepage + $file = ($this->container + ->get(InteractiveRunController::class) + ->isEnabled()) ? 'app.html' : 'app_disabled.html'; + + return $this->generateResponse(file_get_contents(__DIR__.'/../static/'.$file)); + case "/run": + // Run interactive code request + return $this->container + ->get(InteractiveRunController::class) + ->handle($request, $this); + case "/uploadTestenv": + // Upload into test environment (if enabled) + return $this->container + ->get(UploadController::class) + ->handle($request); + default: + if (file_exists(__DIR__.'/../static'.$path)) { + // Proxy for static files + $filename = realpath(__DIR__.'/../static'.$path); + $response = (new Response)->write(file_get_contents($filename)); + switch (pathinfo($filename, PATHINFO_EXTENSION)) { + case "css": + return $response->withHeader('Content-Type', 'text/css'); + case "js": + return $response->withHeader('Content-Type', 'application/javascript'); + default: + return $response; + } + + } + + $coid = COIDParser::fromString(substr($path, 1)); + $this->loadRunClass($coid, $request); + + // Process a standard request for a phpMAE class + $queue = [ + $this->getCORSMiddleware(), + $this->getAuthenticationMiddleware(), + $this + ]; + $relay = new Relay( + array_filter($queue, function ($q) { + return $q !== null; + }) + ); + return $relay->handle($request); + } + } + + /** + * Load a class to execute. + */ + public function loadRunClass(IRI $coid, RequestInterface $request = null) { + if (COIDParser::isValidCOID($coid) && COIDParser::getType($coid) != COIDParser::COID_ROOT) { + $this->object = $this->objectRetriever->get($coid); + if (!isset($this->object)) + throw new PhpMAEException("The object <" . (string)$coid . "> does not exist or this phpMAE instance is not allowed to access it."); + $this->runClass = $this->classRepository->createInstance($this->object, $request); + } else { + throw new PhpMAEException("You must provide a valid, non-root COID to specify the class for execution."); + } + } + + /** + * Specifies the class for execution in the engine. + */ + public function setRunClass(DI\SandboxedContainer $runClass) { + $this->runClass = $runClass; + } + + public function handle(ServerRequestInterface $request, $args = null): ResponseInterface { + try { + if (ClassValidator::isInvokableClass($this->runClass->get(self::SKEY))) { + // Run as invokable class + return $this->executeInvokableClass($request, $args); + } else { + // Run as RPC + // JsonRPC + return $this->executeJsonRPC($request); + } + } catch (\Exception $e) { + throw new PhpMAEException(get_class($e).": ".$e->getMessage()); + } + } + + /** + * Create main request and execute. + */ + public function run() { + set_time_limit(self::PREPARE_TIME_LIMIT); + + $env = new Environment($_SERVER); + $request = Request::createFromEnvironment($env); + + try { + $response = $this->execute($request); + } catch (PhpMAEException $e) { + // Create plain-text error response + $response = (new Response(500)) + ->withHeader('Content-Type', 'text/plain') + ->write($e->getMessage()); + } + + $this->slim->respond($response); + } +} \ No newline at end of file diff --git a/classes/ErrorHandler.php b/classes/ErrorHandler.php new file mode 100644 index 0000000..20ce4e8 --- /dev/null +++ b/classes/ErrorHandler.php @@ -0,0 +1,51 @@ +slim = $slim; + ini_set("display_errors", 0); + $this->setResponseGenerator(function($error, $object) { + $message = substr($error['message'], 0, strpos($error['message'], ' in /')); + return (new Response(500)) + ->withHeader('Content-Type', 'text/plain') + ->write("Error in implementation of <".$object->getId()."> at revision " + . $object->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue() + . ":\n".$message); + }); + } + + public function addMapping($filename, Node $object) { + $this->classMap[realpath($filename)] = $object; + } + + public function setResponseGenerator(callable $responseGenerator) { + $this->responseGenerator = $responseGenerator; + } + + public function getErrorResponse() { + $error = error_get_last(); + if ($error !== null && in_array($error['type'], [ E_ERROR, E_COMPILE_ERROR ]) + && isset($this->classMap[$error['file']])) { + + $response = call_user_func($this->responseGenerator, $error, $this->classMap[$error['file']]); + $this->slim->respond($response); + } + } + +} diff --git a/classes/Exceptions/PhpMAEException.php b/classes/Exceptions/PhpMAEException.php new file mode 100644 index 0000000..47779cd --- /dev/null +++ b/classes/Exceptions/PhpMAEException.php @@ -0,0 +1,13 @@ +cache = $cache; + $this->prefix = $prefix; + } + + public function get($key, $default = null) { + $value = $this->cache->fetch($this->prefix.$key); + if (is_array($value) && isset($value['container']) && isset($value['body']) + && is_object($value['container']) && is_a($value['container'], MessageInterface::class) + && is_string($value['body'])) { + // Convert message interface back + $stream = Psr7\stream_for($value['body']); + $value = $value['container'] + ->withBody($stream); + } + return ($value === false ? $default : $value); + } + + public function set($key, $value, $ttl = null) { + if (is_object($value) && is_a($value, MessageInterface::class)) { + // Read full stream for caching + $stream = $value->getBody(); + $value = [ + 'container' => $value, + 'body' => $stream->getContents() + ]; + $stream->rewind(); + } + return $this->cache->save($this->prefix.$key, $value, $ttl); + } + + public function delete($key) { + throw new CacheException("This method is not implemented."); + } + + public function clear() { + throw new CacheException("This method is not implemented."); + } + + public function getMultiple($keys, $default = null) { + throw new CacheException("This method is not implemented."); + } + + public function setMultiple($values, $ttl = null) { + throw new CacheException("This method is not implemented."); + } + + public function deleteMultiple($keys) { + throw new CacheException("This method is not implemented."); + } + + public function has($key) { + return $this->cache->contains($this->prefix.$key); + } + +} \ No newline at end of file diff --git a/classes/InteractiveRunController.php b/classes/InteractiveRunController.php new file mode 100644 index 0000000..8cba0c6 --- /dev/null +++ b/classes/InteractiveRunController.php @@ -0,0 +1,172 @@ +classRepository = $classRepository; + $this->container = $container; + } + + public function isEnabled() { + return ($this->container->has('interactive_run') + && $this->container->get('interactive_run') === true); + } + + public function getOriginalHostname($sessionHostname) { + if (!isset($this->accountContext)) { + // We cannot access original hostnames for anonymous users + return null; + } + + if (!isset($this->domains)) { + // Get domains that the user has access to + $apiResponse = json_decode($this->accountContext->getClient()->get('dr/') + ->getBody(), true); + $this->domains = isset($apiResponse['domains']) ? $apiResponse['domains'] : []; + } + + $hostname = @$this->mapBack[$sessionHostname]; + return (isset($hostname) && in_array($hostname, $this->domains)) + ? $hostname : null; + } + + private function createTemporaryClassObject($className, $config) { + // Parse RDF/XML config + $parser = \ARC2::getRDFXMLParser(); + $parser->parse('', $config); + $index = $parser->getSimpleIndex(false); + + $rewrittenIndex = []; + $targetName = ''; + foreach ($index as $subject => $data) { + $coid = COIDParser::fromString($subject); + if (COIDParser::getName($coid) == $className) { + // Rewrite namespace to not interfere with production classes + $targetName = 'coid://'.$this->session.'.phpmae'.$coid->getPath(); + $this->mapBack[$this->session.'.phpmae'] = $coid->getHost(); + $rewrittenIndex[$targetName] = $data; + } else + $rewrittenIndex[$subject] = $data; + } + + if (empty($targetName)) + throw new Exception("Could not find configuration for <".$className.">."); + + // Convert to JsonLD as required by the CloudObjects SDK + $document = JsonLD::getDocument( + JsonLD::fromRdf(Arc2JsonLdConverter::indexToQuads($rewrittenIndex)) + ); + + // Find object + $node = $document->getGraph()->getNode($targetName); + + if (!isset($node)) + throw new Exception("Invalid object configuration."); + + return $node; + } + + public function handle(RequestInterface $request, Engine $engine) { + if (!$this->isEnabled()) + throw new PhpMAEException("This is not an environment with interactive run enabled."); + + if ($request->getMethod() != 'POST') + throw new PhpMAEException("Must use POST for run requests."); + + $runData = $request->getParsedBody(); + + $this->session = isset($runData['session']) + ? $runData['session'] + : uniqid(); + + if (isset($runData['aauid']) && isset($runData['access_token'])) { + // We have user credentials + $this->accountContext = new AccountContext( + AAUIDParser::fromString($runData['aauid']), $runData['access_token'] + ); + } + + try { + $object = $this->createTemporaryClassObject($runData['class'], $runData['config']); + $engine->setRunClass($this->classRepository + ->createInstance($object, $request, [], $runData['sourceCode']) + ); + } catch (Exception $e) { + // Catch validation errors + return $engine->generateResponse([ + 'status' => 'error', + 'content' => $e->getMessage(), + 'session' => $this->session + ]); + } + + $rpcBody = json_encode([ + 'jsonrpc' => '2.0', + 'method' => $runData['method'], + 'params' => $runData['params'], + 'id' => 'PG' + ]); + + // Update error handler for response format required by client + $this->container->get(ErrorHandler::class) + ->setResponseGenerator(function($error, $object) use ($engine) { + $message = substr($error['message'], 0, strpos($error['message'], ' in /')); + return $engine->generateResponse([ + 'status' => 'error', + 'content' => $message, + 'session' => $this->session + ]); + }); + + try { + $innerRequest = new ServerRequest('POST', $request->getUri(), + $request->getHeaders(), $rpcBody); + $innerResponse = $engine->handle($innerRequest); + $rpcResponse = json_decode($innerResponse->getBody(), true); + + if (isset($rpcResponse['result'])) + return $engine->generateResponse([ + 'status' => 'success', + 'content' => $rpcResponse['result'], + 'session' => $this->session + ]); + else + return $engine->generateResponse([ + 'status' => 'error', + 'content' => $rpcResponse['error']['message'], + 'session' => $this->session + ]); + } catch (PhpMAEException $e) { + return $engine->generateResponse([ + 'status' => 'error', + 'content' => $e->getMessage(), + 'session' => $this->session + ]); + } + } + +} diff --git a/classes/JsonRPCServer.php b/classes/JsonRPCServer.php new file mode 100644 index 0000000..95a5bbf --- /dev/null +++ b/classes/JsonRPCServer.php @@ -0,0 +1,459 @@ +handler = $methodHandler; + $this->transport = $transport; + + if (!$this->transport) + { + $this->transport = new JsonRPCTransport; + } + + } + + + public function receive($input = '') + { + + $this->init(); + + try + { + $input = $input ?: $this->transport->receive(); + $json = $this->process($input); + $this->transport->reply($json); + } + catch (\Exception $e) + { + $this->logException($e); + exit; + } + + } + + + public function setTransport($transport) + { + $this->transport = $transport; + } + + + public function setLogger($logger) + { + $this->logger = $logger; + } + + + public function setObjectsAsArrays() + { + $this->assoc = true; + } + + + private function process($json) + { + if (!$struct = Rpc::decode($json, $batch)) + { + $code = is_null($struct) ? Rpc::ERR_PARSE : Rpc::ERR_REQUEST; + $data = new Response(); + $data->createStdError($code); + return $data->toJson(); + } + + $this->getRequests($struct); + $this->processRequests(); + + if (count($this->responses) == 1 && is_object($this->responses[0])) + return $this->responses[0]; + + $data = implode(',', $this->responses); + + return $batch && $data ? '[' . $data . ']' : $data; + + } + + + private function getRequests($struct) + { + + if (is_array($struct)) + { + + foreach ($struct as $item) + { + $this->requests[] = new Request($item); + } + + } + else + { + $this->requests[] = new Request($struct); + } + + } + + + private function processRequests() + { + + foreach ($this->requests as $request) + { + + # check if we got an error parsing the request, otherwise process it + if ($request->fault) + { + + $this->error = array( + 'code' => Rpc::ERR_REQUEST, + 'data' => $request->fault + ); + + # we always response to request errors + $this->addResponse($request, null); + + continue; + + } + + $result = $this->processRequest($request->method, $request->params); + + if (!$request->notification) + { + $this->addResponse($request, $result); + } + + } + + } + + + private function processRequest($method, $params) + { + + $this->error = null; + + if (!$callback = $this->getCallback($method)) + { + $this->error = Rpc::ERR_METHOD; + + return; + } + + if (!$this->checkMethod($method, $params)) + { + $this->error = Rpc::ERR_PARAMS; + + return; + } + + if ($this->assoc) + { + $this->castObjectsToArrays($params); + } + + try + { + $result = call_user_func_array($callback, $params); + } + catch (\Exception $e) + { + $this->logException($e); + $this->error = Rpc::ERR_INTERNAL; + + return; + } + + if ($this->error = $this->getHandlerError()) + { + $this->clearHandlerError(); + } + + return $result; + + } + + + private function addResponse($request, $result) + { + if (is_object($result) && is_a($result, ResponseInterface::class)) { + $this->responses[] = $result; + return; + } + + $ar = array( + 'id' => $request->id + ); + + if ($this->error) + { + $ar['error'] = $this->error; + } + else + { + $ar['result'] = $result; + } + + $response = new Response(); + + if (!$response->create($ar)) + { + $this->logError($response->fault); + $response->createStdError(Rpc::ERR_INTERNAL, $request->id); + } + + $this->responses[] = $response->toJson(); + + } + + + private function getCallback($method) + { + + $callback = array($this->handler, $method); + + if (is_callable($callback)) + { + return $callback; + } + + } + + + private function checkMethod($method, &$params) + { + + try + { + + if (!$this->refClass) + { + # we have already checked that handler is callable + $this->refClass = new \ReflectionClass($this->handler); + + try + { + + $prop = $this->refClass->getProperty('error'); + + if ($prop->isPublic()) + { + $this->handlerError = $prop; + } + + } + catch (\Exception $e){} + + } + + try + { + $refMethod = $this->refClass->getMethod($method); + } + catch (\Exception $e) + { + # we know we are callable, so the class must be implementing __call or __callStatic + $params = $this->getParams($params); + return true; + } + + $res = true; + + if (is_object($params)) + { + + $named = (array) $params; + $params = array(); + $refParams = $refMethod->getParameters(); + + foreach ($refParams as $arg) + { + + $argName = $arg->getName(); + + if (array_key_exists($argName, $named)) + { + $params[] = $named[$argName]; + unset($named[$argName]); + } + elseif (!$arg->isOptional()) + { + $res = false; + break; + } + + } + + if ($extra = array_values($named)) + { + $params = array_merge($params, $extra); + } + + } + else + { + $params = $this->getParams($params); + $reqArgs = $refMethod->getNumberOfRequiredParameters(); + $res = count($params) >= $reqArgs; + } + + return $res; + + } + catch (\Exception $e) {} + + } + + + private function getParams($params) + { + + if (is_object($params)) + { + $params = array_values((array) $params); + } + elseif (is_null($params)) + { + $params = array(); + } + + return $params; + + } + + + private function castObjectsToArrays(&$params) + { + + foreach ($params as &$param) + { + + if (is_object($param)) + { + $param = (array) $param; + } + + } + + } + + + private function getHandlerError() + { + + if ($this->handlerError) + { + + if ($this->handlerError->isStatic()) + { + return $this->handlerError->getValue(); + } + else + { + return $this->handlerError->getValue($this->handler); + } + + } + + } + + private function clearHandlerError() + { + + if ($this->handlerError) + { + + if ($this->handlerError->isStatic()) + { + return $this->handlerError->setValue(null); + } + else + { + return $this->handlerError->setValue($this->handler, null); + } + + } + + } + + private function logException(\Exception $e) + { + $message = 'Exception: '. $e->getMessage(); + $message .= ' in ' . $e->getFile() . ' on line ' . $e->getLine(); + $this->logError($message); + } + + private function logError($message) + { + + try + { + + if ($this->logger) + { + + $callback = array($this->logger, 'addRecord'); + + $params = array( + 500, + $message + ); + + $result = call_user_func_array($callback, $params); + + } + else + { + error_log($message); + } + + } + catch (\Exception $e) + { + error_log($e->__toString()); + } + + } + + private function init() + { + $this->requests = array(); + $this->responses = array(); + $this->error = null; + $this->handlerError = null; + $this->refClass = null; + } + + +} diff --git a/classes/JsonRPCTransport.php b/classes/JsonRPCTransport.php new file mode 100644 index 0000000..f266ff2 --- /dev/null +++ b/classes/JsonRPCTransport.php @@ -0,0 +1,38 @@ +response = $data->withHeader('C-PhpMae-Passthru', '1'); + else + $this->response = (new Response(200)) + ->withHeader('Content-Type', 'application/json') + ->write($data); + } + + public function receive() { + return ""; + } + + /** + * Get the response + */ + public function getResponse() { + return $this->response; + } +} diff --git a/classes/ObjectRetrieverPool.php b/classes/ObjectRetrieverPool.php new file mode 100644 index 0000000..60ad30d --- /dev/null +++ b/classes/ObjectRetrieverPool.php @@ -0,0 +1,61 @@ +baseObjectRetriever = $baseObjectRetriever; + $this->baseHostname = $baseHostname; + $this->objectRetrievers[$baseHostname] = $baseObjectRetriever; + $this->options = $options; + } + + public function getBaseObjectRetriever() { + return $this->baseObjectRetriever; + } + + public function getObjectRetriever($hostname) { + if (!isset($this->baseHostname)) + // Never create a new retriever when using developer credentials + return $this->baseObjectRetriever; + + if (!isset($this->objectRetrievers[$hostname])) { + if (substr($hostname, -7) == '.phpmae') { + // Get an anonymous retriever + $retriever = new ObjectRetriever(array_merge($this->options, [ + 'auth_ns' => '', + 'auth_secret' => '', + 'cache_prefix' => 'clobj:'.$hostname.':', + 'logger' => $this->options['logger']->withName('CO-'.$hostname) + ])); + } else { + // Get a retriever with namespace impersonation + $config = $this->baseObjectRetriever->getClient()->getConfig(); + $config['headers']['C-Act-As'] = $hostname; + + $retriever = new ObjectRetriever(array_merge($this->options, [ + 'cache_prefix' => 'clobj:'.$hostname.':', + 'logger' => $this->options['logger']->withName('CO-'.$hostname) + ])); + $retriever->setClient(new Client($config)); + } + $this->objectRetrievers[$hostname] = $retriever; + } + + return $this->objectRetrievers[$hostname]; + } +} + diff --git a/classes/Router.php b/classes/Router.php new file mode 100644 index 0000000..4ad6028 --- /dev/null +++ b/classes/Router.php @@ -0,0 +1,302 @@ +engine = $engine; + $this->objectRetriever = $objectRetriever; + $this->container = $container; + } + + private function getRequestHeaders(Request $request) { + $headers = new Headers; // this instance is required to access the "normalizeKey" method + $output = []; + foreach (array_keys($request->getHeaders()) as $key) { + $key = $headers->normalizeKey($key); + if (substr($key, 0, 9) == 'c-phpmae-' || $key == 'host') { + // do not forward "Host" header or custom phpMAE headers + continue; + } + $output[$key] = $request->getHeaderLine($key); + } + return $output; + } + + private function configure(App $app, Node $object) { + $reader = new NodeReader([ + 'prefixes' => [ + 'co' => 'coid://cloudobjects.io/', + 'phpmae' => 'coid://phpmae.dev/', + 'wa' => 'coid://webapis.co-n.net/', + 'agws' => 'coid://aauid.net/', + ] + ]); + + if ($reader->hasProperty($object, 'phpmae:enableCORSWithOrigin')) { + // Add CORS support to router + $origins = $reader->getAllValuesString($object, 'phpmae:enableCORSWithOrigin'); + $app->add(new CorsMiddleware([ + 'origin' => $origins, + 'headers.allow' => [ 'Content-Type' ], + 'credentials' => true, + 'cache' => 600 + ])); + } + + $routes = array_merge( + $reader->getAllValuesNode($object, 'phpmae:hasRoute'), + $reader->getAllValuesNode($object, 'agws:hasMethod') + ); + + $router = $this; + $engine = $this->engine; + $retriever = $this->getObjectRetriever(new IRI($object->getId())); + + foreach ($routes as $r) { + if (!$reader->hasProperty($r, 'wa:hasVerb') || !$reader->hasProperty($r, 'wa:hasPath')) + throw new PhpMAEException("Incomplete route configuration! Routes must have wa:hasVerb and wa:hasPath."); + + $app->map([ $reader->getFirstValueString($r, 'wa:hasVerb') ], + $reader->getFirstValueString($r, 'wa:hasPath'), + function(RequestInterface $request, ResponseInterface $response, $args) use ($r, $reader, $router, $engine, $retriever, $object) { + if ($reader->hasProperty($r, 'phpmae:runsClass')) { + try { + $params = []; + if ($reader->hasProperty($r, 'wa:hasJSONBodyWithSchema')) { + // Validate request against schema + $schemaValidator = new SchemaValidator($retriever); + $schemaValidator->validateAgainstCOID($request->getParsedBody(), + $reader->getFirstValueIRI($r, 'wa:hasJSONBodyWithSchema')); + // Then, map to single argument + $params = [ $request->getParsedBody() ]; + } elseif (is_array($args) && count($args) > 0) { + // Use path arguments as params + $params = $args; + } elseif (is_array($request->getParsedBody())) { + // Use body as params + $params = $request->getParsedBody(); + } elseif (is_array($request->getQueryParams())) { + // Use query as params + $params = $request->getQueryParams(); + } + } catch (InvalidArgumentException $e) { + return (new Response(400))->withJson([ + 'error' => 'InputValidationFailed', + 'message' => $e->getMessage() + ]); + } + + // Add static parameters from Router + foreach ($reader->getAllValuesNode($r, 'phpmae:includeParameterWithDefault') as $p) { + if (!$reader->hasProperty($p, 'wa:hasKey') || !$reader->hasProperty($p, 'wa:hasDefaultValue')) { + // Ignore incomplete parameter + continue; + } + + if ($reader->hasType($p, 'wa:HeaderParameter')) { + // Add custom header + $request = $request->withHeader( + 'HTTP_'.strtoupper($reader->getFirstValueString($p, 'wa:hasKey')), + $reader->getFirstValueString($p, 'wa:hasDefaultValue') + ); + } + } + + // Route is mapped to a class + $engine->loadRunClass($reader->getFirstValueIRI($r, 'phpmae:runsClass'), $request); + + if ($reader->hasProperty($r, 'phpmae:runsMethod')) { + // Calls to specific methods must be rewritten + // Path, request and query parameters are merged and used as method input + $rpcBody = json_encode([ + 'jsonrpc' => '2.0', + 'method' => $reader->getFirstValueString($r, 'phpmae:runsMethod'), + 'params' => $params, + 'id' => 'R' + ]); + $innerRequest = new ServerRequest('POST', $request->getUri(), + $request->getHeaders(), $rpcBody); + + $innerResponse = $engine->handle($innerRequest); + if ($innerResponse->hasHeader('C-PhpMae-Passthru')) + return $innerResponse->withoutHeader('C-PhpMae-Passthru'); + + $rpcResponse = json_decode($innerResponse->getBody(), true); + + if (isset($rpcResponse['result'])) { + return $engine->generateResponse($rpcResponse['result']); + } else { + return (new Response(500))->withJson($rpcResponse); + } + } else { + // Generic class execution (invokable) + return $engine->handle($request, $params); + } + + } elseif ($reader->hasProperty($r, 'phpmae:redirectsToURL')) { + // Route to redirect to a specific external URL + return (new Response)->withRedirect($reader->getFirstValueString($r, 'phpmae:redirectsToURL')); + + } elseif ($reader->hasProperty($r, 'phpmae:redirectsToBaseURL')) { + // Route to redirect to an external base URL + $baseUrl = $reader->getFirstValueIRI($r, 'phpmae:redirectsToBaseURL'); + $uri = $request->getUri(); + $targetUrl = (string)$baseUrl->resolve(substr($uri->getPath(), 1) . ($uri->getQuery() != '' ? '?'.$uri->getQuery() : '')); + + return (new Response)->withRedirect($targetUrl); + + } elseif ($reader->hasProperty($r, 'phpmae:proxiesRequestsToBaseURL')) { + // Route to proxy requests to an external URL + $client = new Client([ + 'base_uri' => $reader->getFirstValueString($r, 'phpmae:proxiesRequestsToBaseURL') + ]); + $uri = $request->getUri(); + try { + return $client->request($request->getMethod(), + $uri->getPath() . ($uri->getQuery() != '' ? '?'.$uri->getQuery() : ''), [ + 'headers' => $router->getRequestHeaders($request), + 'body' => $request->getBody() + ]); + } catch (BadResponseException $e) { + return $e->getResponse(); + } + + } elseif ($reader->hasProperty($r, 'phpmae:servesStaticFileAttachment')) { + // Rule to serve an attached file + $etag = '"'.md5($reader->getFirstValueString($object, 'co:isAtRevision') + .'+'.$reader->getFirstValueString($r, 'phpmae:servesStaticFileAttachment')).'"'; + + if ($request->hasHeader('If-None-Match') && strpos($request->getHeaderLine('If-None-Match'), $etag) > -1) { + // Can use cached version + return (new Response(304))->withHeader('ETag', $etag) + ->withHeader('Cache-Control', 'max-age='.self::STATIC_CACHE_TTL.', public'); + } + + $attachmentContent = $retriever->getAttachment(new IRI($object->getId()), + $reader->getFirstValueString($r, 'phpmae:servesStaticFileAttachment')); + + if (!isset($attachmentContent)) + return (new Response(501))->write("Requested static file attachment cannot be found."); + + return $engine->generateResponse($attachmentContent) + ->withHeader('ETag', $etag) + ->withHeader('Cache-Control', 'max-age='.self::STATIC_CACHE_TTL.', public'); + } else { + // Route has no implementation + return (new Response(501))->write("Route implementation not available or no access granted."); + } + }); + } + } + + private function getObjectRetriever(IRI $coid) { + return $this->container->get(ObjectRetrieverPool::class) + ->getObjectRetriever($coid->getHost()); + } + + private function getRouter(IRI $coid) { + return $this->getObjectRetriever($coid) + ->get($coid); + } + + /** + * Setup and run router. + */ + public function run() { + try { + $modes = explode('|', $this->container->get('mode')); + $fallback = false; + + $configuration = [ + 'settings' => [ + 'displayErrorDetails' => true, + ], + ]; + $c = new \Slim\Container($configuration); + $app = new App($c); + + $router = null; + $env = new Environment($_SERVER); + foreach ($modes as $m) { + switch ($m) { + case 'router:vhost': + if ($router == null) { + $uri = Uri::createFromEnvironment($env); + if ($uri->getHost() == 'localhost' || filter_var($uri->getHost(), FILTER_VALIDATE_IP) !== false) continue; + + $namespace = $this->objectRetriever->get('coid://'.$uri->getHost()); + if (isset($namespace) && $routerCoid = $namespace->getProperty('coid://phpmae.dev/hasRouter')) + $router = $this->getRouter(new IRI($routerCoid->getId())); + } + break; + case 'router:header': + if ($router == null) { + $request = Request::createFromEnvironment($env); + if ($request->hasHeader('C-PhpMae-Router-COID')) + $router = $this->getRouter(new IRI($request->getHeaderLine('C-PhpMae-Router-COID'))); + } + break; + case 'default': + $fallback = true; + break; + default: + if (substr($m, 0, 14) == 'router:coid://') + $router = $this->getRouter(new IRI(substr($m, 7))); + else + throw new PhpMAEException("Unsupported mode!"); + } + } + + if (isset($router)) { + $this->configure($app, $router); + $response = $app->run(true); + } elseif ($fallback) { + $this->container->get(Engine::class) + ->run(); + exit; + } else { + throw new PhpMAEException("No router found!"); + } + + } catch (PhpMAEException $e) { + // Create plain-text error response + $response = (new Response(500)) + ->withHeader('Content-Type', 'text/plain') + ->write($e->getMessage()); + } + + $app->respond($response); + } +} \ No newline at end of file diff --git a/classes/Sandbox/CustomizedSandbox.php b/classes/Sandbox/CustomizedSandbox.php new file mode 100644 index 0000000..5d7feab --- /dev/null +++ b/classes/Sandbox/CustomizedSandbox.php @@ -0,0 +1,76 @@ +set_options([ + 'allow_classes' => true, + 'allow_interfaces' => true, + 'allow_aliases' => true, + 'allow_closures' => true, + 'allow_casting' => true, + 'allow_error_suppressing' => true, + 'validate_constants' => false + ]); + $this->whitelist([ + 'functions' => [ + 'strlen','strcmp','strncmp','strcasecmp','strncasecmp','each','get_class','property_exists','is_a','trigger_error','user_error','gc_collect_cycles','gc_enabled','strtotime','date','idate','gmdate','mktime','gmmktime','checkdate','time','localtime','getdate','date_create','date_create_immutable','date_create_from_format','date_create_immutable_from_format','date_parse','date_parse_from_format','date_get_last_errors','date_format','date_modify','date_add','date_sub','date_timezone_get','date_timezone_set','date_offset_get','date_diff','date_time_set','date_date_set','date_isodate_set','date_timestamp_set','date_timestamp_get','timezone_open','timezone_name_get','timezone_name_from_abbr','timezone_offset_get','timezone_transitions_get','timezone_location_get','timezone_identifiers_list','timezone_abbreviations_list','date_interval_create_from_date_string','date_interval_format','date_sunrise','date_sunset','date_sun_info','ereg','ereg_replace','eregi','eregi_replace','split','spliti','sql_regcase','libxml_use_internal_errors','libxml_get_last_error','libxml_clear_errors','libxml_get_errors','openssl_spki_new','openssl_spki_verify','openssl_spki_export','openssl_spki_export_challenge','openssl_pkey_free','openssl_pkey_new','openssl_pkey_export','openssl_pkey_get_private','openssl_pkey_get_public','openssl_pkey_get_details','openssl_free_key','openssl_get_privatekey','openssl_get_publickey','openssl_x509_read','openssl_x509_free','openssl_x509_parse','openssl_x509_checkpurpose','openssl_x509_check_private_key','openssl_x509_export','openssl_x509_fingerprint','openssl_pkcs12_export','openssl_pkcs12_read','openssl_csr_new','openssl_csr_export','openssl_csr_sign','openssl_csr_get_subject','openssl_csr_get_public_key','openssl_digest','openssl_encrypt','openssl_decrypt','openssl_cipher_iv_length','openssl_sign','openssl_verify','openssl_seal','openssl_open','openssl_pbkdf2','openssl_private_encrypt','openssl_private_decrypt','openssl_public_encrypt','openssl_public_decrypt','openssl_get_md_methods','openssl_get_cipher_methods','openssl_dh_compute_key','openssl_random_pseudo_bytes','openssl_error_string','pack','preg_match','preg_match_all','preg_replace','preg_replace_callback','preg_filter','preg_split','preg_quote','preg_grep','preg_last_error','gzcompress','gzuncompress','gzdeflate','gzinflate','gzencode','gzdecode','zlib_encode','zlib_decode','zlib_get_coding_type','ob_gzhandler','bcadd','bcsub','bcmul','bcdiv','bcmod','bcpow','bcsqrt','bcscale','bccomp','bcpowmod','bzcompress','bzdecompress','jdtogregorian','gregoriantojd','jdtojulian','juliantojd','jdtojewish','jewishtojd','jdtofrench','frenchtojd','jddayofweek','jdmonthname','easter_date','easter_days','unixtojd','jdtounix','cal_to_jd','cal_from_jd','cal_days_in_month','cal_info','ctype_alnum','ctype_alpha','ctype_cntrl','ctype_digit','ctype_lower','ctype_graph','ctype_print','ctype_punct','ctype_space','ctype_upper','ctype_xdigit','dom_import_simplexml','filter_var','filter_var_array','filter_list','filter_id','hash','hash_hmac','hash_init','hash_update','hash_final','hash_copy','hash_hkdf','hash_algos','hash_pbkdf2','hash_equals','iconv','iconv_get_encoding','iconv_set_encoding','iconv_strlen','iconv_substr','iconv_strpos','iconv_strrpos','iconv_mime_encode','iconv_mime_decode','iconv_mime_decode_headers','json_encode','json_decode','json_last_error','json_last_error_msg','ldap_connect','ldap_close','ldap_bind','ldap_sasl_bind','ldap_unbind','ldap_read','ldap_list','ldap_search','ldap_free_result','ldap_count_entries','ldap_first_entry','ldap_next_entry','ldap_get_entries','ldap_first_attribute','ldap_next_attribute','ldap_get_attributes','ldap_get_values','ldap_get_values_len','ldap_get_dn','ldap_explode_dn','ldap_dn2ufn','ldap_add','ldap_delete','ldap_modify_batch','ldap_modify','ldap_mod_add','ldap_mod_replace','ldap_mod_del','ldap_errno','ldap_err2str','ldap_error','ldap_compare','ldap_rename','ldap_get_option','ldap_set_option','ldap_first_reference','ldap_next_reference','ldap_parse_reference','ldap_parse_result','ldap_start_tls','ldap_set_rebind_proc','ldap_escape','ldap_control_paged_result','ldap_control_paged_result_response','mb_convert_case','mb_strtoupper','mb_strtolower','mb_language','mb_internal_encoding','mb_detect_order','mb_substitute_character','mb_preferred_mime_name','mb_strlen','mb_strpos','mb_strrpos','mb_stripos','mb_strripos','mb_strstr','mb_strrchr','mb_stristr','mb_strrichr','mb_substr_count','mb_substr','mb_strcut','mb_strwidth','mb_strimwidth','mb_convert_encoding','mb_detect_encoding','mb_list_encodings','mb_encoding_aliases','mb_convert_kana','mb_encode_mimeheader','mb_decode_mimeheader','mb_convert_variables','mb_encode_numericentity','mb_decode_numericentity','mb_get_info','mb_check_encoding','mb_regex_encoding','mb_regex_set_options','mb_ereg','mb_eregi','mb_ereg_replace','mb_eregi_replace','mb_ereg_replace_callback','mb_split','mb_ereg_match','mb_ereg_search','mb_ereg_search_pos','mb_ereg_search_regs','mb_ereg_search_init','mb_ereg_search_getregs','mb_ereg_search_getpos','mb_ereg_search_setpos','mbregex_encoding','mbereg','mberegi','mbereg_replace','mberegi_replace','mbsplit','mbereg_match','mbereg_search','mbereg_search_pos','mbereg_search_regs','mbereg_search_init','mbereg_search_getregs','mbereg_search_getpos','mbereg_search_setpos','mysqli_affected_rows','mysqli_autocommit','mysqli_begin_transaction','mysqli_change_user','mysqli_character_set_name','mysqli_close','mysqli_commit','mysqli_connect','mysqli_connect_errno','mysqli_connect_error','mysqli_data_seek','mysqli_dump_debug_info','mysqli_debug','mysqli_errno','mysqli_error','mysqli_error_list','mysqli_stmt_execute','mysqli_execute','mysqli_fetch_field','mysqli_fetch_fields','mysqli_fetch_field_direct','mysqli_fetch_lengths','mysqli_fetch_all','mysqli_fetch_array','mysqli_fetch_assoc','mysqli_fetch_object','mysqli_fetch_row','mysqli_field_count','mysqli_field_seek','mysqli_field_tell','mysqli_free_result','mysqli_get_connection_stats','mysqli_get_client_stats','mysqli_get_charset','mysqli_get_client_info','mysqli_get_client_version','mysqli_get_host_info','mysqli_get_proto_info','mysqli_get_server_info','mysqli_get_server_version','mysqli_get_warnings','mysqli_init','mysqli_info','mysqli_insert_id','mysqli_kill','mysqli_more_results','mysqli_multi_query','mysqli_next_result','mysqli_num_fields','mysqli_num_rows','mysqli_ping','mysqli_poll','mysqli_prepare','mysqli_report','mysqli_query','mysqli_real_connect','mysqli_real_escape_string','mysqli_real_query','mysqli_release_savepoint','mysqli_rollback','mysqli_savepoint','mysqli_select_db','mysqli_set_charset','mysqli_stmt_affected_rows','mysqli_stmt_attr_get','mysqli_stmt_attr_set','mysqli_stmt_bind_param','mysqli_stmt_bind_result','mysqli_stmt_close','mysqli_stmt_data_seek','mysqli_stmt_errno','mysqli_stmt_error','mysqli_stmt_error_list','mysqli_stmt_fetch','mysqli_stmt_field_count','mysqli_stmt_free_result','mysqli_stmt_get_result','mysqli_stmt_get_warnings','mysqli_stmt_init','mysqli_stmt_insert_id','mysqli_stmt_more_results','mysqli_stmt_next_result','mysqli_stmt_num_rows','mysqli_stmt_param_count','mysqli_stmt_prepare','mysqli_stmt_reset','mysqli_stmt_result_metadata','mysqli_stmt_send_long_data','mysqli_stmt_store_result','mysqli_stmt_sqlstate','mysqli_sqlstate','mysqli_ssl_set','mysqli_stat','mysqli_store_result','mysqli_thread_id','mysqli_thread_safe','mysqli_use_result','mysqli_warning_count','mysqli_refresh','mysqli_escape_string','mysqli_set_opt','iterator_to_array','iterator_count','iterator_apply','pdo_drivers','simplexml_load_string','simplexml_import_dom','bin2hex','hex2bin','sleep','usleep','time_nanosleep','time_sleep_until','strptime','wordwrap','htmlspecialchars','htmlentities','html_entity_decode','htmlspecialchars_decode','get_html_translation_table','sha1','md5','crc32','phpversion','strnatcmp','strnatcasecmp','substr_count','strspn','strcspn','strtok','strtoupper','strtolower','strpos','stripos','strrpos','strripos','strrev','hebrev','hebrevc','nl2br','basename','dirname','stripslashes','stripcslashes','strstr','stristr','strrchr','str_shuffle','str_word_count','str_split','strpbrk','substr_compare','strcoll','money_format','substr','substr_replace','quotemeta','ucfirst','lcfirst','ucwords','strtr','addslashes','addcslashes','rtrim','str_replace','str_ireplace','str_repeat','count_chars','chunk_split','trim','ltrim','strip_tags','similar_text','explode','implode','join','setlocale','localeconv','nl_langinfo','soundex','levenshtein','chr','ord','parse_str','str_getcsv','str_pad','chop','strchr','sprintf','vsprintf','sscanf','parse_url','urlencode','urldecode','rawurlencode','rawurldecode','http_build_query','escapeshellcmd','escapeshellarg','rand','srand','getrandmax','mt_rand','mt_srand','mt_getrandmax','base64_decode','base64_encode','password_hash','password_get_info','password_needs_rehash','password_verify','convert_uuencode','convert_uudecode','abs','ceil','floor','round','sin','cos','tan','asin','acos','atan','atanh','atan2','sinh','cosh','tanh','asinh','acosh','expm1','log1p','pi','is_finite','is_nan','is_infinite','pow','exp','log','log10','sqrt','hypot','deg2rad','rad2deg','bindec','hexdec','octdec','decbin','decoct','dechex','base_convert','number_format','fmod','inet_ntop','inet_pton','ip2long','long2ip','microtime','gettimeofday','uniqid','quoted_printable_decode','quoted_printable_encode','convert_cyr_string','error_get_last','serialize','unserialize','highlight_string','parse_ini_string','gethostbyaddr','gethostbyname','gethostbynamel','dns_check_record','checkdnsrr','dns_get_mx','getmxrr','dns_get_record','intval','floatval','doubleval','strval','boolval','gettype','settype','is_null','is_resource','is_bool','is_long','is_float','is_int','is_integer','is_double','is_real','is_numeric','is_string','is_array','is_object','is_scalar','fnmatch','unpack','crypt','lcg_value','metaphone','ksort','krsort','natsort','natcasesort','asort','arsort','sort','rsort','usort','uasort','uksort','shuffle','array_walk','array_walk_recursive','count','end','prev','next','reset','current','key','min','max','in_array','array_search','extract','compact','array_fill','array_fill_keys','range','array_multisort','array_push','array_pop','array_shift','array_unshift','array_splice','array_slice','array_merge','array_merge_recursive','array_replace','array_replace_recursive','array_keys','array_values','array_count_values','array_column','array_reverse','array_reduce','array_pad','array_flip','array_change_key_case','array_rand','array_unique','array_intersect','array_intersect_key','array_intersect_ukey','array_uintersect','array_intersect_assoc','array_uintersect_assoc','array_intersect_uassoc','array_uintersect_uassoc','array_diff','array_diff_key','array_diff_ukey','array_udiff','array_diff_assoc','array_udiff_assoc','array_diff_uassoc','array_udiff_uassoc','array_sum','array_product','array_filter','array_map','array_chunk','array_combine','array_key_exists','pos','sizeof','key_exists','version_compare','str_rot13','wddx_serialize_value','wddx_serialize_vars','wddx_packet_start','wddx_packet_end','wddx_add_vars','xml_parser_create','xml_parser_create_ns','xml_set_object','xml_set_element_handler','xml_set_character_data_handler','xml_set_processing_instruction_handler','xml_set_default_handler','xml_set_unparsed_entity_decl_handler','xml_set_notation_decl_handler','xml_set_external_entity_ref_handler','xml_set_start_namespace_decl_handler','xml_set_end_namespace_decl_handler','xml_parse','xml_parse_into_struct','xml_get_error_code','xml_error_string','xml_get_current_line_number','xml_get_current_column_number','xml_get_current_byte_index','xml_parser_free','xml_parser_set_option','xml_parser_get_option','utf8_encode','utf8_decode','xmlwriter_open_memory','xmlwriter_set_indent','xmlwriter_set_indent_string','xmlwriter_start_comment','xmlwriter_end_comment','xmlwriter_start_attribute','xmlwriter_end_attribute','xmlwriter_write_attribute','xmlwriter_start_attribute_ns','xmlwriter_write_attribute_ns','xmlwriter_start_element','xmlwriter_end_element','xmlwriter_full_end_element','xmlwriter_start_element_ns','xmlwriter_write_element','xmlwriter_write_element_ns','xmlwriter_start_pi','xmlwriter_end_pi','xmlwriter_write_pi','xmlwriter_start_cdata','xmlwriter_end_cdata','xmlwriter_write_cdata','xmlwriter_text','xmlwriter_write_raw','xmlwriter_start_document','xmlwriter_end_document','xmlwriter_write_comment','xmlwriter_start_dtd','xmlwriter_end_dtd','xmlwriter_write_dtd','xmlwriter_start_dtd_element','xmlwriter_end_dtd_element','xmlwriter_write_dtd_element','xmlwriter_start_dtd_attlist','xmlwriter_end_dtd_attlist','xmlwriter_write_dtd_attlist','xmlwriter_start_dtd_entity','xmlwriter_end_dtd_entity','xmlwriter_write_dtd_entity','xmlwriter_output_memory','xmlwriter_flush', + 'random_bytes', + 'promise\unwrap', + 'guzzlehttp\psr7\parse_header' + ] + ]); + } + + public function validate($code) { + $this->preparsed_code = $this->disassemble($code); + $factory = new ParserFactory; + $parser = $factory->create(ParserFactory::PREFER_PHP7); + try { + $this->parsed_ast = $parser->parse($this->preparsed_code); + } catch (ParserError $error) { + $this->validationError("Could not parse sandboxed code!", Error::PARSER_ERROR, null, $this->preparsed_code, $error); + } + $prettyPrinter = new Standard(); + if(($this->allow_functions && $this->auto_whitelist_functions) || + ($this->allow_constants && $this->auto_whitelist_constants) || + ($this->allow_classes && $this->auto_whitelist_classes) || + ($this->allow_interfaces && $this->auto_whitelist_interfaces) || + ($this->allow_traits && $this->auto_whitelist_traits) || + ($this->allow_globals && $this->auto_whitelist_globals)){ + $traverser = new NodeTraverser; + $whitelister = new SandboxWhitelistVisitor($this); + $traverser->addVisitor($whitelister); + $traverser->traverse($this->parsed_ast); + } + $traverser = new NodeTraverser; + $validator = new CustomizedValidatorVisitor($this); + $traverser->addVisitor($validator); + $this->prepared_ast = $traverser->traverse($this->parsed_ast); + $this->prepared_code = $prettyPrinter->prettyPrint($this->prepared_ast); + return $this; + } + + public static function getGlobalSandbox() { + if (!isset(static::$globalSandbox)) + static::$globalSandbox = new self; + + return static::$globalSandbox; + } +} \ No newline at end of file diff --git a/classes/Sandbox/CustomizedValidatorVisitor.php b/classes/Sandbox/CustomizedValidatorVisitor.php new file mode 100644 index 0000000..81486fe --- /dev/null +++ b/classes/Sandbox/CustomizedValidatorVisitor.php @@ -0,0 +1,403 @@ +value instanceof Node\Expr\Variable) ? 'PHPSandbox\\wrapByRef' : 'PHPSandbox\\wrap'), [$node, new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox')], $node->getAttributes()); + } else if($node instanceof Node\Stmt\InlineHTML){ + if(!$this->sandbox->allow_escaping){ + $this->sandbox->validationError("Sandboxed code attempted to escape to HTML!", Error::ESCAPE_ERROR, $node); + } + }else if($node instanceof Node\Expr\Cast){ + if(!$this->sandbox->allow_casting){ + $this->sandbox->validationError("Sandboxed code attempted to cast!", Error::CAST_ERROR, $node); + } + if($node instanceof Node\Expr\Cast\Int_){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_intval', [new Node\Arg($node->expr)], $node->getAttributes()); + } else if($node instanceof Node\Expr\Cast\Double){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_floatval', [new Node\Arg($node->expr)], $node->getAttributes()); + } else if($node instanceof Node\Expr\Cast\Bool_){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_boolval', [new Node\Arg($node->expr)], $node->getAttributes()); + } else if($node instanceof Node\Expr\Cast\Array_){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_arrayval', [new Node\Arg($node->expr)], $node->getAttributes()); + } else if($node instanceof Node\Expr\Cast\Object_){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_objectval', [new Node\Arg($node->expr)], $node->getAttributes()); + } + } else if($node instanceof Node\Expr\FuncCall){ + if($node->name instanceof Node\Name){ + $name = strtolower($node->name->toString()); + if(!$this->sandbox->checkFunc($name)){ + $this->sandbox->validationError("Function failed custom validation!", Error::VALID_FUNC_ERROR, $node); + } + if($this->sandbox->isDefinedFunc($name)){ + $args = $node->args; + array_unshift($args, new Node\Arg(new Node\Scalar\String_($name))); + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), 'call_func', $args, $node->getAttributes()); + } + if($this->sandbox->overwrite_defined_funcs && in_array($name, PHPSandbox::$defined_funcs)){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name([$name])))], $node->getAttributes()); + } + if($this->sandbox->overwrite_sandboxed_string_funcs && in_array($name, PHPSandbox::$sandboxed_string_funcs)){ + $args = $node->args; + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_' . $name, $args, $node->getAttributes()); + } + if($this->sandbox->overwrite_func_get_args && in_array($name, PHPSandbox::$arg_funcs)){ + if($name == 'func_get_arg'){ + $index = new Node\Arg(new Node\Scalar\LNumber(0)); + if(isset($node->args[0]) && $node->args[0] instanceof Node\Arg){ + $index = $node->args[0]; + } + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name(['func_get_args']))), $index], $node->getAttributes()); + } + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name(['func_get_args'])))], $node->getAttributes()); + } + } else { + return new Node\Expr\Ternary( + new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), 'check_func', [new Node\Arg($node->name)], $node->getAttributes()), + $node, + new Node\Expr\ConstFetch(new Node\Name('null')) + ); + } + } else if($node instanceof Node\Stmt\Function_){ + if(!$this->sandbox->allow_functions){ + $this->sandbox->validationError("Sandboxed code attempted to define function!", Error::DEFINE_FUNC_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('function')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'function'); + } + if(!$node->name){ + $this->sandbox->validationError("Sandboxed code attempted to define unnamed function!", Error::DEFINE_FUNC_ERROR, $node, ''); + } + if($this->sandbox->isDefinedFunc($node->name)){ + $this->sandbox->validationError("Sandboxed code attempted to redefine function!", Error::DEFINE_FUNC_ERROR, $node, $node->name); + } + if($node->byRef && !$this->sandbox->allow_references){ + $this->sandbox->validationError("Sandboxed code attempted to define function return by reference!", Error::BYREF_ERROR, $node); + } + } else if($node instanceof Node\Expr\Closure){ + if(!$this->sandbox->allow_closures){ + $this->sandbox->validationError("Sandboxed code attempted to create a closure!", Error::CLOSURE_ERROR, $node); + } + } else if($node instanceof Node\Stmt\Class_){ + if(!$this->sandbox->allow_classes){ + $this->sandbox->validationError("Sandboxed code attempted to define class!", Error::DEFINE_CLASS_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('class')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'class'); + } + if(!$node->name){ + $this->sandbox->validationError("Sandboxed code attempted to define unnamed class!", Error::DEFINE_CLASS_ERROR, $node, ''); + } + if(!$this->sandbox->checkClass($node->name)){ + $this->sandbox->validationError("Class failed custom validation!", Error::VALID_CLASS_ERROR, $node, $node->name); + } + if($node->extends instanceof Node\Name){ + if(!$this->sandbox->checkKeyword('extends')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'extends'); + } + if(!$node->extends->toString()){ + $this->sandbox->validationError("Sandboxed code attempted to extend unnamed class!", Error::DEFINE_CLASS_ERROR, $node, ''); + } + if(!$this->sandbox->checkClass($node->extends->toString(), true)){ + $this->sandbox->validationError("Class extension failed custom validation!", Error::VALID_CLASS_ERROR, $node, $node->extends->toString()); + } + } + if(is_array($node->implements)){ + if(!$this->sandbox->checkKeyword('implements')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'implements'); + } + foreach($node->implements as $implement){ + /** + * @var Node\Name $implement + */ + if(!$implement->toString()){ + $this->sandbox->validationError("Sandboxed code attempted to implement unnamed interface!", Error::DEFINE_INTERFACE_ERROR, $node, ''); + } + if(!$this->sandbox->checkInterface($implement->toString())){ + $this->sandbox->validationError("Interface failed custom validation!", Error::VALID_INTERFACE_ERROR, $node, $implement->toString()); + } + } + } + } else if($node instanceof Node\Stmt\Interface_){ + if(!$this->sandbox->allow_interfaces){ + $this->sandbox->validationError("Sandboxed code attempted to define interface!", Error::DEFINE_INTERFACE_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('interface')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'interface'); + } + if(!$node->name){ + $this->sandbox->validationError("Sandboxed code attempted to define unnamed interface!", Error::DEFINE_INTERFACE_ERROR, $node, ''); + } + if(!$this->sandbox->checkInterface($node->name)){ + $this->sandbox->validationError("Interface failed custom validation!", Error::VALID_INTERFACE_ERROR, $node, $node->name); + } + } else if($node instanceof Node\Stmt\Trait_){ + if(!$this->sandbox->allow_traits){ + $this->sandbox->validationError("Sandboxed code attempted to define trait!", Error::DEFINE_TRAIT_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('trait')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'trait'); + } + if(!$node->name){ + $this->sandbox->validationError("Sandboxed code attempted to define unnamed trait!", Error::DEFINE_TRAIT_ERROR, $node, ''); + } + if(!$this->sandbox->checkTrait($node->name)){ + $this->sandbox->validationError("Trait failed custom validation!", Error::VALID_TRAIT_ERROR, $node, $node->name); + } + } else if($node instanceof Node\Stmt\TraitUse){ + if(!$this->sandbox->checkKeyword('use')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'use'); + } + if(is_array($node->traits)){ + foreach($node->traits as $trait){ + /** + * @var Node\Name $trait + */ + if(!$trait->toString()){ + $this->sandbox->validationError("Sandboxed code attempted to use unnamed trait!", Error::DEFINE_TRAIT_ERROR, $node, ''); + } + if(!$this->sandbox->checkTrait($trait->toString())){ + $this->sandbox->validationError("Trait failed custom validation!", Error::VALID_TRAIT_ERROR, $node, $trait->toString()); + } + } + } + } else if($node instanceof Node\Expr\Yield_){ + if(!$this->sandbox->allow_generators){ + $this->sandbox->validationError("Sandboxed code attempted to create a generator!", Error::GENERATOR_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('yield')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'yield'); + } + } else if($node instanceof Node\Stmt\Global_){ + if(!$this->sandbox->allow_globals){ + $this->sandbox->validationError("Sandboxed code attempted to use global keyword!", Error::GLOBALS_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('global')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'global'); + } + foreach($node->vars as $var){ + /** + * @var Node\Expr\Variable $var + */ + if($var instanceof Node\Expr\Variable){ + if(!$this->sandbox->checkGlobal($var->name)){ + $this->sandbox->validationError("Global failed custom validation!", Error::VALID_GLOBAL_ERROR, $node, $var->name); + } + } else { + $this->sandbox->validationError("Sandboxed code attempted to pass non-variable to global keyword!", Error::DEFINE_GLOBAL_ERROR, $node); + } + } + } else if($node instanceof Node\Expr\Variable){ + if(!is_string($node->name)){ + $this->sandbox->validationError("Sandboxed code attempted dynamically-named variable call!", Error::DYNAMIC_VAR_ERROR, $node); + } + if($node->name == $this->sandbox->name){ + $this->sandbox->validationError("Sandboxed code attempted to access the PHPSandbox instance!", Error::SANDBOX_ACCESS_ERROR, $node); + } + if(in_array($node->name, PHPSandbox::$superglobals)){ + if(!$this->sandbox->checkSuperglobal($node->name)){ + $this->sandbox->validationError("Superglobal failed custom validation!", Error::VALID_SUPERGLOBAL_ERROR, $node, $node->name); + } + if($this->sandbox->overwrite_superglobals){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_get_superglobal', [new Node\Arg(new Node\Scalar\String_($node->name))], $node->getAttributes()); + } + } else { + if(!$this->sandbox->checkVar($node->name)){ + $this->sandbox->validationError("Variable failed custom validation!", Error::VALID_VAR_ERROR, $node, $node->name); + } + } + } else if($node instanceof Node\Stmt\StaticVar){ + if(!$this->sandbox->allow_static_variables){ + $this->sandbox->validationError("Sandboxed code attempted to create static variable!", Error::STATIC_VAR_ERROR, $node); + } + if(!is_string($node->name)){ + $this->sandbox->validationError("Sandboxed code attempted dynamically-named static variable call!", Error::DYNAMIC_STATIC_VAR_ERROR, $node); + } + if(!$this->sandbox->checkVar($node->name)){ + $this->sandbox->validationError("Variable failed custom validation!", Error::VALID_VAR_ERROR, $node, $node->name); + } + if($node->default instanceof Node\Expr\New_){ + $node->default = $node->default->args[0]; + } + } else if($node instanceof Node\Stmt\Const_){ + $this->sandbox->validationError("Sandboxed code cannot use const keyword in the global scope!", Error::GLOBAL_CONST_ERROR, $node); + } else if($node instanceof Node\Expr\ConstFetch){ + if(!$node->name instanceof Node\Name){ + $this->sandbox->validationError("Sandboxed code attempted dynamically-named constant call!", Error::DYNAMIC_CONST_ERROR, $node); + } + if(!$this->sandbox->checkConst($node->name->toString())){ + $this->sandbox->validationError("Constant failed custom validation!", Error::VALID_CONST_ERROR, $node, $node->name->toString()); + } + } else if($node instanceof Node\Expr\ClassConstFetch || $node instanceof Node\Expr\StaticCall || $node instanceof Node\Expr\StaticPropertyFetch){ + $class = $node->class; + if(!$class instanceof Node\Name){ + $this->sandbox->validationError("Sandboxed code attempted dynamically-named class call!", Error::DYNAMIC_CLASS_ERROR, $node); + } + if($this->sandbox->isDefinedClass($class)){ + $node->class = new Node\Name($this->sandbox->getDefinedClass($class)); + } + /** + * @var Node\Name $class + */ + if(!$this->sandbox->checkClass($class->toString())){ + $this->sandbox->validationError("Class constant failed custom validation!", Error::VALID_CLASS_ERROR, $node, $class->toString()); + } + return $node; + } else if($node instanceof Node\Param && $node->type instanceof Node\Name){ + $class = $node->type->toString(); + if($this->sandbox->isDefinedClass($class)){ + $node->type = new Node\Name($this->sandbox->getDefinedClass($class)); + } + return $node; + } else if($node instanceof Node\Expr\New_){ + if(!$this->sandbox->allow_objects){ + $this->sandbox->validationError("Sandboxed code attempted to create object!", Error::CREATE_OBJECT_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('new')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'new'); + } + if(!$node->class instanceof Node\Name){ + $this->sandbox->validationError("Sandboxed code attempted dynamically-named class call!", Error::DYNAMIC_CLASS_ERROR, $node); + } + $class = $node->class->toString(); + if($this->sandbox->isDefinedClass($class)){ + $node->class = new Node\Name($this->sandbox->getDefinedClass($class)); + } + $this->sandbox->checkType($class); + return $node; + } else if($node instanceof Node\Expr\ErrorSuppress){ + if(!$this->sandbox->allow_error_suppressing){ + $this->sandbox->validationError("Sandboxed code attempted to suppress error!", Error::ERROR_SUPPRESS_ERROR, $node); + } + } else if($node instanceof Node\Expr\AssignRef){ + if(!$this->sandbox->allow_references){ + $this->sandbox->validationError("Sandboxed code attempted to assign by reference!", Error::BYREF_ERROR, $node); + } + } else if($node instanceof Node\Stmt\HaltCompiler){ + if(!$this->sandbox->allow_halting){ + $this->sandbox->validationError("Sandboxed code attempted to halt compiler!", Error::HALT_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('halt')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'halt'); + } + } else if($node instanceof Node\Stmt\Namespace_){ + if(!$this->sandbox->allow_namespaces){ + $this->sandbox->validationError("Sandboxed code attempted to define namespace!", Error::DEFINE_NAMESPACE_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('namespace')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'namespace'); + } + if($node->name instanceof Node\Name){ + $namespace = $node->name->toString(); + $this->sandbox->checkNamespace($namespace); + if(!$this->sandbox->isDefinedNamespace($namespace)){ + $this->sandbox->defineNamespace($namespace); + } + } else { + $this->sandbox->validationError("Sandboxed code attempted use invalid namespace!", Error::DEFINE_NAMESPACE_ERROR, $node); + } + return $node->stmts; + } else if($node instanceof Node\Stmt\Use_){ + if(!$this->sandbox->allow_aliases){ + $this->sandbox->validationError("Sandboxed code attempted to use namespace and/or alias!", Error::DEFINE_ALIAS_ERROR, $node); + } + if(!$this->sandbox->checkKeyword('use')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'use'); + } + foreach($node->uses as $use){ + /** + * @var Node\Stmt\UseUse $use + */ + if($use instanceof Node\Stmt\UseUse && $use->name instanceof Node\Name && (is_string($use->alias) || is_null($use->alias))){ + $this->sandbox->checkAlias($use->name->toString()); + if($use->alias){ + if(!$this->sandbox->checkKeyword('as')){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'as'); + } + } + $this->sandbox->defineAlias($use->name->toString(), $use->alias); + } else { + $this->sandbox->validationError("Sandboxed code attempted use invalid namespace or alias!", Error::DEFINE_ALIAS_ERROR, $node); + } + } + return false; + } else if($node instanceof Node\Expr\ShellExec){ + if($this->sandbox->isDefinedFunc('shell_exec')){ + $args = [ + new Node\Arg(new Node\Scalar\String_('shell_exec')), + new Node\Arg(new Node\Scalar\String_(implode('', $node->parts))) + ]; + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), 'call_func', $args, $node->getAttributes()); + } + if($this->sandbox->hasWhitelistedFuncs()){ + if(!$this->sandbox->isWhitelistedFunc('shell_exec')){ + $this->sandbox->validationError("Sandboxed code attempted to use shell execution backticks when the shell_exec function is not whitelisted!", Error::BACKTICKS_ERROR, $node); + } + } else if($this->sandbox->hasBlacklistedFuncs() && $this->sandbox->isBlacklistedFunc('shell_exec')){ + $this->sandbox->validationError("Sandboxed code attempted to use shell execution backticks when the shell_exec function is blacklisted!", Error::BACKTICKS_ERROR, $node); + } + if(!$this->sandbox->allow_backticks){ + $this->sandbox->validationError("Sandboxed code attempted to use shell execution backticks!", Error::BACKTICKS_ERROR, $node); + } + } else if($name = $this->isMagicConst($node)){ + if(!$this->sandbox->checkMagicConst($name)){ + $this->sandbox->validationError("Magic constant failed custom validation!", Error::VALID_MAGIC_CONST_ERROR, $node, $name); + } + if($this->sandbox->isDefinedMagicConst($name)){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_get_magic_const', [new Node\Arg(new Node\Scalar\String_($name))], $node->getAttributes()); + } + } else if($name = $this->isKeyword($node)){ + if(!$this->sandbox->checkKeyword($name)){ + $this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, $name); + } + if($node instanceof Node\Expr\Include_ && !$this->sandbox->allow_includes){ + $this->sandbox->validationError("Sandboxed code attempted to include files!", Error::INCLUDE_ERROR, $node, $name); + } else if($node instanceof Node\Expr\Include_ && + ( + ($node->type == Node\Expr\Include_::TYPE_INCLUDE && $this->sandbox->isDefinedFunc('include')) + || ($node->type == Node\Expr\Include_::TYPE_INCLUDE_ONCE && $this->sandbox->isDefinedFunc('include_once')) + || ($node->type == Node\Expr\Include_::TYPE_REQUIRE && $this->sandbox->isDefinedFunc('require')) + || ($node->type == Node\Expr\Include_::TYPE_REQUIRE_ONCE && $this->sandbox->isDefinedFunc('require_once')) + )){ + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), 'call_func', [new Node\Arg(new Node\Scalar\String_($name)), new Node\Arg($node->expr)], $node->getAttributes()); + } else if($node instanceof Node\Expr\Include_ && $this->sandbox->sandbox_includes){ + switch($node->type){ + case Node\Expr\Include_::TYPE_INCLUDE_ONCE: + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_include_once', [new Node\Arg($node->expr)], $node->getAttributes()); + break; + case Node\Expr\Include_::TYPE_REQUIRE: + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_require', [new Node\Arg($node->expr)], $node->getAttributes()); + break; + case Node\Expr\Include_::TYPE_REQUIRE_ONCE: + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_require_once', [new Node\Arg($node->expr)], $node->getAttributes()); + break; + case Node\Expr\Include_::TYPE_INCLUDE: + default: + return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_include', [new Node\Arg($node->expr)], $node->getAttributes()); + break; + } + } + } else if($name = $this->isOperator($node)){ + if(!$this->sandbox->checkOperator($name)){ + $this->sandbox->validationError("Operator failed custom validation!", Error::VALID_OPERATOR_ERROR, $node, $name); + } + } else if($name = $this->isPrimitive($node)){ + if(!$this->sandbox->checkPrimitive($name)){ + $this->sandbox->validationError("Primitive failed custom validation!", Error::VALID_PRIMITIVE_ERROR, $node, $name); + } + } + return null; + } + +} \ No newline at end of file diff --git a/classes/Sandbox/FunctionExecutor.php b/classes/Sandbox/FunctionExecutor.php new file mode 100644 index 0000000..52e599b --- /dev/null +++ b/classes/Sandbox/FunctionExecutor.php @@ -0,0 +1,34 @@ +sandbox = $sandbox; + } + + public function leaveNode(Node $node){ + if ($node instanceof Node\Expr\FuncCall) { + if($node->name instanceof Node\Name) { + $name = strtolower($node->name->toString()); + try { + $this->sandbox->checkFunc($name); + } catch (\Exception $e) { + return new Node\Expr\StaticCall( + new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\FunctionExecutor"), 'execute', + array_merge([ new Node\Scalar\String_($name) ], $node->args), + $node->getAttributes()); + } + } + } + + return null; + } + +} \ No newline at end of file diff --git a/classes/Session.php b/classes/Session.php new file mode 100644 index 0000000..6b6c7be --- /dev/null +++ b/classes/Session.php @@ -0,0 +1,81 @@ +cookies->has('session')) { + try { + // attempt to restore session from encrypted data + $key = Key::loadFromAsciiSafeString($keyString); + $sessionContent = json_decode(Crypto::decrypt($request->cookies->get('session'), $key), true); + if (!isset($sessionContent['id']) || !isset($sessionContent['data'])) + throw new \Exception; + $session->id = $sessionContent['id']; + $session->data = $sessionContent['data']; + } catch (\Exception $e) { + // session could not be restored, create a new one anonymously + $session->id = uniqid(); + $session->data = []; + } + } else { + // no session found, create one + $session->id = uniqid(); + $session->data = []; + } + + $session->key = $keyString; + + return $session; + } + + public function persistToResponse(Response $response) { + $key = Key::loadFromAsciiSafeString($this->key); + $sessionContent = json_encode([ + 'id' => $this->id, + 'data' => $this->data + ]); + $response->headers->setCookie(new Cookie('session', + Crypto::encrypt($sessionContent, $key), + new \DateTime('1 hour'))); + } + + public function getId() { + return $this->id; + } + + public function offsetExists($offset) { + return isset($this->data[$offset]); + } + + public function offsetGet($offset) { + return $this->data[$offset]; + } + + public function offsetSet($offset, $value) { + $this->data[$offset] = $value; + } + + public function offsetUnset($offset) { + unset($this->data[$offset]); + } +} \ No newline at end of file diff --git a/classes/TestEnvironmentManager.php b/classes/TestEnvironmentManager.php new file mode 100644 index 0000000..56d3688 --- /dev/null +++ b/classes/TestEnvironmentManager.php @@ -0,0 +1,48 @@ + $c->get('testenv.url') ]); + }); + } + } + + $containerBuilder = new ContainerBuilder; + $containerBuilder->addDefinitions($definitions); + return $containerBuilder->build(); + + } + + public static function setTestEnvironment($url) { + file_put_contents(self::getFileName(), json_encode(array( + 'testenv_url' => $url + ))); + } + + public static function unsetTestEnvironment() { + file_put_contents(self::getFileName(), json_encode(array())); + } + +} diff --git a/classes/TwigTemplate.php b/classes/TwigTemplate.php new file mode 100644 index 0000000..ac42b2f --- /dev/null +++ b/classes/TwigTemplate.php @@ -0,0 +1,25 @@ +key = $key; + $this->environment = new \Twig_Environment( + new \Twig_Loader_Array([ $key => $content ]), + [ 'cache' => $cachePath ] + ); + } + + public function render($context) { + return $this->environment->render($this->key, $context); + } +} \ No newline at end of file diff --git a/classes/TwigTemplateFactory.php b/classes/TwigTemplateFactory.php new file mode 100644 index 0000000..8770bb6 --- /dev/null +++ b/classes/TwigTemplateFactory.php @@ -0,0 +1,28 @@ +cachePath = $cachePath; + } + + /** + * Creates a Twig template. + * + * @param string $string The template content. + * @param string $id An identifier that is used to cache the compiled template. + * If not provided, a hash of the template content is used instead. + */ + public function fromString(string $string, string $id = null) { + if ($id == null) $id = md5($string); + return new TwigTemplate($id, $string, $this->cachePath); + } +} \ No newline at end of file diff --git a/classes/TypeChecker.php b/classes/TypeChecker.php new file mode 100644 index 0000000..19d6a92 --- /dev/null +++ b/classes/TypeChecker.php @@ -0,0 +1,52 @@ + [ + 'phpmae' => 'coid://phpmae.dev/' + ]]); + + return self::$reader->hasType($object, $typeString); + } + + public static function isClass(Node $object) { + return self::isType($object, 'phpmae:Class') + || self::isType($object, 'phpmae:HTTPInvokableClass'); + } + + public static function isInterface(Node $object) { + return self::isType($object, 'phpmae:Interface'); + } + + public static function getAdditionalTypes(Node $object) { + $types = $object->getType(); + if (!is_array($types)) + return []; + + $coids = []; + foreach ($types as $t) { + if (in_array($t->getId(), [ 'coid://phpmae.dev/Class', + 'coid://phpmae.dev/HTTPInvokableClass', + 'coid://phpmae.dev/Interface', + ])) continue; + $coids[] = new IRI($t->getId()); + } + + return $coids; + } + +} diff --git a/classes/UploadController.php b/classes/UploadController.php new file mode 100644 index 0000000..89ebbee --- /dev/null +++ b/classes/UploadController.php @@ -0,0 +1,106 @@ +container = $container; + $this->objectRetriever = $objectRetriever; + $this->classRepository = $classRepository; + } + + private function uploadSource(RequestInterface $request) { + $object = $this->objectRetriever->get($request->getQueryParam('coid')); + if (!$object) + throw new PhpMAEException("Unable to retrieve object."); + + $content = (string)$request->getBody(); + $validator = new ClassValidator; + + try { + $validator->validate($content, + new IRI($object->getId()), + TypeChecker::getAdditionalTypes($object)); + } catch (\Exception $e) { + $response = (new Response(400))->withJson([ + 'error_code' => get_class($e), + 'error_message' => $e->getMessage() + ]); + return $response; + } + + if ($this->classRepository->storeUploadedFile($object, $content)) + return new Response(201); + else + return new Response(500); + } + + private function uploadConfig(RequestInterface $request) { + // Parse RDF/XML config + $parser = \ARC2::getRDFXMLParser(); + $parser->parse('', (string)$request->getBody()); + $index = $parser->getSimpleIndex(false); + + // Convert to JsonLD as required by the CloudObjects SDK + $jsonLdConfig = JsonLD::compact( + JsonLD::fromRdf(Arc2JsonLdConverter::indexToQuads($index))); + + // Validate config + if (!isset($jsonLdConfig->{'@id'}) + || $jsonLdConfig->{'@id'} != $request->getQueryParam('coid')) { + throw new PhpMAEException("Uploaded configuration does not correspond to object."); + } + + // Store configuration + $iri = new IRI($request->getQueryParam('coid')); + $path = $this->container->get('uploads_dir') + .DIRECTORY_SEPARATOR.'config' + .DIRECTORY_SEPARATOR.$iri->getHost() + .$iri->getPath(); + if (!is_dir($path)) mkdir($path, 0777, true); + + file_put_contents($path.DIRECTORY_SEPARATOR.'object.jsonld', json_encode($jsonLdConfig)); + + return new Response(201); + } + + public function handle(RequestInterface $request) { + if (!$this->container->has('uploads') || $this->container->get('uploads') !== true) + throw new PhpMAEException("This is not a test environment where uploads are permitted."); + + if ($request->getMethod() != 'PUT') + throw new PhpMAEException("Must use PUT for uploading to test environment."); + + switch ($request->getQueryParam('type')) { + case "source": + return $this->uploadSource($request); + break; + case "config": + return $this->uploadConfig($request); + break; + default: + throw new PhpMAEException("Invalid test environment request."); + } + } + +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..0334b84 --- /dev/null +++ b/composer.json @@ -0,0 +1,42 @@ +{ + "name" : "cloudobjects/phpmae", + "description" : "The PHP Micro API Engine.", + "keywords": ["cloudobjects", "serverless", "faas", "microapi", "sandbox"], + "homepage": "https://github.com/CloudObjects/phpMAE", + "license": "MPL-2.0", + "require": { + "symfony/console" : "^4.2.1", + "corveda/php-sandbox": "^2.0.1", + "cloudobjects/sdk" : "dev-main", + "php-di/php-di": "^6.0", + "slim/slim" : "^3.0", + "jsonrpc/jsonrpc": "^1.0", + "vlucas/phpdotenv" : "^2.4.0", + "semsol/arc2" : "~2.3.1", + "cloudobjects/rdfutilities" : "dev-main", + "tuupola/slim-basic-auth": "^3.2", + "dflydev/fig-cookies": "^1.0", + "doctrine/collections": "^1.5", + "twig/twig": "^2.5", + "monolog/monolog": "^1.24", + "guzzlehttp/oauth-subscriber": "^0.3.0", + "webmozart/assert": "^1.3", + "psr/simple-cache": "^1.0", + "tuupola/cors-middleware": "^1.1", + "relay/relay": "^2.1", + "symfony/mailer": "^5.3" + }, + "autoload": { + "psr-4": { + "CloudObjects\\PhpMAE\\" : "classes" + }, + "files" : [ + "vendor/semsol/arc2/ARC2_getFormat.php", + "vendor/semsol/arc2/ARC2_getPreferredFormat.php" + ] + }, + "require-dev" : { + "phpunit/phpunit": "~5.7", + "consolidation/robo": "~1" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..191eeb9 --- /dev/null +++ b/composer.lock @@ -0,0 +1,6578 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "9c597659dd32b0dc330574e32fc4d933", + "packages": [ + { + "name": "cloudobjects/rdfutilities", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/CloudObjects/RDFUtilities.git", + "reference": "9d80a42b15b7c853d3f9a134567d99c49b6e1e77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CloudObjects/RDFUtilities/zipball/9d80a42b15b7c853d3f9a134567d99c49b6e1e77", + "reference": "9d80a42b15b7c853d3f9a134567d99c49b6e1e77", + "shasum": "" + }, + "require": { + "ml/json-ld": ">=1.0.3", + "semsol/arc2": ">=2.1.0" + }, + "require-dev": { + "phpunit/phpunit": ">=4.8.0,<5.0" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "CloudObjects\\Utilities\\RDF\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MPL-2.0" + ], + "authors": [ + { + "name": "Lukas Rosenstock" + } + ], + "description": "ARC2JsonLD Helper Class", + "homepage": "https://github.com/CloudObjects/RDFUtilities", + "keywords": [ + "JSON-LD", + "RDF", + "arc2", + "cloudobjects" + ], + "support": { + "issues": "https://github.com/CloudObjects/RDFUtilities/issues", + "source": "https://github.com/CloudObjects/RDFUtilities/tree/main" + }, + "time": "2020-11-25T15:00:13+00:00" + }, + { + "name": "cloudobjects/sdk", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/CloudObjects/CloudObjects-PHP-SDK.git", + "reference": "f2f5202fd2de273a4b74d666f24743bbf4ed61ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CloudObjects/CloudObjects-PHP-SDK/zipball/f2f5202fd2de273a4b74d666f24743bbf4ed61ff", + "reference": "f2f5202fd2de273a4b74d666f24743bbf4ed61ff", + "shasum": "" + }, + "require": { + "doctrine/cache": "1.*", + "doctrine/common": ">=2.6.1", + "guzzlehttp/guzzle": ">=6.0", + "kevinrob/guzzle-cache-middleware": "^3.2", + "ml/json-ld": ">=1.0.7", + "psr/log": "^1.1", + "webmozart/assert": "^1.6" + }, + "require-dev": { + "defuse/php-encryption": "^2.2", + "phpunit/phpunit": ">=4.8.0,<5.0", + "symfony/http-foundation": ">=4.0", + "symfony/psr-http-message-bridge": ">=1.1.0", + "zendframework/zend-diactoros": "~1.8.6" + }, + "suggest": { + "defuse/php-encryption": "Required to use CryptoHelper", + "symfony/http-foundation": "Required to use parseSymfonyRequest() in AccountContext.", + "symfony/psr-http-message-bridge": "Required to use parseSymfonyRequest() in AccountContext.", + "zendframework/zend-diactoros": "Required to use parseSymfonyRequest() in AccountContext." + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-0": { + "CloudObjects\\SDK": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MPL-2.0" + ], + "authors": [ + { + "name": "Lukas Rosenstock" + } + ], + "description": "CloudObjects SDK for PHP for working with COIDs and object descriptions from CloudObjects.", + "homepage": "https://github.com/CloudObjects/CloudObjects-PHP-SDK", + "keywords": [ + "cloudobjects", + "sdk" + ], + "support": { + "issues": "https://github.com/CloudObjects/CloudObjects-PHP-SDK/issues", + "source": "https://github.com/CloudObjects/CloudObjects-PHP-SDK/tree/main" + }, + "time": "2021-07-24T10:12:33+00:00" + }, + { + "name": "corveda/php-sandbox", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/Corveda/PHPSandbox.git", + "reference": "d82fe60d58fbc8d01e61facd963296df372eeeb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Corveda/PHPSandbox/zipball/d82fe60d58fbc8d01e61facd963296df372eeeb7", + "reference": "d82fe60d58fbc8d01e61facd963296df372eeeb7", + "shasum": "" + }, + "require": { + "jeremeamia/functionparser": "*", + "nikic/php-parser": "2.*", + "php": ">=5.4" + }, + "replace": { + "fieryprophet/php-sandbox": "*" + }, + "require-dev": { + "phpunit/phpunit": "4.8.*", + "symfony/yaml": "~2.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "PHPSandbox\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Elijah Horton", + "email": "elijah@corveda.com" + }, + { + "name": "Corveda, LLC." + } + ], + "description": "A PHP library that can be used to run PHP code in a sandboxed environment", + "homepage": "https://phpsandbox.org/", + "keywords": [ + "blacklist", + "parser", + "php", + "sandbox", + "whitelist" + ], + "support": { + "issues": "https://github.com/Corveda/PHPSandbox/issues", + "source": "https://github.com/Corveda/PHPSandbox/tree/master" + }, + "time": "2016-05-20T20:23:57+00:00" + }, + { + "name": "dflydev/fig-cookies", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-fig-cookies.git", + "reference": "883233c159d00d39e940bd12cfe42c0d23420c1c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-fig-cookies/zipball/883233c159d00d39e940bd12cfe42c0d23420c1c", + "reference": "883233c159d00d39e940bd12cfe42c0d23420c1c", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "~1.0" + }, + "require-dev": { + "codeclimate/php-test-reporter": "~0.1@dev", + "phpunit/phpunit": "~4.5", + "squizlabs/php_codesniffer": "~2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\FigCookies\\": "src/Dflydev/FigCookies" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Beau Simensen", + "email": "beau@dflydev.com" + } + ], + "description": "Cookies for PSR-7 HTTP Message Interface.", + "keywords": [ + "cookies", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-fig-cookies/issues", + "source": "https://github.com/dflydev/dflydev-fig-cookies/tree/master" + }, + "time": "2016-03-28T09:10:18+00:00" + }, + { + "name": "doctrine/annotations", + "version": "1.13.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f", + "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^0.12.20", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", + "symfony/cache": "^4.4 || ^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.13.1" + }, + "time": "2021-05-16T18:07:53+00:00" + }, + { + "name": "doctrine/cache", + "version": "1.12.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "4cf401d14df219fa6f38b671f5493449151c9ad8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/4cf401d14df219fa6f38b671f5493449151c9ad8", + "reference": "4cf401d14df219fa6f38b671f5493449151c9ad8", + "shasum": "" + }, + "require": { + "php": "~7.1 || ^8.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "cache/integration-tests": "dev-master", + "doctrine/coding-standard": "^8.0", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "predis/predis": "~1.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev", + "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", + "keywords": [ + "abstraction", + "apcu", + "cache", + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" + ], + "support": { + "issues": "https://github.com/doctrine/cache/issues", + "source": "https://github.com/doctrine/cache/tree/1.12.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", + "type": "tidelift" + } + ], + "time": "2021-07-17T14:39:21+00:00" + }, + { + "name": "doctrine/collections", + "version": "1.6.7", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "55f8b799269a1a472457bd1a41b4f379d4cfba4a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/55f8b799269a1a472457bd1a41b4f379d4cfba4a", + "reference": "55f8b799269a1a472457bd1a41b4f379d4cfba4a", + "shasum": "" + }, + "require": { + "php": "^7.1.3 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan-shim": "^0.9.2", + "phpunit/phpunit": "^7.0", + "vimeo/psalm": "^3.8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/collections/issues", + "source": "https://github.com/doctrine/collections/tree/1.6.7" + }, + "time": "2020-07-27T17:53:49+00:00" + }, + { + "name": "doctrine/common", + "version": "3.1.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "a036d90c303f3163b5be8b8fde9b6755b2be4a3a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/a036d90c303f3163b5be8b8fde9b6755b2be4a3a", + "reference": "a036d90c303f3163b5be8b8fde9b6755b2be4a3a", + "shasum": "" + }, + "require": { + "doctrine/persistence": "^2.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0 || ^8.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "^4.0.5", + "vimeo/psalm": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.", + "homepage": "https://www.doctrine-project.org/projects/common.html", + "keywords": [ + "common", + "doctrine", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/common/issues", + "source": "https://github.com/doctrine/common/tree/3.1.2" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcommon", + "type": "tidelift" + } + ], + "time": "2021-02-10T20:18:51+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "v0.5.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "9504165960a1f83cc1480e2be1dd0a0478561314" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314", + "reference": "9504165960a1f83cc1480e2be1dd0a0478561314", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0|^7.0|^8.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v0.5.3" + }, + "time": "2021-03-21T12:59:47+00:00" + }, + { + "name": "doctrine/event-manager", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f", + "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/common": "<2.9@dev" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "keywords": [ + "event", + "event dispatcher", + "event manager", + "event system", + "events" + ], + "support": { + "issues": "https://github.com/doctrine/event-manager/issues", + "source": "https://github.com/doctrine/event-manager/tree/1.1.x" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager", + "type": "tidelift" + } + ], + "time": "2020-05-29T18:28:51+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2020-05-25T17:44:05+00:00" + }, + { + "name": "doctrine/persistence", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/persistence.git", + "reference": "d138f3ab5f761055cab1054070377cfd3222e368" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/d138f3ab5f761055cab1054070377cfd3222e368", + "reference": "d138f3ab5f761055cab1054070377cfd3222e368", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/collections": "^1.0", + "doctrine/deprecations": "^0.5.3", + "doctrine/event-manager": "^1.0", + "php": "^7.1 || ^8.0", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "conflict": { + "doctrine/common": "<2.10@dev" + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.11", + "doctrine/coding-standard": "^6.0 || ^9.0", + "doctrine/common": "^3.0", + "phpstan/phpstan": "0.12.84", + "phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", + "symfony/cache": "^4.4|^5.0", + "vimeo/psalm": "4.7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common", + "Doctrine\\Persistence\\": "lib/Doctrine/Persistence" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.", + "homepage": "https://doctrine-project.org/projects/persistence.html", + "keywords": [ + "mapper", + "object", + "odm", + "orm", + "persistence" + ], + "support": { + "issues": "https://github.com/doctrine/persistence/issues", + "source": "https://github.com/doctrine/persistence/tree/2.2.1" + }, + "time": "2021-05-19T07:07:01+00:00" + }, + { + "name": "egulias/email-validator", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "c81f18a3efb941d8c4d2e025f6183b5c6d697307" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/c81f18a3efb941d8c4d2e025f6183b5c6d697307", + "reference": "c81f18a3efb941d8c4d2e025f6183b5c6d697307", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.2", + "php": ">=7.2", + "symfony/polyfill-intl-idn": "^1.15" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^8.5.8|^9.3.3", + "vimeo/psalm": "^4" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2021-04-01T18:37:14+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.5", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.6.1", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5" + }, + "time": "2020-06-16T21:01:06+00:00" + }, + { + "name": "guzzlehttp/oauth-subscriber", + "version": "0.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/oauth-subscriber.git", + "reference": "04960cdef3cd80ea401d6b0ca8b3e110e9bf12cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/oauth-subscriber/zipball/04960cdef3cd80ea401d6b0ca8b3e110e9bf12cf", + "reference": "04960cdef3cd80ea401d6b0ca8b3e110e9bf12cf", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "~6.0", + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.3-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Subscriber\\Oauth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle OAuth 1.0 subscriber", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "oauth" + ], + "support": { + "issues": "https://github.com/guzzle/oauth-subscriber/issues", + "source": "https://github.com/guzzle/oauth-subscriber/tree/master" + }, + "time": "2015-08-15T19:44:28+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.4.1" + }, + "time": "2021-03-07T09:25:29+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.8.2" + }, + "time": "2021-04-26T09:17:50+00:00" + }, + { + "name": "jeremeamia/functionparser", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/jeremeamia/FunctionParser.git", + "reference": "035b52000b88ea8d72a6647dd4cd39f080cf7ada" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jeremeamia/FunctionParser/zipball/035b52000b88ea8d72a6647dd4cd39f080cf7ada", + "reference": "035b52000b88ea8d72a6647dd4cd39f080cf7ada", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "FunctionParser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Lindblom" + } + ], + "description": "Function parser for PHP functions, methods, and closures", + "homepage": "https://github.com/jeremeamia/FunctionParser", + "keywords": [ + "closure", + "function", + "parser", + "tokenizer" + ], + "support": { + "issues": "https://github.com/jeremeamia/FunctionParser/issues", + "source": "https://github.com/jeremeamia/FunctionParser/tree/1.0.0" + }, + "time": "2015-02-02T17:30:47+00:00" + }, + { + "name": "jsonrpc/jsonrpc", + "version": "v1.0.3", + "source": { + "type": "git", + "url": "https://github.com/johnstevenson/jsonrpc.git", + "reference": "0fcc660ca211a871fe656066e8921406a4c3a2ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/johnstevenson/jsonrpc/zipball/0fcc660ca211a871fe656066e8921406a4c3a2ae", + "reference": "0fcc660ca211a871fe656066e8921406a4c3a2ae", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonRpc": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "JSON-RPC 2.0 client/server implementation", + "homepage": "http://github.com/johnstevenson/jsonrpc", + "keywords": [ + "api", + "json", + "json-rpc", + "rpc" + ], + "support": { + "issues": "https://github.com/johnstevenson/jsonrpc/issues", + "source": "https://github.com/johnstevenson/jsonrpc/tree/v1.0.3" + }, + "time": "2012-11-30T21:43:30+00:00" + }, + { + "name": "kevinrob/guzzle-cache-middleware", + "version": "v3.4.1", + "source": { + "type": "git", + "url": "https://github.com/Kevinrob/guzzle-cache-middleware.git", + "reference": "122e309f64934511146a88d5645599f561b6fae3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Kevinrob/guzzle-cache-middleware/zipball/122e309f64934511146a88d5645599f561b6fae3", + "reference": "122e309f64934511146a88d5645599f561b6fae3", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "guzzlehttp/psr7": "^1.7.0", + "php": ">=5.5.0" + }, + "require-dev": { + "cache/array-adapter": "^0.4 || ^0.5 || ^1.0", + "cache/simple-cache-bridge": "^0.1 || ^1.0", + "doctrine/cache": "^1.0", + "illuminate/cache": "^5.0", + "league/flysystem": "^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.0", + "psr/cache": "^1.0", + "symfony/phpunit-bridge": "^4.4 || ^5.0" + }, + "suggest": { + "doctrine/cache": "This library has a lot of ready-to-use cache storage (to be used with Kevinrob\\GuzzleCache\\Storage\\DoctrineCacheStorage).", + "guzzlehttp/guzzle": "For using this library. It was created for Guzzle6 (but you can use it with any PSR-7 HTTP client).", + "laravel/framework": "To be used with Kevinrob\\GuzzleCache\\Storage\\LaravelCacheStorage", + "league/flysystem": "To be used with Kevinrob\\GuzzleCache\\Storage\\FlysystemStorage", + "psr/cache": "To be used with Kevinrob\\GuzzleCache\\Storage\\Psr6CacheStorage", + "psr/simple-cache": "To be used with Kevinrob\\GuzzleCache\\Storage\\Psr16CacheStorage" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kevinrob\\GuzzleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Robatel", + "email": "kevinrob2@gmail.com", + "homepage": "https://github.com/Kevinrob" + } + ], + "description": "A HTTP/1.1 Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack. (RFC 7234)", + "homepage": "https://github.com/Kevinrob/guzzle-cache-middleware", + "keywords": [ + "Etag", + "Flysystem", + "Guzzle", + "cache", + "cache-control", + "doctrine", + "expiration", + "guzzle6", + "handler", + "http", + "http 1.1", + "middleware", + "performance", + "php", + "promise", + "psr6", + "psr7", + "rfc7234", + "validation" + ], + "support": { + "issues": "https://github.com/Kevinrob/guzzle-cache-middleware/issues", + "source": "https://github.com/Kevinrob/guzzle-cache-middleware/tree/v3.4.1" + }, + "time": "2021-07-11T09:00:28+00:00" + }, + { + "name": "ml/iri", + "version": "1.1.4", + "target-dir": "ML/IRI", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/IRI.git", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", + "shasum": "" + }, + "require": { + "lib-pcre": ">=4.0", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ML\\IRI": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "IRI handling for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "URN", + "iri", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/lanthaler/IRI/issues", + "source": "https://github.com/lanthaler/IRI/tree/master" + }, + "time": "2014-01-21T13:43:39+00:00" + }, + { + "name": "ml/json-ld", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/JsonLD.git", + "reference": "c74a1aed5979ed1cfb1be35a55a305fd30e30b93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/c74a1aed5979ed1cfb1be35a55a305fd30e30b93", + "reference": "c74a1aed5979ed1cfb1be35a55a305fd30e30b93", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ml/iri": "^1.1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "json-ld/tests": "1.0", + "phpunit/phpunit": "^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ML\\JsonLD\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "JSON-LD Processor for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "JSON-LD", + "jsonld" + ], + "support": { + "issues": "https://github.com/lanthaler/JsonLD/issues", + "source": "https://github.com/lanthaler/JsonLD/tree/1.2.0" + }, + "time": "2020-06-16T17:45:06+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.26.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c6b00f05152ae2c9b04a448f99c7590beb6042f5", + "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "~4.5", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.26.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2021-05-28T08:32:12+00:00" + }, + { + "name": "neomerx/cors-psr7", + "version": "v1.0.13", + "source": { + "type": "git", + "url": "https://github.com/neomerx/cors-psr7.git", + "reference": "2556e2013f16a55532c95928455257d5b6bbc6e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/neomerx/cors-psr7/zipball/2556e2013f16a55532c95928455257d5b6bbc6e2", + "reference": "2556e2013f16a55532c95928455257d5b6bbc6e2", + "shasum": "" + }, + "require": { + "php": ">=5.6.0", + "psr/http-message": "^1.0", + "psr/log": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^5.7", + "scrutinizer/ocular": "^1.1", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Neomerx\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "neomerx", + "email": "info@neomerx.com" + } + ], + "description": "Framework agnostic (PSR-7) CORS implementation (www.w3.org/TR/cors/)", + "homepage": "https://github.com/neomerx/cors-psr7", + "keywords": [ + "Cross Origin Resource Sharing", + "Cross-Origin Resource Sharing", + "cors", + "neomerx", + "psr-7", + "psr7", + "w3.org", + "www.w3.org" + ], + "support": { + "issues": "https://github.com/neomerx/cors-psr7/issues", + "source": "https://github.com/neomerx/cors-psr7/tree/develop" + }, + "time": "2018-05-23T16:10:11+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "FastRoute\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "support": { + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/master" + }, + "time": "2018-02-13T20:26:39+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4dd659edadffdc2143e4753df655d866dbfeedf0", + "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/2.x" + }, + "time": "2016-09-16T12:04:44+00:00" + }, + { + "name": "opis/closure", + "version": "3.6.2", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6", + "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Closure\\": "src/" + }, + "files": [ + "functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/opis/closure/issues", + "source": "https://github.com/opis/closure/tree/3.6.2" + }, + "time": "2021-04-09T13:42:10+00:00" + }, + { + "name": "php-di/invoker", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "540c27c86f663e20fe39a24cd72fa76cdb21d41a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/540c27c86f663e20fe39a24cd72fa76cdb21d41a", + "reference": "540c27c86f663e20fe39a24cd72fa76cdb21d41a", + "shasum": "" + }, + "require": { + "psr/container": "~1.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "phpunit/phpunit": "~4.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/master" + }, + "time": "2017-03-20T19:28:22+00:00" + }, + { + "name": "php-di/php-di", + "version": "6.3.4", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "f53bcba06ab31b18e911b77c039377f4ccd1f7a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/f53bcba06ab31b18e911b77c039377f4ccd1f7a5", + "reference": "f53bcba06ab31b18e911b77c039377f4ccd1f7a5", + "shasum": "" + }, + "require": { + "opis/closure": "^3.5.5", + "php": ">=7.2.0", + "php-di/invoker": "^2.0", + "php-di/phpdoc-reader": "^2.0.1", + "psr/container": "^1.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "doctrine/annotations": "~1.2", + "friendsofphp/php-cs-fixer": "^2.4", + "mnapoli/phpunit-easymock": "^1.2", + "ocramius/proxy-manager": "^2.0.2", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^8.5|^9.0" + }, + "suggest": { + "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + }, + "type": "library", + "autoload": { + "psr-4": { + "DI\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/6.3.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "time": "2021-06-10T08:04:48+00:00" + }, + { + "name": "php-di/phpdoc-reader", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PhpDocReader.git", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^8.5|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpDocReader\\": "src/PhpDocReader" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", + "keywords": [ + "phpdoc", + "reflection" + ], + "support": { + "issues": "https://github.com/PHP-DI/PhpDocReader/issues", + "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" + }, + "time": "2020-10-12T12:39:22+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "86406047271859ffc13424a048541f4531f53601" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/86406047271859ffc13424a048541f4531f53601", + "reference": "86406047271859ffc13424a048541f4531f53601", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "https://pimple.symfony.com", + "keywords": [ + "container", + "dependency injection" + ], + "support": { + "source": "https://github.com/silexphp/Pimple/tree/v3.4.0" + }, + "time": "2021-03-06T08:28:00+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-handler/issues", + "source": "https://github.com/php-fig/http-server-handler/tree/master" + }, + "time": "2018-10-30T16:46:14+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/master" + }, + "time": "2018-10-30T17:12:04+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "relay/relay", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/relayphp/Relay.Relay.git", + "reference": "924fdf9473492d6d221bd7760a8f201f8b35d96c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/relayphp/Relay.Relay/zipball/924fdf9473492d6d221bd7760a8f201f8b35d96c", + "reference": "924fdf9473492d6d221bd7760a8f201f8b35d96c", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "~1.0", + "psr/http-server-handler": "~1.0", + "psr/http-server-middleware": "^1.0" + }, + "provide": { + "psr/http-server-handler-implementation": "1.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0", + "friendsofphp/php-cs-fixer": "^3.0", + "laminas/laminas-diactoros": "~2.2", + "phpstan/phpstan": "^0.12.14", + "phpunit/phpunit": "~7.0 || ~9.5", + "roave/security-advisories": "dev-master", + "vimeo/psalm": "^4.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Relay\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Relay.Relay Contributors", + "homepage": "https://github.com/relayphp/Relay.Relay/contributors" + } + ], + "description": "A PSR-15 server request handler.", + "homepage": "https://github.com/relayphp/Relay.Relay", + "keywords": [ + "middleware", + "psr-15", + "psr-7" + ], + "support": { + "issues": "https://github.com/relayphp/Relay.Relay/issues", + "source": "https://github.com/relayphp/Relay.Relay/tree/2.1.2" + }, + "time": "2021-05-23T05:42:52+00:00" + }, + { + "name": "semsol/arc2", + "version": "2.3.1", + "source": { + "type": "git", + "url": "https://github.com/semsol/arc2.git", + "reference": "d520631fc10175533f8003b2a1ee1a56c7b5f2d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/semsol/arc2/zipball/d520631fc10175533f8003b2a1ee1a56c7b5f2d0", + "reference": "d520631fc10175533f8003b2a1ee1a56c7b5f2d0", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "./", + "parsers/", + "serializers/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "W3C" + ], + "authors": [ + { + "name": "Benji Nowack", + "homepage": "http://bnowack.de/" + } + ], + "description": "ARC2 RDF library for PHP", + "homepage": "https://github.com/semsol/arc2", + "keywords": [ + "RDF", + "sparql" + ], + "support": { + "issues": "https://github.com/semsol/arc2/issues", + "source": "https://github.com/semsol/arc2/tree/master" + }, + "time": "2017-06-26T09:46:05+00:00" + }, + { + "name": "slim/slim", + "version": "3.12.3", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "1c9318a84ffb890900901136d620b4f03a59da38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/1c9318a84ffb890900901136d620b4f03a59da38", + "reference": "1c9318a84ffb890900901136d620b4f03a59da38", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "nikic/fast-route": "^1.0", + "php": ">=5.5.0", + "pimple/pimple": "^3.0", + "psr/container": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0", + "squizlabs/php_codesniffer": "^2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "support": { + "issues": "https://github.com/slimphp/Slim/issues", + "source": "https://github.com/slimphp/Slim/tree/3.x" + }, + "time": "2019-11-28T17:40:33+00:00" + }, + { + "name": "symfony/console", + "version": "v4.4.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "9aa1eb46c1b12fada74dc0c529e93d1ccef22576" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/9aa1eb46c1b12fada74dc0c529e93d1ccef22576", + "reference": "9aa1eb46c1b12fada74dc0c529e93d1ccef22576", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.26" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-06-06T09:12:27+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-23T23:28:01+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.25", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "047773e7016e4fd45102cedf4bd2558ae0d0c32f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/047773e7016e4fd45102cedf4bd2558ae0d0c32f", + "reference": "047773e7016e4fd45102cedf4bd2558ae0d0c32f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.25" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-26T17:39:37+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-06T13:19:58+00:00" + }, + { + "name": "symfony/mailer", + "version": "v5.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "c1f83da2296741110be35dd779f2a9e412cec466" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/c1f83da2296741110be35dd779f2a9e412cec466", + "reference": "c1f83da2296741110be35dd779f2a9e412cec466", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3", + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/mime": "^5.2.6", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/http-kernel": "<4.4" + }, + "require-dev": { + "symfony/http-client-contracts": "^1.1|^2", + "symfony/messenger": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v5.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-07-23T15:55:36+00:00" + }, + { + "name": "symfony/mime", + "version": "v5.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "633e4e8afe9e529e5599d71238849a4218dd497b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/633e4e8afe9e529e5599d71238849a4218dd497b", + "reference": "633e4e8afe9e529e5599d71238849a4218dd497b", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/property-access": "^4.4|^5.1", + "symfony/property-info": "^4.4|^5.1", + "symfony/serializer": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v5.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-07-21T12:40:44+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-27T09:27:20+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-27T09:27:20+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-27T09:17:38+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", + "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-04-01T10:43:52+00:00" + }, + { + "name": "tuupola/callable-handler", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/tuupola/callable-handler.git", + "reference": "0bc7b88630ca753de9aba8f411046856f5ca6f8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tuupola/callable-handler/zipball/0bc7b88630ca753de9aba8f411046856f5ca6f8c", + "reference": "0bc7b88630ca753de9aba8f411046856f5ca6f8c", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0", + "psr/http-server-middleware": "^1.0" + }, + "require-dev": { + "overtrue/phplint": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.2", + "tuupola/http-factory": "^0.4.0|^1.0", + "zendframework/zend-diactoros": "^1.6.0|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tuupola\\Middleware\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mika Tuupola", + "email": "tuupola@appelsiini.net", + "homepage": "https://appelsiini.net/", + "role": "Developer" + } + ], + "description": "Compatibility layer for PSR-7 double pass and PSR-15 middlewares.", + "homepage": "https://github.com/tuupola/callable-handler", + "keywords": [ + "middleware", + "psr-15", + "psr-7" + ], + "support": { + "issues": "https://github.com/tuupola/callable-handler/issues", + "source": "https://github.com/tuupola/callable-handler/tree/1.1.0" + }, + "funding": [ + { + "url": "https://github.com/tuupola", + "type": "github" + } + ], + "time": "2020-09-09T08:31:54+00:00" + }, + { + "name": "tuupola/cors-middleware", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/tuupola/cors-middleware.git", + "reference": "4f085d11f349e83d18f1eb5802551353b2b093a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tuupola/cors-middleware/zipball/4f085d11f349e83d18f1eb5802551353b2b093a3", + "reference": "4f085d11f349e83d18f1eb5802551353b2b093a3", + "shasum": "" + }, + "require": { + "neomerx/cors-psr7": "^1.0.4", + "php": "^7.1|^8.0", + "psr/http-message": "^1.0.1", + "psr/http-server-middleware": "^1.0", + "tuupola/callable-handler": "^1.0", + "tuupola/http-factory": "^1.0.2" + }, + "require-dev": { + "equip/dispatch": "^2.0", + "overtrue/phplint": "^1.0", + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.5", + "zendframework/zend-diactoros": "^1.0|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tuupola\\Middleware\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mika Tuupola", + "email": "tuupola@appelsiini.net", + "homepage": "https://appelsiini.net/", + "role": "Developer" + } + ], + "description": "PSR-7 and PSR-15 CORS middleware", + "homepage": "https://github.com/tuupola/cors-middleware", + "keywords": [ + "cors", + "middleware", + "psr-15", + "psr-7" + ], + "support": { + "issues": "https://github.com/tuupola/cors-middleware/issues", + "source": "https://github.com/tuupola/cors-middleware/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/tuupola", + "type": "github" + } + ], + "time": "2020-10-29T11:01:06+00:00" + }, + { + "name": "tuupola/http-factory", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/tuupola/http-factory.git", + "reference": "aa48841a9f572b9cebe9d3ac5d5d3362a83f57ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tuupola/http-factory/zipball/aa48841a9f572b9cebe9d3ac5d5d3362a83f57ac", + "reference": "aa48841a9f572b9cebe9d3ac5d5d3362a83f57ac", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0", + "psr/http-factory": "^1.0" + }, + "conflict": { + "nyholm/psr7": "<1.0" + }, + "provide": { + "psr/http-factory-implementation": "^1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.7.0", + "overtrue/phplint": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tuupola\\Http\\Factory\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mika Tuupola", + "email": "tuupola@appelsiini.net", + "homepage": "https://appelsiini.net/", + "role": "Developer" + } + ], + "description": "Lightweight autodiscovering PSR-17 HTTP factories", + "homepage": "https://github.com/tuupola/http-factory", + "keywords": [ + "http", + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/tuupola/http-factory/issues", + "source": "https://github.com/tuupola/http-factory/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/tuupola", + "type": "github" + } + ], + "time": "2020-10-01T07:46:32+00:00" + }, + { + "name": "tuupola/slim-basic-auth", + "version": "3.3.1", + "source": { + "type": "git", + "url": "https://github.com/tuupola/slim-basic-auth.git", + "reference": "18e49c18f5648b05bb6169d166ccb6f797f0fbc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tuupola/slim-basic-auth/zipball/18e49c18f5648b05bb6169d166ccb6f797f0fbc4", + "reference": "18e49c18f5648b05bb6169d166ccb6f797f0fbc4", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0", + "psr/http-message": "^1.0.1", + "psr/http-server-middleware": "^1.0", + "tuupola/callable-handler": "^0.3.0|^0.4.0|^1.0", + "tuupola/http-factory": "^0.4.0|^1.0.2" + }, + "require-dev": { + "equip/dispatch": "^2.0", + "overtrue/phplint": "^2.0.2", + "phpstan/phpstan": "^0.12.43", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.3.2", + "symfony/process": "^3.3", + "zendframework/zend-diactoros": "^1.3|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tuupola\\Middleware\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mika Tuupola", + "email": "tuupola@appelsiini.net", + "homepage": "https://appelsiini.net/" + } + ], + "description": "PSR-7 and PSR-15 HTTP Basic Authentication Middleware", + "homepage": "https://appelsiini.net/projects/slim-basic-auth", + "keywords": [ + "auth", + "middleware", + "psr-15", + "psr-7" + ], + "support": { + "issues": "https://github.com/tuupola/slim-basic-auth/issues", + "source": "https://github.com/tuupola/slim-basic-auth/tree/3.3.1" + }, + "funding": [ + { + "url": "https://github.com/tuupola", + "type": "github" + } + ], + "time": "2020-10-28T15:22:12+00:00" + }, + { + "name": "twig/twig", + "version": "v2.14.6", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "27e5cf2b05e3744accf39d4c68a3235d9966d260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/27e5cf2b05e3744accf39d4c68a3235d9966d260", + "reference": "27e5cf2b05e3744accf39d4c68a3235d9966d260", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4.9|^5.0.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.14-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v2.14.6" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2021-05-16T12:12:47+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v2.6.7", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "b786088918a884258c9e3e27405c6a4cf2ee246e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b786088918a884258c9e3e27405c6a4cf2ee246e", + "reference": "b786088918a884258c9e3e27405c6a4cf2ee246e", + "shasum": "" + }, + "require": { + "php": "^5.3.9 || ^7.0 || ^8.0", + "symfony/polyfill-ctype": "^1.17" + }, + "require-dev": { + "ext-filter": "*", + "ext-pcre": "*", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator.", + "ext-pcre": "Required to use most of the library." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "homepage": "https://gjcampbell.co.uk/" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://vancelucas.com/" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v2.6.7" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2021-01-20T14:39:13+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" + } + ], + "packages-dev": [ + { + "name": "consolidation/annotated-command", + "version": "4.2.4", + "source": { + "type": "git", + "url": "https://github.com/consolidation/annotated-command.git", + "reference": "ec297e05cb86557671c2d6cbb1bebba6c7ae2c60" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/ec297e05cb86557671c2d6cbb1bebba6c7ae2c60", + "reference": "ec297e05cb86557671c2d6cbb1bebba6c7ae2c60", + "shasum": "" + }, + "require": { + "consolidation/output-formatters": "^4.1.1", + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/console": "^4.4.8|~5.1.0", + "symfony/event-dispatcher": "^4.4.8|^5", + "symfony/finder": "^4.4.8|^5" + }, + "require-dev": { + "phpunit/phpunit": ">=7.5.20", + "squizlabs/php_codesniffer": "^3", + "yoast/phpunit-polyfills": "^0.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\AnnotatedCommand\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Initialize Symfony Console commands from annotated command class methods.", + "support": { + "issues": "https://github.com/consolidation/annotated-command/issues", + "source": "https://github.com/consolidation/annotated-command/tree/4.2.4" + }, + "time": "2020-12-10T16:56:39+00:00" + }, + { + "name": "consolidation/config", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/consolidation/config.git", + "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/config/zipball/cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", + "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^1.1.0", + "grasmash/expander": "^1", + "php": ">=5.4.0" + }, + "require-dev": { + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", + "phpunit/phpunit": "^5", + "squizlabs/php_codesniffer": "2.*", + "symfony/console": "^2.5|^3|^4", + "symfony/yaml": "^2.8.11|^3|^4" + }, + "suggest": { + "symfony/yaml": "Required to use Consolidation\\Config\\Loader\\YamlConfigLoader" + }, + "type": "library", + "extra": { + "scenarios": { + "symfony4": { + "require-dev": { + "symfony/console": "^4.0" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require-dev": { + "symfony/console": "^2.8", + "symfony/event-dispatcher": "^2.8", + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + } + }, + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Provide configuration services for a commandline tool.", + "support": { + "issues": "https://github.com/consolidation/config/issues", + "source": "https://github.com/consolidation/config/tree/master" + }, + "time": "2019-03-03T19:37:04+00:00" + }, + { + "name": "consolidation/log", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/consolidation/log.git", + "reference": "82a2aaaa621a7b976e50a745a8d249d5085ee2b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/log/zipball/82a2aaaa621a7b976e50a745a8d249d5085ee2b1", + "reference": "82a2aaaa621a7b976e50a745a8d249d5085ee2b1", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1.0", + "symfony/console": "^4|^5" + }, + "require-dev": { + "phpunit/phpunit": ">=7.5.20", + "squizlabs/php_codesniffer": "^3", + "yoast/phpunit-polyfills": "^0.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", + "support": { + "issues": "https://github.com/consolidation/log/issues", + "source": "https://github.com/consolidation/log/tree/2.0.2" + }, + "time": "2020-12-10T16:26:23+00:00" + }, + { + "name": "consolidation/output-formatters", + "version": "4.1.2", + "source": { + "type": "git", + "url": "https://github.com/consolidation/output-formatters.git", + "reference": "5821e6ae076bf690058a4de6c94dce97398a69c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/5821e6ae076bf690058a4de6c94dce97398a69c9", + "reference": "5821e6ae076bf690058a4de6c94dce97398a69c9", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^1.1.0", + "php": ">=7.1.3", + "symfony/console": "^4|^5", + "symfony/finder": "^4|^5" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.4.2", + "phpunit/phpunit": ">=7", + "squizlabs/php_codesniffer": "^3", + "symfony/var-dumper": "^4", + "symfony/yaml": "^4", + "yoast/phpunit-polyfills": "^0.2.0" + }, + "suggest": { + "symfony/var-dumper": "For using the var_dump formatter" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\OutputFormatters\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Format text by applying transformations provided by plug-in formatters.", + "support": { + "issues": "https://github.com/consolidation/output-formatters/issues", + "source": "https://github.com/consolidation/output-formatters/tree/4.1.2" + }, + "time": "2020-12-12T19:04:59+00:00" + }, + { + "name": "consolidation/robo", + "version": "1.4.13", + "source": { + "type": "git", + "url": "https://github.com/consolidation/Robo.git", + "reference": "fd28dcca1b935950ece26e63541fbdeeb09f7343" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/Robo/zipball/fd28dcca1b935950ece26e63541fbdeeb09f7343", + "reference": "fd28dcca1b935950ece26e63541fbdeeb09f7343", + "shasum": "" + }, + "require": { + "consolidation/annotated-command": "^2.12.1|^4.1", + "consolidation/config": "^1.2.1", + "consolidation/log": "^1.1.1|^2", + "consolidation/output-formatters": "^3.5.1|^4.1", + "consolidation/self-update": "^1.1.5", + "grasmash/yaml-expander": "^1.4", + "league/container": "^2.4.1", + "php": ">=5.5.0", + "symfony/console": "^2.8|^3|^4", + "symfony/event-dispatcher": "^2.5|^3|^4", + "symfony/filesystem": "^2.5|^3|^4", + "symfony/finder": "^2.5|^3|^4|^5", + "symfony/process": "^2.5|^3|^4" + }, + "replace": { + "codegyre/robo": "< 1.0" + }, + "require-dev": { + "g1a/composer-test-scenarios": "^3", + "natxet/cssmin": "3.0.4", + "patchwork/jsqueeze": "^2", + "pear/archive_tar": "^1.4.4", + "php-coveralls/php-coveralls": "^1", + "phpunit/phpunit": "^5.7.27", + "squizlabs/php_codesniffer": "^3" + }, + "suggest": { + "henrikbjorn/lurker": "For monitoring filesystem changes in taskWatch", + "natxet/CssMin": "For minifying CSS files in taskMinify", + "patchwork/jsqueeze": "For minifying JS files in taskMinify", + "pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively." + }, + "bin": [ + "robo" + ], + "type": "library", + "extra": { + "scenarios": { + "finder5": { + "require": { + "symfony/finder": "^5" + }, + "config": { + "platform": { + "php": "7.2.5" + } + } + }, + "symfony4": { + "require": { + "symfony/console": "^4" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.5.9" + } + }, + "scenario-options": { + "create-lockfile": "false" + } + } + }, + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Robo\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Davert", + "email": "davert.php@resend.cc" + } + ], + "description": "Modern task runner", + "support": { + "issues": "https://github.com/consolidation/Robo/issues", + "source": "https://github.com/consolidation/Robo/tree/1.4.13" + }, + "time": "2020-10-11T04:51:34+00:00" + }, + { + "name": "consolidation/self-update", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/consolidation/self-update.git", + "reference": "dba6b2c0708f20fa3ba8008a2353b637578849b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/self-update/zipball/dba6b2c0708f20fa3ba8008a2353b637578849b4", + "reference": "dba6b2c0708f20fa3ba8008a2353b637578849b4", + "shasum": "" + }, + "require": { + "php": ">=5.5.0", + "symfony/console": "^2.8|^3|^4|^5", + "symfony/filesystem": "^2.5|^3|^4|^5" + }, + "bin": [ + "scripts/release" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "SelfUpdate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alexander Menk", + "email": "menk@mestrona.net" + }, + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Provides a self:update command for Symfony Console applications.", + "support": { + "issues": "https://github.com/consolidation/self-update/issues", + "source": "https://github.com/consolidation/self-update/tree/1.2.0" + }, + "time": "2020-04-13T02:49:20+00:00" + }, + { + "name": "container-interop/container-interop", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "shasum": "" + }, + "require": { + "psr/container": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "homepage": "https://github.com/container-interop/container-interop", + "support": { + "issues": "https://github.com/container-interop/container-interop/issues", + "source": "https://github.com/container-interop/container-interop/tree/master" + }, + "abandoned": "psr/container", + "time": "2017-02-14T19:40:03+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "3fbd874921ab2c041e899d044585a2ab9795df8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/3fbd874921ab2c041e899d044585a2ab9795df8a", + "reference": "3fbd874921ab2c041e899d044585a2ab9795df8a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Dflydev\\DotAccessData": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/master" + }, + "time": "2017-01-20T21:14:22+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^8.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2020-11-10T18:47:58+00:00" + }, + { + "name": "grasmash/expander", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/grasmash/expander.git", + "reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/grasmash/expander/zipball/95d6037344a4be1dd5f8e0b0b2571a28c397578f", + "reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^1.1.0", + "php": ">=5.4" + }, + "require-dev": { + "greg-1-anderson/composer-test-scenarios": "^1", + "phpunit/phpunit": "^4|^5.5.4", + "satooshi/php-coveralls": "^1.0.2|dev-master", + "squizlabs/php_codesniffer": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Grasmash\\Expander\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Grasmick" + } + ], + "description": "Expands internal property references in PHP arrays file.", + "support": { + "issues": "https://github.com/grasmash/expander/issues", + "source": "https://github.com/grasmash/expander/tree/master" + }, + "time": "2017-12-21T22:14:55+00:00" + }, + { + "name": "grasmash/yaml-expander", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/grasmash/yaml-expander.git", + "reference": "3f0f6001ae707a24f4d9733958d77d92bf9693b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/grasmash/yaml-expander/zipball/3f0f6001ae707a24f4d9733958d77d92bf9693b1", + "reference": "3f0f6001ae707a24f4d9733958d77d92bf9693b1", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^1.1.0", + "php": ">=5.4", + "symfony/yaml": "^2.8.11|^3|^4" + }, + "require-dev": { + "greg-1-anderson/composer-test-scenarios": "^1", + "phpunit/phpunit": "^4.8|^5.5.4", + "satooshi/php-coveralls": "^1.0.2|dev-master", + "squizlabs/php_codesniffer": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Grasmash\\YamlExpander\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Grasmick" + } + ], + "description": "Expands internal property references in a yaml file.", + "support": { + "issues": "https://github.com/grasmash/yaml-expander/issues", + "source": "https://github.com/grasmash/yaml-expander/tree/master" + }, + "time": "2017-12-16T16:06:03+00:00" + }, + { + "name": "league/container", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/container.git", + "reference": "8438dc47a0674e3378bcce893a0a04d79a2c22b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/container/zipball/8438dc47a0674e3378bcce893a0a04d79a2c22b3", + "reference": "8438dc47a0674e3378bcce893a0a04d79a2c22b3", + "shasum": "" + }, + "require": { + "container-interop/container-interop": "^1.2", + "php": "^5.4 || ^7.0 || ^8.0" + }, + "provide": { + "container-interop/container-interop-implementation": "^1.2", + "psr/container-implementation": "^1.0" + }, + "replace": { + "orno/di": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36", + "scrutinizer/ocular": "^1.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Container\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Bennett", + "email": "philipobenito@gmail.com", + "homepage": "http://www.philipobenito.com", + "role": "Developer" + } + ], + "description": "A fast and intuitive dependency injection container.", + "homepage": "https://github.com/thephpleague/container", + "keywords": [ + "container", + "dependency", + "di", + "injection", + "league", + "provider", + "service" + ], + "support": { + "issues": "https://github.com/thephpleague/container/issues", + "source": "https://github.com/thephpleague/container/tree/2.5.0" + }, + "funding": [ + { + "url": "https://github.com/philipobenito", + "type": "github" + } + ], + "time": "2021-02-22T09:20:06+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.10.2", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2020-11-13T09:40:50+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.2.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + }, + "time": "2020-09-03T19:13:55+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + }, + "time": "2020-09-17T18:55:26+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.10.3", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "451c3cd1418cf640de218914901e51b064abb093" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5 || ^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.10.3" + }, + "time": "2020-03-05T15:02:03+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "^1.3", + "phpunit/php-text-template": "^1.2", + "phpunit/php-token-stream": "^1.4.2 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "^1.0 || ^2.0" + }, + "require-dev": { + "ext-xdebug": "^2.1.4", + "phpunit/phpunit": "^5.7" + }, + "suggest": { + "ext-xdebug": "^2.5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/4.0" + }, + "time": "2017-04-02T07:44:40+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5" + }, + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/master" + }, + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "791198a2c6254db10131eecfe8c06670700904db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + }, + "abandoned": true, + "time": "2017-11-27T05:48:46+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "5.7.27", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.6.2", + "phpunit/php-code-coverage": "^4.0.4", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "^1.2.4", + "sebastian/diff": "^1.4.3", + "sebastian/environment": "^1.3.4 || ^2.0", + "sebastian/exporter": "~2.0", + "sebastian/global-state": "^1.1", + "sebastian/object-enumerator": "~2.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "^1.0.6|^2.0.1", + "symfony/yaml": "~2.1|~3.0|~4.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/5.7.27" + }, + "time": "2018-02-01T05:50:59+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2 || ^2.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues", + "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/3.4" + }, + "abandoned": true, + "time": "2017-06-30T09:13:00+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:15:22+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/1.2" + }, + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/1.4" + }, + "time": "2017-05-22T07:24:03+00:00" + }, + { + "name": "sebastian/environment", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/master" + }, + "time": "2016-11-26T07:53:53+00:00" + }, + { + "name": "sebastian/exporter", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/master" + }, + "time": "2016-11-19T08:54:04+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/1.1.1" + }, + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/master" + }, + "time": "2017-02-18T15:18:39+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/master" + }, + "time": "2016-11-19T07:33:16+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/master" + }, + "abandoned": true, + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "a501126eb6ec9288a3434af01b3d4499ec1268a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/a501126eb6ec9288a3434af01b3d4499ec1268a0", + "reference": "a501126eb6ec9288a3434af01b3d4499ec1268a0", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v4.4.26" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-06-30T07:12:23+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", + "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-26T12:52:38+00:00" + }, + { + "name": "symfony/process", + "version": "v4.4.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "7e812c84c3f2dba173d311de6e510edf701685a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/7e812c84c3f2dba173d311de6e510edf701685a8", + "reference": "7e812c84c3f2dba173d311de6e510edf701685a8", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v4.4.26" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-06-09T14:57:04+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.4.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "e096ef4b4c4c9a2f72c2ac660f54352cd31c60f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e096ef4b4c4c9a2f72c2ac660f54352cd31c60f8", + "reference": "e096ef4b4c4c9a2f72c2ac660f54352cd31c60f8", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.26" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-06-23T19:06:53+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "cloudobjects/sdk": 20, + "cloudobjects/rdfutilities": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/config.php.default b/config.php.default new file mode 100644 index 0000000..27a73c0 --- /dev/null +++ b/config.php.default @@ -0,0 +1,13 @@ + false, + 'interactive_run' => false, + 'client_authentication' => 'none', + 'mode' => 'default', + 'agws.data_cache' => 'file', + 'log.target' => 'errorlog', + 'log.level' => Monolog\Logger::DEBUG, + 'cache_dir' => sys_get_temp_dir() . '/phpMAE/cache', + 'uploads_dir' => sys_get_temp_dir() . '/phpMAE/uploads', +]; diff --git a/config.php.template b/config.php.template new file mode 100644 index 0000000..0918a6a --- /dev/null +++ b/config.php.template @@ -0,0 +1,94 @@ + false, + + /** + * Specifies whether the interactive runtime is enabled. + * - false: disabled + * - true: enabled + */ + 'interactive_run' => false, + + /** + * Client authentication requires all requests to have HTTP Basic Authentication. + * - none: Authentication is disabled. + * - none:public_only: Authentication is disabled for all classes that have co:isVisibleTo + * and co:permitsUsageTo both set to co:Public. All other classes will be treated + * by other authentication schemes. + * - shared_secret:runclass: Client must authenticate with the shared secret between + * the identity of this phpMAE instance (auth_ns) and the namespace of the class + * that is requested to run + * - shared_secret:: Client must authenticate with the shared secret between + * the identity of this phpMAE instance (auth_ns) and the namespace identified + * by the COID. + * Multiple authentication schemes (except "none") can be separated with the + * pipe (|) character. The first valid scheme will be used. + */ + 'client_authentication' => 'none', + + /** + * Choose whether authentication is only accepted over TLS (HTTPS) connections: + * - true: Credentials are accepted only over HTTPS; this is the default value. + * - false: Credentials are also accepted over insecure connections. This should only + * be used for staging environments or local network deployments. + */ + 'client_authentication_must_be_secure' => false, + + /** + * Choose whether CORS requests are possible and the origins that are allowed: + * - empty string: No CORS + * - '*': All origins allowed. + * - Multiple origins can be separated with the pipe (|). + 'global_cors_origins' => '', + + /** + * Choose an operation mode of this phpMAE instance. + * - default: Runs classes as specified in the request URI. Routing functionality is disabled. + * - router:: Mounts the router specified by the COID. No other classes can be run. + * - router:vhost: Mounts the router specified as phpmae:hasRouter for the namespace + * of the HTTP Host header. + * - router:header: Mounts the router specified by the "C-PhpMae-Router-COID" header. + * Multiple modes can be separated with the pipe (|) character. The first mode + * that applies will be used. + */ + 'mode' => 'default', + + /** + * Specify the identity and CloudObjects Core authentication credential for this phpMAE instance. + */ + 'co.auth_ns' => 'phpmae.dev', + 'co.auth_secret' => 'YOUR_SECRET_HERE', + + /** + * Specify whether and how data about accounts should be cached. This applies to requests that + * originate from a CloudObjects Account Gateway. + * - none: No caching. + * - file: Cache in filesystem. Uses the "cache_dir" configuration option. + */ + 'agws.data_cache' => 'file', + + /** + * Specifies whether and how phpMAE should write a log. + * log.target: + * - none: Write no log. + * - errorlog: Write to the default error logger. + * log.level: Use Monolog constants. + */ + 'log.target' => 'errorlog', + 'log.level' => Monolog\Logger::DEBUG, + + /** + * Specifies a maximum time for script execution. Time limit starts + * from the running class. + */ + 'execution_time_limit' => 10 + + 'cache_dir' => __DIR__.'/cache', + 'uploads_dir' => __DIR__.'/uploads', +]; diff --git a/data/function.allowed.json b/data/function.allowed.json new file mode 100644 index 0000000..fa98e25 --- /dev/null +++ b/data/function.allowed.json @@ -0,0 +1 @@ +["strlen","strcmp","strncmp","strcasecmp","strncasecmp","each","get_class","property_exists","is_a","trigger_error","user_error","gc_collect_cycles","gc_enabled","strtotime","date","idate","gmdate","mktime","gmmktime","checkdate","time","localtime","getdate","date_create","date_create_immutable","date_create_from_format","date_create_immutable_from_format","date_parse","date_parse_from_format","date_get_last_errors","date_format","date_modify","date_add","date_sub","date_timezone_get","date_timezone_set","date_offset_get","date_diff","date_time_set","date_date_set","date_isodate_set","date_timestamp_set","date_timestamp_get","timezone_open","timezone_name_get","timezone_name_from_abbr","timezone_offset_get","timezone_transitions_get","timezone_location_get","timezone_identifiers_list","timezone_abbreviations_list","date_interval_create_from_date_string","date_interval_format","date_sunrise","date_sunset","date_sun_info","ereg","ereg_replace","eregi","eregi_replace","split","spliti","sql_regcase","libxml_use_internal_errors","libxml_get_last_error","libxml_clear_errors","libxml_get_errors","openssl_spki_new","openssl_spki_verify","openssl_spki_export","openssl_spki_export_challenge","openssl_pkey_free","openssl_pkey_new","openssl_pkey_export","openssl_pkey_get_private","openssl_pkey_get_public","openssl_pkey_get_details","openssl_free_key","openssl_get_privatekey","openssl_get_publickey","openssl_x509_read","openssl_x509_free","openssl_x509_parse","openssl_x509_checkpurpose","openssl_x509_check_private_key","openssl_x509_export","openssl_x509_fingerprint","openssl_pkcs12_export","openssl_pkcs12_read","openssl_csr_new","openssl_csr_export","openssl_csr_sign","openssl_csr_get_subject","openssl_csr_get_public_key","openssl_digest","openssl_encrypt","openssl_decrypt","openssl_cipher_iv_length","openssl_sign","openssl_verify","openssl_seal","openssl_open","openssl_pbkdf2","openssl_private_encrypt","openssl_private_decrypt","openssl_public_encrypt","openssl_public_decrypt","openssl_get_md_methods","openssl_get_cipher_methods","openssl_dh_compute_key","openssl_random_pseudo_bytes","openssl_error_string","preg_match","preg_match_all","preg_replace","preg_replace_callback","preg_filter","preg_split","preg_quote","preg_grep","preg_last_error","gzcompress","gzuncompress","gzdeflate","gzinflate","gzencode","gzdecode","zlib_encode","zlib_decode","zlib_get_coding_type","ob_gzhandler","bcadd","bcsub","bcmul","bcdiv","bcmod","bcpow","bcsqrt","bcscale","bccomp","bcpowmod","bzcompress","bzdecompress","jdtogregorian","gregoriantojd","jdtojulian","juliantojd","jdtojewish","jewishtojd","jdtofrench","frenchtojd","jddayofweek","jdmonthname","easter_date","easter_days","unixtojd","jdtounix","cal_to_jd","cal_from_jd","cal_days_in_month","cal_info","ctype_alnum","ctype_alpha","ctype_cntrl","ctype_digit","ctype_lower","ctype_graph","ctype_print","ctype_punct","ctype_space","ctype_upper","ctype_xdigit","dom_import_simplexml","filter_var","filter_var_array","filter_list","filter_id","hash","hash_hmac","hash_init","hash_update","hash_final","hash_copy","hash_algos","hash_pbkdf2","hash_equals","iconv","iconv_get_encoding","iconv_set_encoding","iconv_strlen","iconv_substr","iconv_strpos","iconv_strrpos","iconv_mime_encode","iconv_mime_decode","iconv_mime_decode_headers","json_encode","json_decode","json_last_error","json_last_error_msg","ldap_connect","ldap_close","ldap_bind","ldap_sasl_bind","ldap_unbind","ldap_read","ldap_list","ldap_search","ldap_free_result","ldap_count_entries","ldap_first_entry","ldap_next_entry","ldap_get_entries","ldap_first_attribute","ldap_next_attribute","ldap_get_attributes","ldap_get_values","ldap_get_values_len","ldap_get_dn","ldap_explode_dn","ldap_dn2ufn","ldap_add","ldap_delete","ldap_modify_batch","ldap_modify","ldap_mod_add","ldap_mod_replace","ldap_mod_del","ldap_errno","ldap_err2str","ldap_error","ldap_compare","ldap_rename","ldap_get_option","ldap_set_option","ldap_first_reference","ldap_next_reference","ldap_parse_reference","ldap_parse_result","ldap_start_tls","ldap_set_rebind_proc","ldap_escape","ldap_control_paged_result","ldap_control_paged_result_response","mb_convert_case","mb_strtoupper","mb_strtolower","mb_language","mb_internal_encoding","mb_detect_order","mb_substitute_character","mb_preferred_mime_name","mb_strlen","mb_strpos","mb_strrpos","mb_stripos","mb_strripos","mb_strstr","mb_strrchr","mb_stristr","mb_strrichr","mb_substr_count","mb_substr","mb_strcut","mb_strwidth","mb_strimwidth","mb_convert_encoding","mb_detect_encoding","mb_list_encodings","mb_encoding_aliases","mb_convert_kana","mb_encode_mimeheader","mb_decode_mimeheader","mb_convert_variables","mb_encode_numericentity","mb_decode_numericentity","mb_get_info","mb_check_encoding","mb_regex_encoding","mb_regex_set_options","mb_ereg","mb_eregi","mb_ereg_replace","mb_eregi_replace","mb_ereg_replace_callback","mb_split","mb_ereg_match","mb_ereg_search","mb_ereg_search_pos","mb_ereg_search_regs","mb_ereg_search_init","mb_ereg_search_getregs","mb_ereg_search_getpos","mb_ereg_search_setpos","mbregex_encoding","mbereg","mberegi","mbereg_replace","mberegi_replace","mbsplit","mbereg_match","mbereg_search","mbereg_search_pos","mbereg_search_regs","mbereg_search_init","mbereg_search_getregs","mbereg_search_getpos","mbereg_search_setpos","mysqli_affected_rows","mysqli_autocommit","mysqli_begin_transaction","mysqli_change_user","mysqli_character_set_name","mysqli_close","mysqli_commit","mysqli_connect","mysqli_connect_errno","mysqli_connect_error","mysqli_data_seek","mysqli_dump_debug_info","mysqli_debug","mysqli_errno","mysqli_error","mysqli_error_list","mysqli_stmt_execute","mysqli_execute","mysqli_fetch_field","mysqli_fetch_fields","mysqli_fetch_field_direct","mysqli_fetch_lengths","mysqli_fetch_all","mysqli_fetch_array","mysqli_fetch_assoc","mysqli_fetch_object","mysqli_fetch_row","mysqli_field_count","mysqli_field_seek","mysqli_field_tell","mysqli_free_result","mysqli_get_connection_stats","mysqli_get_client_stats","mysqli_get_charset","mysqli_get_client_info","mysqli_get_client_version","mysqli_get_host_info","mysqli_get_proto_info","mysqli_get_server_info","mysqli_get_server_version","mysqli_get_warnings","mysqli_init","mysqli_info","mysqli_insert_id","mysqli_kill","mysqli_more_results","mysqli_multi_query","mysqli_next_result","mysqli_num_fields","mysqli_num_rows","mysqli_ping","mysqli_poll","mysqli_prepare","mysqli_report","mysqli_query","mysqli_real_connect","mysqli_real_escape_string","mysqli_real_query","mysqli_release_savepoint","mysqli_rollback","mysqli_savepoint","mysqli_select_db","mysqli_set_charset","mysqli_stmt_affected_rows","mysqli_stmt_attr_get","mysqli_stmt_attr_set","mysqli_stmt_bind_param","mysqli_stmt_bind_result","mysqli_stmt_close","mysqli_stmt_data_seek","mysqli_stmt_errno","mysqli_stmt_error","mysqli_stmt_error_list","mysqli_stmt_fetch","mysqli_stmt_field_count","mysqli_stmt_free_result","mysqli_stmt_get_result","mysqli_stmt_get_warnings","mysqli_stmt_init","mysqli_stmt_insert_id","mysqli_stmt_more_results","mysqli_stmt_next_result","mysqli_stmt_num_rows","mysqli_stmt_param_count","mysqli_stmt_prepare","mysqli_stmt_reset","mysqli_stmt_result_metadata","mysqli_stmt_send_long_data","mysqli_stmt_store_result","mysqli_stmt_sqlstate","mysqli_sqlstate","mysqli_ssl_set","mysqli_stat","mysqli_store_result","mysqli_thread_id","mysqli_thread_safe","mysqli_use_result","mysqli_warning_count","mysqli_refresh","mysqli_escape_string","mysqli_set_opt","iterator_to_array","iterator_count","iterator_apply","pdo_drivers","simplexml_load_string","simplexml_import_dom","bin2hex","hex2bin","sleep","usleep","time_nanosleep","time_sleep_until","strptime","wordwrap","htmlspecialchars","htmlentities","html_entity_decode","htmlspecialchars_decode","get_html_translation_table","sha1","md5","crc32","phpversion","strnatcmp","strnatcasecmp","substr_count","strspn","strcspn","strtok","strtoupper","strtolower","strpos","stripos","strrpos","strripos","strrev","hebrev","hebrevc","nl2br","basename","dirname","stripslashes","stripcslashes","strstr","stristr","strrchr","str_shuffle","str_word_count","str_split","strpbrk","substr_compare","strcoll","money_format","substr","substr_replace","quotemeta","ucfirst","lcfirst","ucwords","strtr","addslashes","addcslashes","rtrim","str_replace","str_ireplace","str_repeat","count_chars","chunk_split","trim","ltrim","strip_tags","similar_text","explode","implode","join","setlocale","localeconv","nl_langinfo","soundex","levenshtein","chr","ord","parse_str","str_getcsv","str_pad","chop","strchr","sprintf","vsprintf","sscanf","parse_url","urlencode","urldecode","rawurlencode","rawurldecode","http_build_query","escapeshellcmd","escapeshellarg","rand","srand","getrandmax","mt_rand","mt_srand","mt_getrandmax","base64_decode","base64_encode","password_hash","password_get_info","password_needs_rehash","password_verify","convert_uuencode","convert_uudecode","abs","ceil","floor","round","sin","cos","tan","asin","acos","atan","atanh","atan2","sinh","cosh","tanh","asinh","acosh","expm1","log1p","pi","is_finite","is_nan","is_infinite","pow","exp","log","log10","sqrt","hypot","deg2rad","rad2deg","bindec","hexdec","octdec","decbin","decoct","dechex","base_convert","number_format","fmod","inet_ntop","inet_pton","ip2long","long2ip","microtime","gettimeofday","uniqid","quoted_printable_decode","quoted_printable_encode","convert_cyr_string","error_get_last","serialize","unserialize","highlight_string","parse_ini_string","gethostbyaddr","gethostbyname","gethostbynamel","dns_check_record","checkdnsrr","dns_get_mx","getmxrr","dns_get_record","intval","floatval","doubleval","strval","boolval","gettype","settype","is_null","is_resource","is_bool","is_long","is_float","is_int","is_integer","is_double","is_real","is_numeric","is_string","is_array","is_object","is_scalar","fnmatch","unpack","crypt","lcg_value","metaphone","ksort","krsort","natsort","natcasesort","asort","arsort","sort","rsort","usort","uasort","uksort","shuffle","array_walk","array_walk_recursive","count","end","prev","next","reset","current","key","min","max","in_array","array_search","extract","compact","array_fill","array_fill_keys","range","array_multisort","array_push","array_pop","array_shift","array_unshift","array_splice","array_slice","array_merge","array_merge_recursive","array_replace","array_replace_recursive","array_keys","array_values","array_count_values","array_column","array_reverse","array_reduce","array_pad","array_flip","array_change_key_case","array_rand","array_unique","array_intersect","array_intersect_key","array_intersect_ukey","array_uintersect","array_intersect_assoc","array_uintersect_assoc","array_intersect_uassoc","array_uintersect_uassoc","array_diff","array_diff_key","array_diff_ukey","array_udiff","array_diff_assoc","array_udiff_assoc","array_diff_uassoc","array_udiff_uassoc","array_sum","array_product","array_filter","array_map","array_chunk","array_combine","array_key_exists","pos","sizeof","key_exists","version_compare","str_rot13","wddx_serialize_value","wddx_serialize_vars","wddx_packet_start","wddx_packet_end","wddx_add_vars","xml_parser_create","xml_parser_create_ns","xml_set_object","xml_set_element_handler","xml_set_character_data_handler","xml_set_processing_instruction_handler","xml_set_default_handler","xml_set_unparsed_entity_decl_handler","xml_set_notation_decl_handler","xml_set_external_entity_ref_handler","xml_set_start_namespace_decl_handler","xml_set_end_namespace_decl_handler","xml_parse","xml_parse_into_struct","xml_get_error_code","xml_error_string","xml_get_current_line_number","xml_get_current_column_number","xml_get_current_byte_index","xml_parser_free","xml_parser_set_option","xml_parser_get_option","utf8_encode","utf8_decode","xmlwriter_open_memory","xmlwriter_set_indent","xmlwriter_set_indent_string","xmlwriter_start_comment","xmlwriter_end_comment","xmlwriter_start_attribute","xmlwriter_end_attribute","xmlwriter_write_attribute","xmlwriter_start_attribute_ns","xmlwriter_write_attribute_ns","xmlwriter_start_element","xmlwriter_end_element","xmlwriter_full_end_element","xmlwriter_start_element_ns","xmlwriter_write_element","xmlwriter_write_element_ns","xmlwriter_start_pi","xmlwriter_end_pi","xmlwriter_write_pi","xmlwriter_start_cdata","xmlwriter_end_cdata","xmlwriter_write_cdata","xmlwriter_text","xmlwriter_write_raw","xmlwriter_start_document","xmlwriter_end_document","xmlwriter_write_comment","xmlwriter_start_dtd","xmlwriter_end_dtd","xmlwriter_write_dtd","xmlwriter_start_dtd_element","xmlwriter_end_dtd_element","xmlwriter_write_dtd_element","xmlwriter_start_dtd_attlist","xmlwriter_end_dtd_attlist","xmlwriter_write_dtd_attlist","xmlwriter_start_dtd_entity","xmlwriter_end_dtd_entity","xmlwriter_write_dtd_entity","xmlwriter_output_memory","xmlwriter_flush"] \ No newline at end of file diff --git a/data/function.forbidden.json b/data/function.forbidden.json new file mode 100644 index 0000000..853a303 --- /dev/null +++ b/data/function.forbidden.json @@ -0,0 +1 @@ +["zend_version","func_num_args","func_get_arg","func_get_args","error_reporting","define","defined","get_called_class","get_parent_class","method_exists","class_exists","interface_exists","trait_exists","function_exists","class_alias","get_included_files","get_required_files","is_subclass_of","get_class_vars","get_object_vars","get_class_methods","set_error_handler","restore_error_handler","set_exception_handler","restore_exception_handler","get_declared_classes","get_declared_traits","get_declared_interfaces","get_defined_functions","get_defined_vars","create_function","get_resource_type","get_loaded_extensions","extension_loaded","get_extension_funcs","get_defined_constants","debug_backtrace","debug_print_backtrace","gc_enable","gc_disable","strftime","gmstrftime","timezone_version_get","date_default_timezone_set","date_default_timezone_get","libxml_set_streams_context","libxml_disable_entity_loader","libxml_set_external_entity_loader","openssl_get_cert_locations","openssl_pkey_export_to_file","openssl_x509_export_to_file","openssl_pkcs12_export_to_file","openssl_csr_export_to_file","openssl_pkcs7_decrypt","openssl_pkcs7_verify","openssl_pkcs7_sign","openssl_pkcs7_encrypt","readgzfile","gzrewind","gzclose","gzeof","gzgetc","gzgets","gzgetss","gzread","gzopen","gzpassthru","gzseek","gztell","gzwrite","gzputs","gzfile","bzopen","bzread","bzwrite","bzflush","bzclose","bzerrno","bzerrstr","bzerror","curl_init","curl_copy_handle","curl_version","curl_setopt","curl_setopt_array","curl_exec","curl_getinfo","curl_error","curl_errno","curl_close","curl_strerror","curl_multi_strerror","curl_reset","curl_escape","curl_unescape","curl_pause","curl_multi_init","curl_multi_add_handle","curl_multi_remove_handle","curl_multi_select","curl_multi_exec","curl_multi_getcontent","curl_multi_info_read","curl_multi_close","curl_multi_setopt","curl_share_init","curl_share_close","curl_share_setopt","curl_file_create","dba_open","dba_popen","dba_close","dba_delete","dba_exists","dba_fetch","dba_insert","dba_replace","dba_firstkey","dba_nextkey","dba_optimize","dba_sync","dba_handlers","dba_list","dba_key_split","exif_read_data","read_exif_data","exif_tagname","exif_thumbnail","exif_imagetype","finfo_open","finfo_close","finfo_set_flags","finfo_file","finfo_buffer","mime_content_type","filter_input","filter_input_array","filter_has_var","ftp_connect","ftp_ssl_connect","ftp_login","ftp_pwd","ftp_cdup","ftp_chdir","ftp_exec","ftp_raw","ftp_mkdir","ftp_rmdir","ftp_chmod","ftp_alloc","ftp_nlist","ftp_rawlist","ftp_systype","ftp_pasv","ftp_get","ftp_fget","ftp_put","ftp_fput","ftp_size","ftp_mdtm","ftp_rename","ftp_delete","ftp_site","ftp_close","ftp_set_option","ftp_get_option","ftp_nb_fget","ftp_nb_get","ftp_nb_continue","ftp_nb_put","ftp_nb_fput","ftp_quit","gd_info","imagearc","imageellipse","imagechar","imagecharup","imagecolorat","imagecolorallocate","imagepalettecopy","imagecreatefromstring","imagecolorclosest","imagecolorclosesthwb","imagecolordeallocate","imagecolorresolve","imagecolorexact","imagecolorset","imagecolortransparent","imagecolorstotal","imagecolorsforindex","imagecopy","imagecopymerge","imagecopymergegray","imagecopyresized","imagecreate","imagecreatetruecolor","imageistruecolor","imagetruecolortopalette","imagepalettetotruecolor","imagesetthickness","imagefilledarc","imagefilledellipse","imagealphablending","imagesavealpha","imagecolorallocatealpha","imagecolorresolvealpha","imagecolorclosestalpha","imagecolorexactalpha","imagecopyresampled","imagerotate","imageflip","imageantialias","imagecrop","imagecropauto","imagescale","imageaffine","imageaffinematrixconcat","imageaffinematrixget","imagesetinterpolation","imagesettile","imagesetbrush","imagesetstyle","imagecreatefrompng","imagecreatefromgif","imagecreatefromjpeg","imagecreatefromwbmp","imagecreatefromxbm","imagecreatefromgd","imagecreatefromgd2","imagecreatefromgd2part","imagepng","imagegif","imagejpeg","imagewbmp","imagegd","imagegd2","imagedestroy","imagegammacorrect","imagefill","imagefilledpolygon","imagefilledrectangle","imagefilltoborder","imagefontwidth","imagefontheight","imageinterlace","imageline","imageloadfont","imagepolygon","imagerectangle","imagesetpixel","imagestring","imagestringup","imagesx","imagesy","imagedashedline","imagetypes","jpeg2wbmp","png2wbmp","image2wbmp","imagelayereffect","imagexbm","imagecolormatch","imagefilter","imageconvolution","hash_file","hash_hmac_file","hash_update_stream","hash_update_file","ldap_sort","mb_http_input","mb_http_output","mb_parse_str","mb_output_handler","mb_send_mail","mysql_connect","mysql_pconnect","mysql_close","mysql_select_db","mysql_query","mysql_unbuffered_query","mysql_db_query","mysql_list_dbs","mysql_list_tables","mysql_list_fields","mysql_list_processes","mysql_error","mysql_errno","mysql_affected_rows","mysql_insert_id","mysql_result","mysql_num_rows","mysql_num_fields","mysql_fetch_row","mysql_fetch_array","mysql_fetch_assoc","mysql_fetch_object","mysql_data_seek","mysql_fetch_lengths","mysql_fetch_field","mysql_field_seek","mysql_free_result","mysql_field_name","mysql_field_table","mysql_field_len","mysql_field_type","mysql_field_flags","mysql_escape_string","mysql_real_escape_string","mysql_stat","mysql_thread_id","mysql_client_encoding","mysql_ping","mysql_get_client_info","mysql_get_host_info","mysql_get_proto_info","mysql_get_server_info","mysql_info","mysql_set_charset","mysql","mysql_fieldname","mysql_fieldtable","mysql_fieldlen","mysql_fieldtype","mysql_fieldflags","mysql_selectdb","mysql_freeresult","mysql_numfields","mysql_numrows","mysql_listdbs","mysql_listtables","mysql_listfields","mysql_db_name","mysql_dbname","mysql_tablename","mysql_table_name","mysqli_get_links_stats","mysqli_options","mysqli_reap_async_query","spl_classes","spl_autoload","spl_autoload_extensions","spl_autoload_register","spl_autoload_unregister","spl_autoload_functions","spl_autoload_call","class_parents","class_implements","class_uses","spl_object_hash","posix_kill","posix_getpid","posix_getppid","posix_getuid","posix_setuid","posix_geteuid","posix_seteuid","posix_getgid","posix_setgid","posix_getegid","posix_setegid","posix_getgroups","posix_getlogin","posix_getpgrp","posix_setsid","posix_setpgid","posix_getpgid","posix_getsid","posix_uname","posix_times","posix_ctermid","posix_ttyname","posix_isatty","posix_getcwd","posix_mkfifo","posix_mknod","posix_access","posix_getgrnam","posix_getgrgid","posix_getpwnam","posix_getpwuid","posix_getrlimit","posix_get_last_error","posix_errno","posix_strerror","posix_initgroups","readline","readline_info","readline_add_history","readline_clear_history","readline_read_history","readline_write_history","readline_completion_function","readline_callback_handler_install","readline_callback_read_char","readline_callback_handler_remove","readline_redisplay","readline_on_new_line","session_name","session_module_name","session_save_path","session_id","session_regenerate_id","session_decode","session_encode","session_start","session_destroy","session_unset","session_set_save_handler","session_cache_limiter","session_cache_expire","session_set_cookie_params","session_get_cookie_params","session_write_close","session_abort","session_reset","session_status","session_register_shutdown","session_commit","shmop_open","shmop_read","shmop_close","shmop_size","shmop_write","shmop_delete","simplexml_load_file","snmpget","snmpgetnext","snmpwalk","snmprealwalk","snmpwalkoid","snmpset","snmp_get_quick_print","snmp_set_quick_print","snmp_set_enum_print","snmp_set_oid_output_format","snmp_set_oid_numeric_print","snmp2_get","snmp2_getnext","snmp2_walk","snmp2_real_walk","snmp2_set","snmp3_get","snmp3_getnext","snmp3_walk","snmp3_real_walk","snmp3_set","snmp_set_valueretrieval","snmp_get_valueretrieval","snmp_read_mib","use_soap_error_handler","is_soap_fault","socket_select","socket_create","socket_create_listen","socket_create_pair","socket_accept","socket_set_nonblock","socket_set_block","socket_listen","socket_close","socket_write","socket_read","socket_getsockname","socket_getpeername","socket_connect","socket_strerror","socket_bind","socket_recv","socket_send","socket_recvfrom","socket_sendto","socket_get_option","socket_set_option","socket_shutdown","socket_last_error","socket_clear_error","socket_import_stream","socket_sendmsg","socket_recvmsg","socket_cmsg_space","socket_getopt","socket_setopt","constant","flush","sha1_file","md5_file","iptcparse","iptcembed","getimagesize","getimagesizefromstring","image_type_to_mime_type","image_type_to_extension","phpinfo","phpcredits","php_sapi_name","php_uname","php_ini_scanned_files","php_ini_loaded_file","pathinfo","printf","vprintf","fprintf","vfprintf","fscanf","readlink","linkinfo","symlink","link","unlink","exec","system","passthru","shell_exec","proc_open","proc_close","proc_terminate","proc_get_status","proc_nice","getservbyname","getservbyport","getprotobyname","getprotobynumber","getmyuid","getmygid","getmypid","getmyinode","getlastmod","getenv","putenv","getopt","sys_getloadavg","getrusage","get_current_user","set_time_limit","header_register_callback","get_cfg_var","magic_quotes_runtime","set_magic_quotes_runtime","get_magic_quotes_gpc","get_magic_quotes_runtime","error_log","call_user_func","call_user_func_array","call_user_method","call_user_method_array","forward_static_call","forward_static_call_array","debug_zval_dump","print_r","var_dump","var_export","memory_get_usage","memory_get_peak_usage","register_shutdown_function","register_tick_function","unregister_tick_function","highlight_file","show_source","php_strip_whitespace","ini_get","ini_get_all","ini_set","ini_alter","ini_restore","get_include_path","set_include_path","restore_include_path","setcookie","setrawcookie","header","header_remove","headers_sent","headers_list","http_response_code","connection_aborted","connection_status","ignore_user_abort","parse_ini_file","is_uploaded_file","move_uploaded_file","gethostname","is_callable","pclose","popen","readfile","rewind","rmdir","umask","fclose","feof","fgetc","fgets","fgetss","fread","fopen","fpassthru","ftruncate","fstat","fseek","ftell","fflush","fwrite","fputs","mkdir","rename","copy","tempnam","tmpfile","file","file_get_contents","file_put_contents","stream_select","stream_context_create","stream_context_set_params","stream_context_get_params","stream_context_set_option","stream_context_get_options","stream_context_get_default","stream_context_set_default","stream_filter_prepend","stream_filter_append","stream_filter_remove","stream_socket_client","stream_socket_server","stream_socket_accept","stream_socket_get_name","stream_socket_recvfrom","stream_socket_sendto","stream_socket_enable_crypto","stream_socket_shutdown","stream_socket_pair","stream_copy_to_stream","stream_get_contents","stream_supports_lock","fgetcsv","fputcsv","flock","get_meta_tags","stream_set_read_buffer","stream_set_write_buffer","set_file_buffer","stream_set_chunk_size","set_socket_blocking","stream_set_blocking","socket_set_blocking","stream_get_meta_data","stream_get_line","stream_wrapper_register","stream_register_wrapper","stream_wrapper_unregister","stream_wrapper_restore","stream_get_wrappers","stream_get_transports","stream_resolve_include_path","stream_is_local","get_headers","stream_set_timeout","socket_set_timeout","socket_get_status","realpath","fsockopen","pfsockopen","pack","get_browser","opendir","closedir","chdir","getcwd","rewinddir","readdir","dir","scandir","glob","fileatime","filectime","filegroup","fileinode","filemtime","fileowner","fileperms","filesize","filetype","file_exists","is_writable","is_writeable","is_readable","is_executable","is_file","is_dir","is_link","stat","lstat","chown","chgrp","lchown","lchgrp","chmod","touch","clearstatcache","disk_total_space","disk_free_space","diskfreespace","realpath_cache_size","realpath_cache_get","mail","ezmlm_hash","openlog","syslog","closelog","ob_start","ob_flush","ob_clean","ob_end_flush","ob_end_clean","ob_get_flush","ob_get_clean","ob_get_length","ob_get_level","ob_get_status","ob_get_contents","ob_implicit_flush","ob_list_handlers","assert","assert_options","ftok","stream_get_filters","stream_filter_register","stream_bucket_make_writeable","stream_bucket_prepend","stream_bucket_append","stream_bucket_new","output_add_rewrite_var","output_reset_rewrite_vars","sys_get_temp_dir","msg_get_queue","msg_send","msg_receive","msg_remove_queue","msg_stat_queue","msg_set_queue","msg_queue_exists","sem_get","sem_acquire","sem_release","sem_remove","shm_attach","shm_remove","shm_detach","shm_put_var","shm_has_var","shm_get_var","shm_remove_var","tidy_getopt","tidy_parse_string","tidy_parse_file","tidy_get_output","tidy_get_error_buffer","tidy_clean_repair","tidy_repair_string","tidy_repair_file","tidy_diagnose","tidy_get_release","tidy_get_config","tidy_get_status","tidy_get_html_ver","tidy_is_xhtml","tidy_is_xml","tidy_error_count","tidy_warning_count","tidy_access_count","tidy_config_count","tidy_get_opt_doc","tidy_get_root","tidy_get_head","tidy_get_html","tidy_get_body","token_get_all","token_name","wddx_deserialize","xmlrpc_encode","xmlrpc_decode","xmlrpc_decode_request","xmlrpc_encode_request","xmlrpc_get_type","xmlrpc_set_type","xmlrpc_is_fault","xmlrpc_server_create","xmlrpc_server_destroy","xmlrpc_server_register_method","xmlrpc_server_call_method","xmlrpc_parse_method_descriptions","xmlrpc_server_add_introspection_data","xmlrpc_server_register_introspection_callback","xmlwriter_open_uri","zip_open","zip_close","zip_read","zip_entry_open","zip_entry_close","zip_entry_read","zip_entry_filesize","zip_entry_name","zip_entry_compressedsize","zip_entry_compressionmethod","dl","cli_set_process_title","cli_get_process_title"] \ No newline at end of file diff --git a/directory-template/Class.html.twig b/directory-template/Class.html.twig new file mode 100644 index 0000000..a9228f0 --- /dev/null +++ b/directory-template/Class.html.twig @@ -0,0 +1,43 @@ +
Public PHP Methods
+{% if custom.methods|length > 0 %} +
    + {% for m in custom.methods %} +
  • +
    + {{m.name}}({{m.params}}) +
    +
    + {% if m.comment is empty %} +

    No documentation available.

    + {% else %} +

    {{m.comment|nl2br}}

    + {% endif %} + + {% if custom.public_source_code is defined and m.can_run == true %} +
    +
    + + + {% for f in m.fields %} +
    + + +
    + {% endfor %} + +
    +
    +
    +
    + {% endif %} +
    +
  • + {% endfor %} +
+{% else %} +

This class has no public methods yet or a problem occurred while retrieving them.

+{% endif %} +{% if custom.public_source_code is defined %} +
Source Code
+
{{ custom.public_source_code }}
+{% endif %} \ No newline at end of file diff --git a/directory-template/Interface.html.twig b/directory-template/Interface.html.twig new file mode 100644 index 0000000..8034a21 --- /dev/null +++ b/directory-template/Interface.html.twig @@ -0,0 +1,24 @@ +
Public PHP Methods
+{% if custom.methods|length > 0 %} +
    + {% for m in custom.methods %} +
  • +
    + {{m.name}}({{m.params}}) +
    +
    + {% if m.comment is empty %} +

    No documentation available.

    + {% else %} +

    {{m.comment|nl2br}}

    + {% endif %} +
    +
  • + {% endfor %} +
+{% else %} +

This interface has no public methods yet or a problem occurred while retrieving them.

+{% endif %} +
Create Class from Interface (CLI)
+

With phpMAE installed locally, you can create a PHP class that implements this interface with the following command:

+
phpmae class:create --implements={{id}} --confjob <COID>
diff --git a/directory-template/Stack.html.twig b/directory-template/Stack.html.twig new file mode 100644 index 0000000..11d1736 --- /dev/null +++ b/directory-template/Stack.html.twig @@ -0,0 +1,40 @@ +
Whitelisted Classes from Packages
+
    + {% for className in config['coid://phpmae.dev/whitelistsClassname'] %} +
  • {{ className.o_value }}
  • + {% endfor %} +
+
Defined Packages
+ + + + + + + + + {% for package in custom.defined %} + + + + + {% endfor %} + +
NameVersion
{{ package.name }}{{ package.version }}
+
Actual Installed Packages
+ + + + + + + + + {% for package in custom.actual %} + + + + + {% endfor %} + +
NameVersion
{% if package.defined %}{% endif %}{{ package.name }}{% if package.defined %}{% endif %}{{ package.version }}
\ No newline at end of file diff --git a/directory-template/phpmae.js b/directory-template/phpmae.js new file mode 100644 index 0000000..28eb5ef --- /dev/null +++ b/directory-template/phpmae.js @@ -0,0 +1,54 @@ +$('.collapsible-body form').on('submit', function(event) { + event.preventDefault(); + var form = $(this); + form.find('.btn').addClass('disabled'); + + var fields = form.serializeArray(); + var className = ""; + var method = ""; + var params = {}; + for (var f in fields) { + switch (fields[f].name) { + case "method": + method = fields[f].value; + break; + case "class": + className = fields[f].value; + break; + default: + params[fields[f].name.substr(2)] = fields[f].value; + } + } + + axios.post('https://phpmae.dev/' + className, { + jsonrpc : '2.0', + id : 'COWebsite', + method : method, + params : params + }).then(function(response) { + form.find('.btn').removeClass('disabled'); + + if (typeof(response.data) == "object" && response.data.hasOwnProperty('result')) { + form.find('.console-response-status').text('Success'); + form.find('.console-response').text( + typeof(response.data.result) == "string" ? response.data.result + : JSON.stringify(response.data.result, null, 4)); + } else + if (typeof(response.data) == "object" && !response.data.hasOwnProperty('error')) { + form.find('.console-response-status').text('Success'); + form.find('.console-response').text(JSON.stringify(response.data, null, 4)); + } else + if (typeof(response.data) == "object") { + form.find('.console-response-status').text('Error'); + form.find('.console-response').text(JSON.stringify(response.data.error, null, 4)) + } else { + form.find('.console-response-status').text('Success'); + form.find('.console-response').text(response.data); + } + }).catch(function(error) { + form.find('.btn').removeClass('disabled'); + + form.find('.console-response-status').text('Exception'); + form.find('.console-response').text(JSON.stringify(error, null, 4)) + }); +}); \ No newline at end of file diff --git a/fly.toml b/fly.toml new file mode 100644 index 0000000..fbf97e1 --- /dev/null +++ b/fly.toml @@ -0,0 +1,21 @@ +app = "phpmae" + +[[services]] + internal_port = 80 + protocol = "tcp" + + [services.concurrency] + hard_limit = 25 + soft_limit = 20 + + [[services.ports]] + handlers = ["http"] + port = "80" + + [[services.ports]] + handlers = ["tls", "http"] + port = "443" + + [[services.tcp_checks]] + interval = 10000 + timeout = 2000 \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..99b27cd --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,52 @@ +const gulp = require('gulp'); +const concat = require('gulp-concat'); +const streamqueue = require('streamqueue'); +const uglify = require('gulp-uglify'); +const cssPurge = require('gulp-css-purge'); +const sass = require('gulp-sass'); + +// Concatenate and minify scripts +gulp.task('scripts', function() { + // inspired by https://stackoverflow.com/a/23507836 + return streamqueue({ objectMode: true }, + gulp.src('./node_modules/jquery/dist/jquery.min.js'), + gulp.src('./node_modules/materialize-css/dist/js/materialize.js'), + gulp.src('./node_modules/codemirror/lib/codemirror.js'), + gulp.src('./node_modules/codemirror/mode/clike/clike.js'), + gulp.src('./node_modules/codemirror/addon/edit/matchbrackets.js'), + gulp.src('./node_modules/codemirror/mode/xml/xml.js'), + gulp.src('./node_modules/codemirror/mode/javascript/javascript.js'), + gulp.src('./node_modules/codemirror/mode/htmlmixed/htmlmixed.js'), + gulp.src('./node_modules/codemirror/mode/css/css.js'), + gulp.src('./node_modules/codemirror/mode/php/php.js'), + gulp.src('./static/app.js') + ) + .pipe(concat('scripts.js')) + .pipe(uglify()) + .pipe(gulp.dest('./static')); +}); + +// Concatenate and minify stylesheets +gulp.task('styles', function() { + return streamqueue({ objectMode: true }, + gulp.src('./scss/materialize-customized.scss') + .pipe(sass().on('error', sass.logError)), + gulp.src('./static/app.css') + ) + .pipe(concat('styles.css')) + .pipe(cssPurge({ + trim : true, + shorten : true, + verbose : false + })) + .pipe(gulp.dest('./static')); +}); + +// Copy file that is needed as-is +gulp.task('copy', function () { + return gulp.src('./node_modules/codemirror/lib/codemirror.css') + .pipe(gulp.dest('static')); +}); + +// Run entire process +gulp.task('default', gulp.series('scripts', 'styles', 'copy')); \ No newline at end of file diff --git a/init.sh b/init.sh new file mode 100644 index 0000000..09f0082 --- /dev/null +++ b/init.sh @@ -0,0 +1,30 @@ +# Apply defaults for unset variables +if [ -z $MODE ]; then MODE=default; fi +if [ -z $CLIENT_AUTH ]; then CLIENT_AUTH=shared_secret:runclass; fi +if [ -z $INTERACTIVE ]; then INTERACTIVE=false; fi + +# Write configuration file + +echo " false, " \ + " 'interactive_run' => $INTERACTIVE, " \ + " 'cache_dir' => __DIR__.'/cache', " \ + " 'uploads_dir' => __DIR__.'/uploads', " \ + " 'mode' => '$MODE', " \ + " 'client_authentication' => '$CLIENT_AUTH', " \ + " 'client_authentication_must_be_secure' => false, " \ + " 'global_cors_origins' => 'https://cloudobjects.io', " \ + " 'co.auth_ns' => '$CO_AUTH_NS', " \ + " 'co.auth_secret' => '$CO_AUTH_SECRET', " \ + " 'agws.data_cache' => 'file', " \ + " 'log.target' => 'errorlog', " \ + " 'log.level' => Monolog\Logger::INFO, " \ + " ); " > /var/www/app/config.php + +# Make cache folder +mkdir /var/www/app/cache +chown lighttpd:lighttpd /var/www/app/cache + +# Run start script from parent container + +sh /tmp/start.sh \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 0000000..d5e9ca0 --- /dev/null +++ b/makefile @@ -0,0 +1,34 @@ +.PHONY: all clean + +all: stacks phpmae.phar + +clean: + # Delete PHAR and stacks + rm *.phar + rm -rf stacks + +composer.lock: composer.json + # Updating Dependencies with Composer + composer update -n -o + +vendor: composer.lock + # Installing Dependencies with Composer + composer install -n -o + +robo.phar: + # Get a copy of robo + wget http://robo.li/robo.phar + +config.php: config.php.default + # Use .default if no other config provided + cp config.php.default config.php + +stacks: robo.phar vendor + # Create stack directory + mkdir stacks + # Install default stack + php robo.phar install:stack coid://phpmae.dev/DefaultStack + +phpmae.phar: phpmae.php config.php vendor RoboFile.php robo.phar + # Building archive with robo + php robo.phar phar \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a4cc945 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4680 @@ +{ + "name": "phpmae", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" + }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + } + } + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "requires": { + "buffer-equal": "^1.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "requires": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + } + } + }, + "array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "requires": { + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + } + } + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" + }, + "array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "requires": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "requires": { + "async-done": "^1.2.2" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "requires": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=" + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "~2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, + "buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + } + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", + "requires": { + "ansi-regex": "^2.1.1", + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.5" + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" + }, + "cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "codemirror": { + "version": "5.65.3", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.3.tgz", + "integrity": "sha512-kCC0iwGZOVZXHEKW3NDTObvM7pTIyowjty4BUqeREROc/3I6bWbgZDA3fGDwlA+rbgRjvnRnfqs9SfXynel1AQ==" + }, + "collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "requires": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "copy-props": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", + "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "requires": { + "each-props": "^1.3.2", + "is-plain-object": "^5.0.0" + }, + "dependencies": { + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + } + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-font-size-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-font-size-keywords/-/css-font-size-keywords-1.0.0.tgz", + "integrity": "sha1-hUh1rOmspqjS7g00WkSq6btttss=" + }, + "css-font-stretch-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-font-stretch-keywords/-/css-font-stretch-keywords-1.0.1.tgz", + "integrity": "sha1-UM7puboDH7XJUtRyMTnx4Qe1SxA=" + }, + "css-font-style-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-font-style-keywords/-/css-font-style-keywords-1.0.1.tgz", + "integrity": "sha1-XDUygT9jtKHelU0TzqhqtDM0CeQ=" + }, + "css-font-weight-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-font-weight-keywords/-/css-font-weight-keywords-1.0.0.tgz", + "integrity": "sha1-m8BGcayFvHJLV07106yWsNYE/Zc=" + }, + "css-global-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-global-keywords/-/css-global-keywords-1.0.1.tgz", + "integrity": "sha1-cqmupyeW0Bmx0qMlLeTlqqN+Smk=" + }, + "css-list-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-list-helpers/-/css-list-helpers-1.0.1.tgz", + "integrity": "sha1-//VxkiAtuDJAxBaG+RnkSacCT30=", + "requires": { + "tcomb": "^2.5.0" + } + }, + "css-purge": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/css-purge/-/css-purge-3.1.8.tgz", + "integrity": "sha512-iwOtr9AxxnDOR/37UIgmnKzNjh3AMBDYckSpIEieERzFavdkw471CWOIL6LJCA5yA241GIMfgb2KCScsAVY8zw==", + "requires": { + "cli-color": "^1.4.0", + "commander": "^2.19.0", + "css": "^2.2.4", + "htmlparser2": "^3.10.0", + "jsdom": "^11.12.0", + "parse-css-font": "^2.0.2", + "request": "^2.88.0", + "through2": "^2.0.5", + "valid-url": "^1.0.9" + } + }, + "css-system-font-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz", + "integrity": "sha1-hcbwhquk6zLFcaMIav/ENLhII+0=" + }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "requires": { + "cssom": "0.3.x" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "^1.0.1" + } + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "dateformat": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "requires": { + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=" + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "requires": { + "readable-stream": "~1.1.9" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "requires": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es5-ext": { + "version": "0.10.61", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", + "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "ext": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", + "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "requires": { + "type": "^2.5.0" + }, + "dependencies": { + "type": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", + "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=" + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "requires": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + } + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "requires": { + "globule": "^1.0.0" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, + "glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "requires": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globule": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", + "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "requires": { + "sparkles": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "requires": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "dependencies": { + "gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "requires": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + } + } + } + }, + "gulp-concat": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", + "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "requires": { + "concat-with-sourcemaps": "^1.0.0", + "through2": "^2.0.0", + "vinyl": "^2.0.0" + } + }, + "gulp-css-purge": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/gulp-css-purge/-/gulp-css-purge-3.0.9.tgz", + "integrity": "sha512-s+53B541laxxy3LeccU8tHlAMRaz2XMDE9+yhxSdsUDujgLeRIjJ+iO4Js/wHPCmB82yygrHB21X2ebWCydmhg==", + "requires": { + "css-purge": "^3.1.0", + "gulp-util": "^3.0.8", + "through2": "^2.0.3" + } + }, + "gulp-sass": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-4.1.1.tgz", + "integrity": "sha512-bg7mfgsgho0Ej0WXE9Cd2sq/YxeKxOjagrMmM40zvOYXHtZvi5ED84wIpqCUvJLz66kFNkv+jS/rQXolmgXrUQ==", + "requires": { + "chalk": "^2.3.0", + "lodash": "^4.17.20", + "node-sass": "^4.8.3", + "plugin-error": "^1.0.1", + "replace-ext": "^1.0.0", + "strip-ansi": "^4.0.0", + "through2": "^2.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "gulp-uglify": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz", + "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==", + "requires": { + "array-each": "^1.0.1", + "extend-shallow": "^3.0.2", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "isobject": "^3.0.1", + "make-error-cause": "^1.1.1", + "safe-buffer": "^5.1.2", + "through2": "^2.0.0", + "uglify-js": "^3.0.5", + "vinyl-sourcemaps-apply": "^0.2.0" + } + }, + "gulp-util": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "requires": { + "array-differ": "^1.0.0", + "array-uniq": "^1.0.2", + "beeper": "^1.0.0", + "chalk": "^1.0.0", + "dateformat": "^2.0.0", + "fancy-log": "^1.1.0", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "lodash._reescape": "^3.0.0", + "lodash._reevaluate": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.template": "^3.0.0", + "minimist": "^1.1.0", + "multipipe": "^0.1.2", + "object-assign": "^3.0.0", + "replace-ext": "0.0.1", + "through2": "^2.0.0", + "vinyl": "^0.5.0" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=" + }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" + }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "requires": { + "glogg": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "requires": { + "sparkles": "^1.0.0" + } + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "in-publish": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, + "js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + } + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "just-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", + "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "requires": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + } + }, + "lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "requires": { + "readable-stream": "^2.0.5" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "requires": { + "flush-write-stream": "^1.0.2" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "requires": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=" + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=" + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" + }, + "lodash._reescape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=" + }, + "lodash._reevaluate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "requires": { + "lodash._root": "^3.0.0" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + }, + "dependencies": { + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + } + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "requires": { + "es5-ext": "~0.10.2" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "make-error-cause": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz", + "integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=", + "requires": { + "make-error": "^1.2.0" + } + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "requires": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "dependencies": { + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "materialize-css": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/materialize-css/-/materialize-css-1.0.0.tgz", + "integrity": "sha512-4/oecXl8y/1i8RDZvyvwAICyqwNoKU4or5uf8uoAd74k76KzZ0Llym4zhJ5lLNUskcqjO0AuMcvNyDkpz8Z6zw==" + }, + "memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "requires": { + "duplexer2": "0.0.2" + } + }, + "mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==" + }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + } + } + }, + "node-sass": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", + "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "2.2.5", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "requires": { + "once": "^1.3.2" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "dependencies": { + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + } + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse-css-font": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/parse-css-font/-/parse-css-font-2.0.2.tgz", + "integrity": "sha1-e2CwYHBaJam5C38O1JPlgjJIplI=", + "requires": { + "css-font-size-keywords": "^1.0.0", + "css-font-stretch-keywords": "^1.0.1", + "css-font-style-keywords": "^1.0.1", + "css-font-weight-keywords": "^1.0.0", + "css-global-keywords": "^1.0.1", + "css-list-helpers": "^1.0.1", + "css-system-font-keywords": "^1.0.0", + "tcomb": "^2.5.0", + "unquote": "^1.1.0" + } + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "requires": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + } + }, + "remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "requires": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==" + }, + "replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "requires": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "requires": { + "value-or-function": "^3.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass-graph": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", + "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "requires": { + "sver-compat": "^1.5.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, + "stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==" + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "streamqueue": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/streamqueue/-/streamqueue-1.1.2.tgz", + "integrity": "sha512-CHUpqa+1BM99z7clQz9W6L9ZW4eXRRQCR0H+utVAGGvNo2ePlJAFjhdK0IjunaBbY/gWKJawk5kpJeyz0EXxRA==", + "requires": { + "isstream": "^0.1.2", + "readable-stream": "^2.3.3" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "^4.0.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "requires": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "tcomb": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tcomb/-/tcomb-2.7.0.tgz", + "integrity": "sha1-ENYpWAQWaaXVNWe5pO6M3iKxwrA=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" + }, + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "requires": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "requires": { + "through2": "^2.0.3" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "requires": { + "glob": "^7.1.2" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uglify-js": { + "version": "3.15.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.5.tgz", + "integrity": "sha512-hNM5q5GbBRB5xB+PMqVRcgYe4c8jbyZ1pzZhS6jbq54/4F2gFK869ZheiE5A8/t+W5jtTNpWef/5Q9zk639FNQ==" + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "requires": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "valid-url": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", + "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + } + } + }, + "vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + }, + "vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "requires": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + } + }, + "vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "requires": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "requires": { + "source-map": "^0.5.1" + } + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", + "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", + "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.1" + } + }, + "yargs-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", + "requires": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..584ff0b --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "phpmae", + "version": "1.0.0", + "description": "Static files for phpMAE interactive mode.", + "dependencies": { + "codemirror": "^5.60.0", + "gulp": "^4.0.2", + "gulp-concat": "^2.6.1", + "gulp-css-purge": "^3.0.9", + "gulp-sass": "^4.0.2", + "gulp-uglify": "^3.0.2", + "lodash.template": ">=4.5.0", + "materialize-css": "^1.0.0", + "streamqueue": "^1.1.2", + "jquery": "^3.4.1" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/CloudObjects/phpMAE.git" + }, + "author": "Lukas Rosenstock", + "license": "MPL", + "bugs": { + "url": "https://github.com/CloudObjects/phpMAE/issues" + }, + "homepage": "https://github.com/CloudObjects/phpMAE#readme" +} diff --git a/patch/Node.php b/patch/Node.php new file mode 100644 index 0000000..da4bb79 --- /dev/null +++ b/patch/Node.php @@ -0,0 +1,512 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ML\JsonLD; + +use stdClass as JsonObject; + +/** + * A Node represents a node in a JSON-LD graph. + * + * @author Markus Lanthaler + */ +class Node implements NodeInterface, JsonLdSerializable +{ + /** The @type constant. */ + const TYPE = '@type'; + + /** + * @var GraphInterface The graph the node belongs to. + */ + private $graph; + + /** + * @var string The ID of the node + */ + private $id; + + /** + * @var array An associative array holding all properties of the node except it's ID + */ + private $properties = array(); + + /** + * An associative array holding all reverse properties of this node, i.e., + * a pointers to all nodes that link to this node. + * + * @var array + */ + private $revProperties = array(); + + /** + * Constructor + * + * @param GraphInterface $graph The graph the node belongs to. + * @param null|string $id The ID of the node. + */ + public function __construct(GraphInterface $graph, $id = null) + { + $this->graph = $graph; + $this->id = $id; + } + + /** + * {@inheritdoc} + */ + public function getId() + { + return $this->id; + } + + /** + * {@inheritdoc} + */ + public function setType($type) + { + if ((null !== $type) && !($type instanceof NodeInterface)) { + if (is_array($type)) { + foreach ($type as $val) { + if ((null !== $val) && !($val instanceof NodeInterface)) { + throw new \InvalidArgumentException('type must be null, a Node, or an array of Nodes'); + } + } + } else { + throw new \InvalidArgumentException('type must be null, a Node, or an array of Nodes'); + } + } + + $this->setProperty(self::TYPE, $type); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function addType(NodeInterface $type) + { + $this->addPropertyValue(self::TYPE, $type); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function removeType(NodeInterface $type) + { + $this->removePropertyValue(self::TYPE, $type); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getType() + { + return $this->getProperty(self::TYPE); + } + + /** + * {@inheritdoc} + */ + public function getNodesWithThisType() + { + if (null === ($nodes = $this->getReverseProperty(self::TYPE))) { + return array(); + } + + return (is_array($nodes)) ? $nodes : array($nodes); + } + + /** + * {@inheritdoc} + */ + public function getGraph() + { + return $this->graph; + } + + /** + * {@inheritdoc} + */ + public function removeFromGraph() + { + // Remove other node's properties and reverse properties pointing to + // this node + foreach ($this->revProperties as $property => $nodes) { + foreach ($nodes as $node) { + $node->removePropertyValue($property, $this); + } + } + + foreach ($this->properties as $property => $values) { + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $value) { + if ($value instanceof NodeInterface) { + $this->removePropertyValue($property, $value); + } + } + } + + $g = $this->graph; + $this->graph = null; + + $g->removeNode($this); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function isBlankNode() + { + return ((null === $this->id) || ('_:' === substr($this->id, 0, 2))); + } + + /** + * {@inheritdoc} + */ + public function setProperty($property, $value) + { + if (null === $value) { + $this->removeProperty($property); + } else { + $this->doMergeIntoProperty((string) $property, array(), $value); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function addPropertyValue($property, $value) + { + $existing = (isset($this->properties[(string) $property])) + ? $this->properties[(string) $property] + : array(); + + if (!is_array($existing)) { + $existing = array($existing); + } + + $this->doMergeIntoProperty((string) $property, $existing, $value); + + return $this; + } + + /** + * Merge a value into a set of existing values. + * + * @param string $property The name of the property. + * @param array $existingValues The existing values. + * @param mixed $value The value to merge into the existing + * values. This MUST NOT be an array. + * + * @throws \InvalidArgumentException If value is an array or an object + * which is neither a language-tagged + * string nor a typed value or a node. + */ + private function doMergeIntoProperty($property, $existingValues, $value) + { + if (is_a($value, \PHPSandbox\SandboxedString::class)) + $value = (string)$value; + + // TODO: Handle lists! + + if (null === $value) { + return; + } + + if (!$this->isValidPropertyValue($value)) { + throw new \InvalidArgumentException( + 'value must be a scalar, a node, a language-tagged string, or a typed value' + ); + } + + $normalizedValue = $this->normalizePropertyValue($value); + + foreach ($existingValues as $existing) { + if ($this->equalValues($existing, $normalizedValue)) { + return; + } + } + + $existingValues[] = $normalizedValue; + + if (1 === count($existingValues)) { + $existingValues = $existingValues[0]; + } + + $this->properties[$property] = $existingValues; + + if ($normalizedValue instanceof NodeInterface) { + $value->addReverseProperty($property, $this); + } + } + + /** + * {@inheritdoc} + */ + public function removeProperty($property) + { + if (!isset($this->properties[(string) $property])) { + return $this; + } + + $values = is_array($this->properties[(string) $property]) + ? $this->properties[(string) $property] + : array($this->properties[(string) $property]); + + foreach ($values as $value) { + if ($value instanceof NodeInterface) { + $value->removeReverseProperty((string) $property, $this); + } + } + + unset($this->properties[(string) $property]); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function removePropertyValue($property, $value) + { + if (!$this->isValidPropertyValue($value) || !isset($this->properties[(string) $property])) { + return $this; + } + + $normalizedValue = $this->normalizePropertyValue($value); + + $values =& $this->properties[(string) $property]; + + if (!is_array($this->properties[(string) $property])) { + $values = array($values); + } + + for ($i = 0, $length = count($values); $i < $length; $i++) { + if ($this->equalValues($values[$i], $normalizedValue)) { + if ($normalizedValue instanceof NodeInterface) { + $normalizedValue->removeReverseProperty((string) $property, $this); + } + + unset($values[$i]); + break; + } + } + + if (0 === count($values)) { + unset($this->properties[(string) $property]); + + return $this; + } + + $this->properties[(string) $property] = array_values($values); // re-index the array + + if (1 === count($this->properties[(string) $property])) { + $this->properties[(string) $property] = $this->properties[(string) $property][0]; + } + } + + /** + * {@inheritdoc} + */ + public function getProperties() + { + return $this->properties; + } + + /** + * {@inheritdoc} + */ + public function getProperty($property) + { + return (isset($this->properties[(string) $property])) + ? $this->properties[(string) $property] + : null; + } + + /** + * {@inheritdoc} + */ + public function getReverseProperties() + { + $result = array(); + foreach ($this->revProperties as $key => $nodes) { + $result[$key] = array_values($nodes); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function getReverseProperty($property) + { + if (!isset($this->revProperties[(string) $property])) { + return null; + } + + $result = array_values($this->revProperties[(string) $property]); + + return (1 === count($result)) + ? $result[0] + : $result; + } + + /** + * {@inheritdoc} + */ + public function equals(NodeInterface $other) + { + return $this === $other; + } + + /** + * {@inheritdoc} + */ + public function toJsonLd($useNativeTypes = true) + { + $node = new \stdClass(); + + // Only label blank nodes if other nodes point to it + if ((false === $this->isBlankNode()) || (count($this->getReverseProperties()) > 0)) { + $node->{'@id'} = $this->getId(); + } + + $properties = $this->getProperties(); + + foreach ($properties as $prop => $values) { + if (false === is_array($values)) { + $values = array($values); + } + + if (self::TYPE === $prop) { + $node->{'@type'} = array(); + foreach ($values as $val) { + $node->{'@type'}[] = $val->getId(); + } + + continue; + } + + $node->{$prop} = array(); + + foreach ($values as $value) { + if ($value instanceof NodeInterface) { + $ref = new \stdClass(); + $ref->{'@id'} = $value->getId(); + $node->{$prop}[] = $ref; + } elseif (is_object($value)) { // language-tagged string or typed value + $node->{$prop}[] = $value->toJsonLd($useNativeTypes); + } else { + $val = new JsonObject(); + $val->{'@value'} = $value; + $node->{$prop}[] = $val; + } + } + + } + + return $node; + } + + /** + * Add a reverse property. + * + * @param string $property The name of the property. + * @param NodeInterface $node The node which has a property pointing + * to this node instance. + */ + protected function addReverseProperty($property, NodeInterface $node) + { + $this->revProperties[$property][$node->getId()] = $node; + } + + /** + * Remove a reverse property. + * + * @param string $property The name of the property. + * @param NodeInterface $node The node which has a property pointing + * to this node instance. + */ + protected function removeReverseProperty($property, NodeInterface $node) + { + unset($this->revProperties[$property][$node->getId()]); + + if (0 === count($this->revProperties[$property])) { + unset($this->revProperties[$property]); + } + } + + /** + * Checks whether a value is a valid property value. + * + * @param mixed $value The value to check. + * + * @return bool Returns true if the value is a valid property value; + * false otherwise. + */ + protected function isValidPropertyValue($value) + { + return (is_scalar($value) || + (is_object($value) && + ((($value instanceof NodeInterface) && ($value->getGraph() === $this->graph)) || + ($value instanceof Value)))); + } + + /** + * Normalizes a property value by converting scalars to Value objects. + * + * @param mixed $value The value to normalize. + * + * @return NodeInterface|Value The normalized value. + */ + protected function normalizePropertyValue($value) + { + if (false === is_scalar($value)) { + return $value; + } + + return Value::fromJsonLd((object) array('@value' => $value)); + } + + /** + * Checks whether the two specified values are the same. + * + * Scalars and nodes are checked for identity, value objects for + * equality. + * + * @param mixed $value1 Value 1. + * @param mixed $value2 Value 2. + * + * @return bool Returns true if the two values are equals; otherwise false. + */ + protected function equalValues($value1, $value2) + { + if (gettype($value1) !== gettype($value2)) { + return false; + } + + if (is_object($value1) && ($value1 instanceof Value)) { + return $value1->equals($value2); + } + + return ($value1 === $value2); + } +} diff --git a/patch/patch.sh b/patch/patch.sh new file mode 100644 index 0000000..a3d2505 --- /dev/null +++ b/patch/patch.sh @@ -0,0 +1 @@ +cp patch/Node.php vendor/ml/json-ld/Node.php \ No newline at end of file diff --git a/phpmae b/phpmae new file mode 100755 index 0000000..aa4f9c2 --- /dev/null +++ b/phpmae @@ -0,0 +1,3 @@ +#!/usr/bin/php +retriever = $retriever; + $this->reader = new NodeReader([ + 'prefixes' => [ + 'co' => 'coid://cloudobjects.io/', + 'phpmae' => 'coid://phpmae.dev/' + ] + ]); + } + + public function getTemplateVariables($coid) { + $coid = new IRI($coid); + $object = $this->retriever->getObject($coid); + if (!isset($object)) + return false; + + $isInterface = $this->reader->hasType($object, 'phpmae:Interface'); + + // Retrieve source code + $sourceUrl = $isInterface + ? $this->reader->getFirstValueString($object, 'phpmae:hasDefinitionFile') + : $this->reader->getFirstValueString($object, 'phpmae:hasSourceFile'); + if (!$sourceUrl) + return false; + $sourceCode = $this->retriever->getAttachment($coid, $sourceUrl); + + // Find method signatures and comment blocks using regular expression + $matches = []; + preg_match_all("/(?:\/\*\*((?:[\s\S](?!\/\*))*?)\*\/+\s*)?public\s+function\s+(\w+)\s*\((.*)\)/", + $sourceCode, $matches); + + // The following groups are captured through RegExes: + // 0 - complete definition block + // 1 - comment string + // 2 - method name + // 3 - method parameters + + $methods = []; + for ($i = 0; $i < count($matches[0]); $i++) { + // Remove * and whitespace from from comment string. + $commentString = trim(preg_replace('/\n\s+\*/', "\n", $matches[1][$i])); + + // Filter magic methods (incl. constructor), except __invoke + if (substr($matches[2][$i], 0, 2) == '__' && $matches[2][$i] != '__invoke') + continue; + + // Get parameters and decode for test client + $paramString = trim($matches[3][$i]); + $paramsDecoded = []; + $canRun = true; + foreach (explode(',', $paramString) as $p) { + if ($p == '') continue; // ignore empty parameter string + $p = trim($p); + if ($p[0] == '$') { + // Parameter without type hint + $paramsDecoded[] = [ + 'type' => 'text', + 'name' => substr($p, 1) + ]; + } else { + // Parameter with type hint + $p = explode(' ', $p); + $type = null; + switch ($p[0]) { + case "string": + $type = 'text'; + } + if (isset($type)) + $paramsDecoded[] = [ + 'type' => $type, + 'name' => substr($p[1], 1) + ]; + else + // Type hint points to an object which we cannot provide via JSON-RPC + $canRun = false; + } + } + + + // List methods with parameters and comment + $methods[] = [ + 'name' => $matches[2][$i], + 'params' => $paramString, + 'fields' => $paramsDecoded, + 'can_run' => $canRun, + 'comment' => $commentString + ]; + } + + $result = [ 'methods' => $methods ]; + + // Check if public, in that case include source code + if (!$isInterface + && $this->reader->hasProperty($object, 'co:isVisibleTo') + && $this->reader->getFirstValueIRI($object, 'co:isVisibleTo') + ->equals(self::CO_PUBLIC) + && $this->reader->hasProperty($object, 'co:permitsUsageTo') + && $this->reader->getFirstValueIRI($object, 'co:permitsUsageTo') + ->equals(self::CO_PUBLIC)) + $result['public_source_code'] = $sourceCode; + + return $result; + } + +} \ No newline at end of file diff --git a/phpmae-classes/DirectoryTemplateVariableGenerator.xml b/phpmae-classes/DirectoryTemplateVariableGenerator.xml new file mode 100644 index 0000000..6f887d5 --- /dev/null +++ b/phpmae-classes/DirectoryTemplateVariableGenerator.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/phpmae-classes/StackTemplateVariableGenerator.php b/phpmae-classes/StackTemplateVariableGenerator.php new file mode 100644 index 0000000..6ab4436 --- /dev/null +++ b/phpmae-classes/StackTemplateVariableGenerator.php @@ -0,0 +1,64 @@ +retriever = $retriever; + $this->reader = new NodeReader([ + 'prefixes' => [ + 'co' => 'coid://cloudobjects.io/', + 'phpmae' => 'coid://phpmae.dev/' + ] + ]); + } + + /** + * Get a key-value array of template variables for an object. + * @param string $coid The COID of the object. + */ + public function getTemplateVariables($coid) { + $coid = new IRI($coid); + $object = $this->retriever->getObject($coid); + if (!isset($object) || !$this->reader->hasType($object, 'phpmae:Stack')) + return false; + + // Retrieve files + $composerFile = json_decode($this->retriever->getAttachment($coid, + $this->reader->getFirstValueString($object, 'phpmae:hasAttachedComposerFile')), true); + $lockFile = json_decode($this->retriever->getAttachment($coid, + $this->reader->getFirstValueString($object, 'phpmae:hasAttachedLockFile')), true); + + // Compile output + $output = [ + 'defined' => [], + 'actual' => [] + ]; + + foreach ($composerFile['require'] as $name => $version) { + $output['defined'][] = [ + 'name' => $name, + 'version' => $version + ]; + } + + foreach ($lockFile['packages'] as $package) { + $output['actual'][] = [ + 'name' => $package['name'], + 'version' => $package['version'], + 'defined' => isset($composerFile['require'][$package['name']]) + ]; + } + + return $output; + } +} \ No newline at end of file diff --git a/phpmae-classes/StackTemplateVariableGenerator.xml b/phpmae-classes/StackTemplateVariableGenerator.xml new file mode 100644 index 0000000..bb44968 --- /dev/null +++ b/phpmae-classes/StackTemplateVariableGenerator.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/phpmae.docker b/phpmae.docker new file mode 100644 index 0000000..5080133 --- /dev/null +++ b/phpmae.docker @@ -0,0 +1,3 @@ +#!/usr/bin/php +add(new ClassCreateCommand); +$app->add(new ClassDeployCommand); +$app->add(new ClassValidateCommand); +$app->add(new ClassTestEnvCommand); +$app->add(new ClassTestEnvRPCCommand); + +$app->add(new DependenciesAddClassCommand); +$app->add(new DependenciesAddWebAPICommand); +$app->add(new DependenciesAddStaticTextCommand); +$app->add(new DependenciesAddAttachmentCommand); +$app->add(new DependenciesAddTemplateCommand); + +$app->add(new InterfaceCreateCommand); +$app->add(new InterfaceDeployCommand); +$app->add(new InterfaceValidateCommand); + +$app->add(new TestEnvironmentStartCommand); +$app->run(); diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..631fa50 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,17 @@ + + + + + ./tests + + + diff --git a/scss/materialize-colors.scss b/scss/materialize-colors.scss new file mode 100644 index 0000000..882fbaa --- /dev/null +++ b/scss/materialize-colors.scss @@ -0,0 +1,377 @@ +// Custom Color + +$co-primary: ( + "base" : #7976FF +); + +// Google Color Palette defined: http://www.google.com/design/spec/style/color.html + +$materialize-red: ( + "base": #e51c23, + "lighten-5": #fdeaeb, + "lighten-4": #f8c1c3, + "lighten-3": #f3989b, + "lighten-2": #ee6e73, + "lighten-1": #ea454b, + "darken-1": #d0181e, + "darken-2": #b9151b, + "darken-3": #a21318, + "darken-4": #8b1014, +); + +$red: ( + "base": #F44336, + "lighten-5": #FFEBEE, + "lighten-4": #FFCDD2, + "lighten-3": #EF9A9A, + "lighten-2": #E57373, + "lighten-1": #EF5350, + "darken-1": #E53935, + "darken-2": #D32F2F, + "darken-3": #C62828, + "darken-4": #B71C1C, + "accent-1": #FF8A80, + "accent-2": #FF5252, + "accent-3": #FF1744, + "accent-4": #D50000 +); + +$pink: ( + "base": #e91e63, + "lighten-5": #fce4ec, + "lighten-4": #f8bbd0, + "lighten-3": #f48fb1, + "lighten-2": #f06292, + "lighten-1": #ec407a, + "darken-1": #d81b60, + "darken-2": #c2185b, + "darken-3": #ad1457, + "darken-4": #880e4f, + "accent-1": #ff80ab, + "accent-2": #ff4081, + "accent-3": #f50057, + "accent-4": #c51162 +); + +$purple: ( + "base": #9c27b0, + "lighten-5": #f3e5f5, + "lighten-4": #e1bee7, + "lighten-3": #ce93d8, + "lighten-2": #ba68c8, + "lighten-1": #ab47bc, + "darken-1": #8e24aa, + "darken-2": #7b1fa2, + "darken-3": #6a1b9a, + "darken-4": #4a148c, + "accent-1": #ea80fc, + "accent-2": #e040fb, + "accent-3": #d500f9, + "accent-4": #aa00ff +); + +$deep-purple: ( + "base": #673ab7, + "lighten-5": #ede7f6, + "lighten-4": #d1c4e9, + "lighten-3": #b39ddb, + "lighten-2": #9575cd, + "lighten-1": #7e57c2, + "darken-1": #5e35b1, + "darken-2": #512da8, + "darken-3": #4527a0, + "darken-4": #311b92, + "accent-1": #b388ff, + "accent-2": #7c4dff, + "accent-3": #651fff, + "accent-4": #6200ea +); + +$indigo: ( + "base": #3f51b5, + "lighten-5": #e8eaf6, + "lighten-4": #c5cae9, + "lighten-3": #9fa8da, + "lighten-2": #7986cb, + "lighten-1": #5c6bc0, + "darken-1": #3949ab, + "darken-2": #303f9f, + "darken-3": #283593, + "darken-4": #1a237e, + "accent-1": #8c9eff, + "accent-2": #536dfe, + "accent-3": #3d5afe, + "accent-4": #304ffe +); + +$blue: ( + "base": #2196F3, + "lighten-5": #E3F2FD, + "lighten-4": #BBDEFB, + "lighten-3": #90CAF9, + "lighten-2": #64B5F6, + "lighten-1": #42A5F5, + "darken-1": #1E88E5, + "darken-2": #1976D2, + "darken-3": #1565C0, + "darken-4": #0D47A1, + "accent-1": #82B1FF, + "accent-2": #448AFF, + "accent-3": #2979FF, + "accent-4": #2962FF +); + +$light-blue: ( + "base": #03a9f4, + "lighten-5": #e1f5fe, + "lighten-4": #b3e5fc, + "lighten-3": #81d4fa, + "lighten-2": #4fc3f7, + "lighten-1": #29b6f6, + "darken-1": #039be5, + "darken-2": #0288d1, + "darken-3": #0277bd, + "darken-4": #01579b, + "accent-1": #80d8ff, + "accent-2": #40c4ff, + "accent-3": #00b0ff, + "accent-4": #0091ea +); + +$cyan: ( + "base": #00bcd4, + "lighten-5": #e0f7fa, + "lighten-4": #b2ebf2, + "lighten-3": #80deea, + "lighten-2": #4dd0e1, + "lighten-1": #26c6da, + "darken-1": #00acc1, + "darken-2": #0097a7, + "darken-3": #00838f, + "darken-4": #006064, + "accent-1": #84ffff, + "accent-2": #18ffff, + "accent-3": #00e5ff, + "accent-4": #00b8d4 +); + +$teal: ( + "base": #009688, + "lighten-5": #e0f2f1, + "lighten-4": #b2dfdb, + "lighten-3": #80cbc4, + "lighten-2": #4db6ac, + "lighten-1": #26a69a, + "darken-1": #00897b, + "darken-2": #00796b, + "darken-3": #00695c, + "darken-4": #004d40, + "accent-1": #a7ffeb, + "accent-2": #64ffda, + "accent-3": #1de9b6, + "accent-4": #00bfa5 +); + +$green: ( + "base": #4CAF50, + "lighten-5": #E8F5E9, + "lighten-4": #C8E6C9, + "lighten-3": #A5D6A7, + "lighten-2": #81C784, + "lighten-1": #66BB6A, + "darken-1": #43A047, + "darken-2": #388E3C, + "darken-3": #2E7D32, + "darken-4": #1B5E20, + "accent-1": #B9F6CA, + "accent-2": #69F0AE, + "accent-3": #00E676, + "accent-4": #00C853 +); + +$light-green: ( + "base": #8bc34a, + "lighten-5": #f1f8e9, + "lighten-4": #dcedc8, + "lighten-3": #c5e1a5, + "lighten-2": #aed581, + "lighten-1": #9ccc65, + "darken-1": #7cb342, + "darken-2": #689f38, + "darken-3": #558b2f, + "darken-4": #33691e, + "accent-1": #ccff90, + "accent-2": #b2ff59, + "accent-3": #76ff03, + "accent-4": #64dd17 +); + +$lime: ( + "base": #cddc39, + "lighten-5": #f9fbe7, + "lighten-4": #f0f4c3, + "lighten-3": #e6ee9c, + "lighten-2": #dce775, + "lighten-1": #d4e157, + "darken-1": #c0ca33, + "darken-2": #afb42b, + "darken-3": #9e9d24, + "darken-4": #827717, + "accent-1": #f4ff81, + "accent-2": #eeff41, + "accent-3": #c6ff00, + "accent-4": #aeea00 +); + +$yellow: ( + "base": #ffeb3b, + "lighten-5": #fffde7, + "lighten-4": #fff9c4, + "lighten-3": #fff59d, + "lighten-2": #fff176, + "lighten-1": #ffee58, + "darken-1": #fdd835, + "darken-2": #fbc02d, + "darken-3": #f9a825, + "darken-4": #f57f17, + "accent-1": #ffff8d, + "accent-2": #ffff00, + "accent-3": #ffea00, + "accent-4": #ffd600 +); + +$amber: ( + "base": #ffc107, + "lighten-5": #fff8e1, + "lighten-4": #ffecb3, + "lighten-3": #ffe082, + "lighten-2": #ffd54f, + "lighten-1": #ffca28, + "darken-1": #ffb300, + "darken-2": #ffa000, + "darken-3": #ff8f00, + "darken-4": #ff6f00, + "accent-1": #ffe57f, + "accent-2": #ffd740, + "accent-3": #ffc400, + "accent-4": #ffab00 +); + +$orange: ( + "base": #ff9800, + "lighten-5": #fff3e0, + "lighten-4": #ffe0b2, + "lighten-3": #ffcc80, + "lighten-2": #ffb74d, + "lighten-1": #ffa726, + "darken-1": #fb8c00, + "darken-2": #f57c00, + "darken-3": #ef6c00, + "darken-4": #e65100, + "accent-1": #ffd180, + "accent-2": #ffab40, + "accent-3": #ff9100, + "accent-4": #ff6d00 +); + +$deep-orange: ( + "base": #ff5722, + "lighten-5": #fbe9e7, + "lighten-4": #ffccbc, + "lighten-3": #ffab91, + "lighten-2": #ff8a65, + "lighten-1": #ff7043, + "darken-1": #f4511e, + "darken-2": #e64a19, + "darken-3": #d84315, + "darken-4": #bf360c, + "accent-1": #ff9e80, + "accent-2": #ff6e40, + "accent-3": #ff3d00, + "accent-4": #dd2c00 +); + +$brown: ( + "base": #795548, + "lighten-5": #efebe9, + "lighten-4": #d7ccc8, + "lighten-3": #bcaaa4, + "lighten-2": #a1887f, + "lighten-1": #8d6e63, + "darken-1": #6d4c41, + "darken-2": #5d4037, + "darken-3": #4e342e, + "darken-4": #3e2723 +); + +$blue-grey: ( + "base": #607d8b, + "lighten-5": #eceff1, + "lighten-4": #cfd8dc, + "lighten-3": #b0bec5, + "lighten-2": #90a4ae, + "lighten-1": #78909c, + "darken-1": #546e7a, + "darken-2": #455a64, + "darken-3": #37474f, + "darken-4": #263238 +); + +$grey: ( + "base": #9e9e9e, + "lighten-5": #fafafa, + "lighten-4": #f5f5f5, + "lighten-3": #eeeeee, + "lighten-2": #e0e0e0, + "lighten-1": #bdbdbd, + "darken-1": #757575, + "darken-2": #616161, + "darken-3": #424242, + "darken-4": #212121 +); + +$shades: ( + "black": #000000, + "white": #FFFFFF, + "transparent": transparent +); + +$colors: ( + "materialize-red": $materialize-red, + "red": $red, + "pink": $pink, + "purple": $purple, + "deep-purple": $deep-purple, + "indigo": $indigo, + "blue": $blue, + "light-blue": $light-blue, + "cyan": $cyan, + "teal": $teal, + "green": $green, + "light-green": $light-green, + "lime": $lime, + "yellow": $yellow, + "amber": $amber, + "orange": $orange, + "deep-orange": $deep-orange, + "brown": $brown, + "blue-grey": $blue-grey, + "grey": $grey, + "shades": $shades, + "co-primary": $co-primary +) !default; + + +// usage: color("name_of_color", "type_of_color") +// to avoid to repeating map-get($colors, ...) + +@function color($color, $type) { + @if map-has-key($colors, $color) { + $curr_color: map-get($colors, $color); + @if map-has-key($curr_color, $type) { + @return map-get($curr_color, $type); + } + } + @warn "Unknown `#{$color}` - `#{$type}` in $colors."; + @return null; +} diff --git a/scss/materialize-customized.scss b/scss/materialize-customized.scss new file mode 100644 index 0000000..0490b41 --- /dev/null +++ b/scss/materialize-customized.scss @@ -0,0 +1,41 @@ +@charset "UTF-8"; + +// Color +@import "materialize-colors.scss"; +@import "../node_modules/materialize-css/sass/components/color-classes"; + +// Variables; +@import "materialize-variables"; + +// Reset +@import "../node_modules/materialize-css/sass/components/normalize"; + +// components +@import "../node_modules/materialize-css/sass/components/global"; +@import "../node_modules/materialize-css/sass/components/badges"; +@import "../node_modules/materialize-css/sass/components/icons-material-design"; +@import "../node_modules/materialize-css/sass/components/grid"; +@import "../node_modules/materialize-css/sass/components/navbar"; +@import "../node_modules/materialize-css/sass/components/typography"; +@import "../node_modules/materialize-css/sass/components/transitions"; +@import "../node_modules/materialize-css/sass/components/cards"; +@import "../node_modules/materialize-css/sass/components/toast"; +@import "../node_modules/materialize-css/sass/components/tabs"; +@import "../node_modules/materialize-css/sass/components/tooltip"; +@import "../node_modules/materialize-css/sass/components/buttons"; +@import "../node_modules/materialize-css/sass/components/dropdown"; +@import "../node_modules/materialize-css/sass/components/waves"; +@import "../node_modules/materialize-css/sass/components/modal"; +@import "../node_modules/materialize-css/sass/components/collapsible"; +@import "../node_modules/materialize-css/sass/components/chips"; +@import "../node_modules/materialize-css/sass/components/materialbox"; +@import "../node_modules/materialize-css/sass/components/forms/forms"; +@import "../node_modules/materialize-css/sass/components/table_of_contents"; +@import "../node_modules/materialize-css/sass/components/sidenav"; +@import "../node_modules/materialize-css/sass/components/preloader"; +@import "../node_modules/materialize-css/sass/components/slider"; +// @import "../node_modules/materialize-css/sass/components/carousel"; - currently not used +@import "../node_modules/materialize-css/sass/components/tapTarget"; +@import "../node_modules/materialize-css/sass/components/pulse"; +// @import "../node_modules/materialize-css/sass/components/datepicker"; - currently not used +// @import "../node_modules/materialize-css/sass/components/timepicker"; - currently not used diff --git a/scss/materialize-variables.scss b/scss/materialize-variables.scss new file mode 100644 index 0000000..837bf63 --- /dev/null +++ b/scss/materialize-variables.scss @@ -0,0 +1,350 @@ +// ========================================================================== +// Materialize variables +// ========================================================================== +// +// Table of Contents: +// +// 1. Colors +// 2. Badges +// 3. Buttons +// 4. Cards +// 5. Carousel +// 6. Collapsible +// 7. Chips +// 8. Date + Time Picker +// 9. Dropdown +// 10. Forms +// 11. Global +// 12. Grid +// 13. Navigation Bar +// 14. Side Navigation +// 15. Photo Slider +// 16. Spinners | Loaders +// 17. Tabs +// 18. Tables +// 19. Toasts +// 20. Typography +// 21. Footer +// 22. Flow Text +// 23. Collections +// 24. Progress Bar + + + +// 1. Colors +// ========================================================================== + +$primary-color: color("co-primary", "base") !default; +$primary-color-light: lighten($primary-color, 15%) !default; +$primary-color-dark: darken($primary-color, 15%) !default; + +$secondary-color: color("co-primary", "base") !default; +// origina: $secondary-color: color("teal", "lighten-1") !default; +$success-color: color("green", "base") !default; +$error-color: color("red", "base") !default; +$link-color: color("light-blue", "darken-1") !default; + + +// 2. Badges +// ========================================================================== + +$badge-bg-color: $secondary-color !default; +$badge-height: 22px !default; + + +// 3. Buttons +// ========================================================================== + +// Shared styles +$button-border: none !default; +$button-background-focus: lighten($secondary-color, 4%) !default; +$button-font-size: 14px !default; +$button-icon-font-size: 1.3rem !default; +$button-height: 36px !default; +$button-padding: 0 16px !default; +$button-radius: 2px !default; + +// Disabled styles +$button-disabled-background: #DFDFDF !default; +$button-disabled-color: #9F9F9F !default; + +// Raised buttons +$button-raised-background: $secondary-color !default; +$button-raised-background-hover: lighten($button-raised-background, 5%) !default; +$button-raised-color: #fff !default; + +// Large buttons +$button-large-font-size: 15px !default; +$button-large-icon-font-size: 1.6rem !default; +$button-large-height: $button-height * 1.5 !default; +$button-floating-large-size: 56px !default; + +// Small buttons +$button-small-font-size: 13px !default; +$button-small-icon-font-size: 1.2rem !default; +$button-small-height: $button-height * .9 !default; +$button-floating-small-size: $button-height * .9 !default; + +// Flat buttons +$button-flat-color: #343434 !default; +$button-flat-disabled-color: lighten(#999, 10%) !default; + +// Floating buttons +$button-floating-background: $secondary-color !default; +$button-floating-background-hover: $button-floating-background !default; +$button-floating-color: #fff !default; +$button-floating-size: 40px !default; +$button-floating-radius: 50% !default; + + +// 4. Cards +// ========================================================================== + +$card-padding: 24px !default; +$card-bg-color: #fff !default; +$card-link-color: color("orange", "accent-2") !default; +$card-link-color-light: lighten($card-link-color, 20%) !default; + + +// 5. Carousel +// ========================================================================== + +$carousel-height: 400px !default; +$carousel-item-height: $carousel-height / 2 !default; +$carousel-item-width: $carousel-item-height !default; + + +// 6. Collapsible +// ========================================================================== + +$collapsible-height: 3rem !default; +$collapsible-line-height: $collapsible-height !default; +$collapsible-header-color: #fff !default; +$collapsible-border-color: #ddd !default; + + +// 7. Chips +// ========================================================================== + +$chip-bg-color: #e4e4e4 !default; +$chip-border-color: #9e9e9e !default; +$chip-selected-color: #26a69a !default; +$chip-margin: 5px !default; + + +// 8. Date + Time Picker +// ========================================================================== + +$datepicker-display-font-size: 2.8rem; +$datepicker-calendar-header-color: #999; +$datepicker-weekday-color: rgba(0, 0, 0, .87) !default; +$datepicker-weekday-bg: darken($secondary-color, 7%) !default; +$datepicker-date-bg: $secondary-color !default; +$datepicker-year: rgba(255, 255, 255, .7) !default; +$datepicker-focus: rgba(0,0,0, .05) !default; +$datepicker-selected: $secondary-color !default; +$datepicker-selected-outfocus: desaturate(lighten($secondary-color, 35%), 15%) !default; +$datepicker-day-focus: transparentize(desaturate($secondary-color, 5%), .75) !default; +$datepicker-disabled-day-color: rgba(0, 0, 0, .3) !default; + +$timepicker-clock-color: rgba(0, 0, 0, .87) !default; +$timepicker-clock-plate-bg: #eee !default; + + +// 9. Dropdown +// ========================================================================== + +$dropdown-bg-color: #fff !default; +$dropdown-hover-bg-color: #eee !default; +$dropdown-color: $secondary-color !default; +$dropdown-item-height: 50px !default; + + +// 10. Forms +// ========================================================================== + +// Text Inputs + Textarea +$input-height: 3rem !default; +$input-border-color: color("grey", "base") !default; +$input-border: 1px solid $input-border-color !default; +$input-background: #fff !default; +$input-error-color: $error-color !default; +$input-success-color: $success-color !default; +$input-focus-color: $secondary-color !default; +$input-font-size: 16px !default; +$input-margin-bottom: 8px; +$input-margin: 0 0 $input-margin-bottom 0 !default; +$input-padding: 0 !default; +$label-font-size: .8rem !default; +$input-disabled-color: rgba(0,0,0, .42) !default; +$input-disabled-solid-color: #949494 !default; +$input-disabled-border: 1px dotted $input-disabled-color !default; +$input-invalid-border: 1px solid $input-error-color !default; +$input-icon-size: 2rem; +$placeholder-text-color: lighten($input-border-color, 20%) !default; + +// Radio Buttons +$radio-fill-color: $secondary-color !default; +$radio-empty-color: #5a5a5a !default; +$radio-border: 2px solid $radio-fill-color !default; + +// Range +$range-height: 14px !default; +$range-width: 14px !default; +$track-height: 3px !default; + +// Select +$select-border: 1px solid #f2f2f2 !default; +$select-background: rgba(255, 255, 255, 0.90) !default; +$select-focus: 1px solid lighten($secondary-color, 47%) !default; +$select-option-hover: rgba(0,0,0,.08) !default; +$select-option-focus: rgba(0,0,0,.08) !default; +$select-option-selected: rgba(0,0,0,.03) !default; +$select-padding: 5px !default; +$select-radius: 2px !default; +$select-disabled-color: rgba(0,0,0,.3) !default; + +// Switches +$switch-bg-color: $secondary-color !default; +$switch-checked-lever-bg: desaturate(lighten($switch-bg-color, 25%), 25%) !default; +$switch-unchecked-bg: #F1F1F1 !default; +$switch-unchecked-lever-bg: rgba(0,0,0,.38) !default; +$switch-radius: 15px !default; + + +// 11. Global +// ========================================================================== + +// Media Query Ranges +$small-screen-up: 601px !default; +$medium-screen-up: 993px !default; +$large-screen-up: 1201px !default; +$small-screen: 600px !default; +$medium-screen: 992px !default; +$large-screen: 1200px !default; + +$medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default; +$large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default; +$extra-large-and-up: "only screen and (min-width : #{$large-screen-up})" !default; +$small-and-down: "only screen and (max-width : #{$small-screen})" !default; +$medium-and-down: "only screen and (max-width : #{$medium-screen})" !default; +$medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default; + + +// 12. Grid +// ========================================================================== + +$num-cols: 12 !default; +$gutter-width: 1.5rem !default; +$element-top-margin: $gutter-width/3 !default; +$element-bottom-margin: ($gutter-width*2)/3 !default; + + +// 13. Navigation Bar +// ========================================================================== + +$navbar-height: 64px !default; +$navbar-line-height: $navbar-height !default; +$navbar-height-mobile: 56px !default; +$navbar-line-height-mobile: $navbar-height-mobile !default; +$navbar-font-size: 1rem !default; +$navbar-font-color: #fff !default; +$navbar-brand-font-size: 2.1rem !default; + +// 14. Side Navigation +// ========================================================================== + +$sidenav-width: 300px !default; +$sidenav-font-size: 14px !default; +$sidenav-font-color: rgba(0,0,0,.87) !default; +$sidenav-bg-color: #fff !default; +$sidenav-padding: 16px !default; +$sidenav-item-height: 48px !default; +$sidenav-line-height: $sidenav-item-height !default; + + +// 15. Photo Slider +// ========================================================================== + +$slider-bg-color: color('grey', 'base') !default; +$slider-bg-color-light: color('grey', 'lighten-2') !default; +$slider-indicator-color: color('green', 'base') !default; + + +// 16. Spinners | Loaders +// ========================================================================== + +$spinner-default-color: $secondary-color !default; + + +// 17. Tabs +// ========================================================================== + +$tabs-underline-color: $primary-color-light !default; +$tabs-text-color: $primary-color !default; +$tabs-bg-color: #fff !default; + + +// 18. Tables +// ========================================================================== + +$table-border-color: rgba(0,0,0,.12) !default; +$table-striped-color: rgba(242, 242, 242, 0.5) !default; + + +// 19. Toasts +// ========================================================================== + +$toast-height: 48px !default; +$toast-color: #323232 !default; +$toast-text-color: #fff !default; +$toast-action-color: #eeff41; + + +// 20. Typography +// ========================================================================== + +$font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif !default; +$off-black: rgba(0, 0, 0, 0.87) !default; +// Header Styles +$h1-fontsize: 4.2rem !default; +$h2-fontsize: 3.56rem !default; +$h3-fontsize: 2.92rem !default; +$h4-fontsize: 2.28rem !default; +$h5-fontsize: 1.64rem !default; +$h6-fontsize: 1.15rem !default; + + +// 21. Footer +// ========================================================================== + +$footer-font-color: #fff !default; +$footer-bg-color: $primary-color !default; +$footer-copyright-font-color: rgba(255,255,255,.8) !default; +$footer-copyright-bg-color: rgba(51,51,51,.08) !default; + + +// 22. Flow Text +// ========================================================================== + +$range : $large-screen - $small-screen !default; +$intervals: 20 !default; +$interval-size: $range / $intervals !default; + + +// 23. Collections +// ========================================================================== + +$collection-border-color: #e0e0e0 !default; +$collection-bg-color: #fff !default; +$collection-active-bg-color: $secondary-color !default; +$collection-active-color: lighten($secondary-color, 55%) !default; +$collection-hover-bg-color: #ddd !default; +$collection-link-color: $secondary-color !default; +$collection-line-height: 1.5rem !default; + + +// 24. Progress Bar +// ========================================================================== + +$progress-bar-color: $secondary-color !default; diff --git a/static/app.css b/static/app.css new file mode 100644 index 0000000..568d08f --- /dev/null +++ b/static/app.css @@ -0,0 +1,15 @@ +#phpmae-main-grid { + margin:15px 0; +} + +#phpmae-result { + font-family: monospace; +} + +#phpmae-source-editor, #phpmae-config-editor { + margin:15px 0; +} + +.phpmae-signedout-only, .phpmae-signedin-only { + display:none; +} \ No newline at end of file diff --git a/static/app.html b/static/app.html new file mode 100644 index 0000000..b05a48b --- /dev/null +++ b/static/app.html @@ -0,0 +1,80 @@ + + + + phpMAE + + + + + + +
+
+ +
+
+
+
+
+
+ + +
+
+ + +
+
+
+ +
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/static/app.js b/static/app.js new file mode 100644 index 0000000..4586420 --- /dev/null +++ b/static/app.js @@ -0,0 +1,265 @@ +$(function() { + var sessionId = sessionStorage.getItem('phpMaeSessionId'); + var functionMatcher = /(?:\/\*\*((?:[\s\S](?!\/\*))*?)\*\/+\s*)?public\s+function\s+(\w+)\s*\((.*)\)/g; + var codeEditor = CodeMirror(document.getElementById('phpmae-source-editor'), { + lineNumbers: false, + matchBrackets: true, + mode: "application/x-httpd-php", + indentUnit: 4, + indentWithTabs: false + }); + var configEditor = CodeMirror(document.getElementById('phpmae-config-editor'), { + lineNumbers: false, + matchBrackets: true, + mode: "application/xml", + indentUnit: 4, + indentWithTabs: false + }); + var dirty = false; + + function checkSignInStatus() { + if (typeof(COWebApp) !== "undefined" && COWebApp.getAccountContext() !== null) { + // Signed in + $('.phpmae-signedout-only').hide(); + $('.phpmae-signedin-only').show(); + } else { + // Signed out + $('.phpmae-signedin-only').hide(); + $('.phpmae-signedout-only').show(); + } + } + + function updateParameters(functionName) { + var sourceCode = codeEditor.getValue(); + var container = $('#phpmae-parameter-container'); + var parametersHtml = ""; + do { + functionMatch = functionMatcher.exec(sourceCode); + if (functionMatch && functionMatch[2] == functionName) { + var parameters = functionMatch[3].split(","); + for (var p in parameters) { + var parameter = parameters[p].trim(); + if (parameter[0] != "$" || parameter.length < 2) continue; + var noPrefix = parameter.substr(1); + var oldValue = container.find('[name=' + noPrefix + ']').val(); + parametersHtml += '
' + + '' + + '' + + '
'; + } + } + } while (functionMatch); + container.html(parametersHtml); + M.updateTextFields(); + } + + window.phpMAE = { + execute : function(form) { + form = $(form); + form.find('button').addClass('disabled'); + + var request = { + config : configEditor.getValue(), + sourceCode : codeEditor.getValue(), + class : form.find('[name=class]').val(), + method : form.find('[name=function]').val(), + params : {} + }; + if (sessionId != null) request.session = sessionId; + var parameters = form.find('input'); + for (var p in parameters) + request.params[parameters[p].name] = parameters[p].value; + + fetch('/run', { + method : 'POST', + headers : { 'Content-Type' : 'application/json' }, + body : JSON.stringify(request) + }).then(function(response) { + response.json().then(function(data) { + if (data.session != sessionId) { + sessionId = data.session; + sessionStorage.setItem('phpMaeSessionId', sessionId); + } + $('#phpmae-result') + .text((typeof(data.content) == "object") + ? JSON.stringify(data.content, null, 2) + : data.content) + .css('color', (data.status == "error") ? "#ff0000" : "#000000"); + form.find('button').removeClass('disabled'); + }); + }); + }, + loadTemplate : function(template) { + if (dirty == false || window.confirm("Do you want to load this template? This will delete your code changes!")) + fetch('/templates/' + template + '.txt').then(function (response) { + response.text().then(function(data) { + var template = data.split("\n----\n"); + if (template.length !== 2) { + alert("Invalid template file!"); + return; + } + codeEditor.setValue(template[0]); + configEditor.setValue(template[1]); + + // Add class name + var classDefinition = template[0].match(/class\s+(\w+)/); + $('input[name="class"]').val( + (classDefinition.length > 1 ? classDefinition[1] : "") + ); + + // Build executor function list + var functionOptionsHtml = ""; + var firstFunction = null; + do { + functionMatch = functionMatcher.exec(template[0]); + if (functionMatch && functionMatch[2] != "__construct") { + firstFunction = firstFunction || functionMatch[2]; + functionOptionsHtml += ''; + } + } while (functionMatch); + $('select[name=function]').html(functionOptionsHtml).formSelect(); + updateParameters(firstFunction); + + // Clear output + $('#phpmae-result').text(''); + + dirty = false; + }); + }); + }, + signin : function() { + alert("Coming soon!") + }, + signout : function() { + COWebApp.signOut(); + } + }; + + codeEditor.on("change", function(instance, change) { + dirty = true; + var line = instance.getLine(change.from.line); + if (line.indexOf("class") > -1) { + var classDefinition = instance.getValue().match(/class\s+(\w+)/); + $('input[name="class"]').val( + (classDefinition.length > 1 ? classDefinition[1] : "") + ); + } else + if (line.indexOf("function") > -1) { + var sourceCode = instance.getValue(); + var selector = $('select[name=function]'); + var currentlySelected = selector.val(); + var previousExists = false; + var functionOptionsHtml = ""; + do { + functionMatch = functionMatcher.exec(sourceCode); + if (functionMatch && functionMatch[2] != "__construct") { + previousExists = previousExists || (functionMatch[2] == currentlySelected); + functionOptionsHtml += ''; + } + } while (functionMatch); + selector.html(functionOptionsHtml).formSelect(); + updateParameters(selector.val()); + } + }); + + configEditor.on("change", function(instance, change) { + dirty = true; + }); + + $('.tabs').tabs({ + onShow : function() { + codeEditor.refresh(); + configEditor.refresh(); + } + }); + + $('select[name=function]').on('change', function() { + updateParameters($(this).val()); + }).formSelect(); + + $('.dropdown-trigger').dropdown({ + constrainWidth : false, + coverTrigger : false + }); + + function fixHeight() { + $('.CodeMirror').css('height', ($(window).height() - $('.CodeMirror').offset().top - 30) + 'px'); + } + + $(window).on('resize', fixHeight); + fixHeight(); + checkSignInStatus(); + phpMAE.loadTemplate('helloworld'); + + // Initialize loader modal + $('#phpmae-load').modal({ + onOpenStart : function() { + var domainSelector = $('#phpmae-load-form-domain'); + var objectSelector = $('#phpmae-load-form-domain-object'); + var step2 = $('#phpmae-load-form-step2'); + var coAgwClient = COWebApp.getAccountContext().getClient(); + + // Get domains and create list in domain selector field + domainSelector.attr('disabled', true).formSelect(); + + coAgwClient.get('/dr/').then(function(response) { + response.data.domains.forEach(function(domain) { + domainSelector.append(''); + }); + + domainSelector.attr('disabled', false) + .formSelect(); // re-render with Materialize UI + }); + + domainSelector.on('change', function() { + if (domainSelector.val() != "") { + step2.show(); + + // Reset input and view + objectSelector.html('') + .attr('disabled', true) + .formSelect(); + + // Get objects and create list in object selector field + coAgwClient.get('/ws/' + domainSelector.val() + '/all.jsonld?type=' + + encodeURIComponent('coid://phpmae.dev/Class') + '&jsonld_format=expanded') + .then(function(response) { + currentDomainDoc = LD(response.data, { + 'rdfs' : 'http://www.w3.org/2000/01/rdf-schema#' + }); + + var ids = currentDomainDoc.queryAll('[@type=' + options.domain + '] > @id'); + if (ids.length == 1) { + // Single result is automatically selected + var label = currentDomainDoc + .query('[@id=' + ids[0] + '] > rdfs:label @value'); + objectSelector.html(''); + objectSelector.trigger('change'); + } else { + // Multiple results give options + ids.forEach(function(id) { + var label = currentDomainDoc + .query('[@id=' + id + '] > rdfs:label @value'); + objectSelector.append(''); + }); + } + + objectSelector.attr('disabled', false) + .formSelect(); // re-render with Materialize UI + }); + } else { + step2.hide(); + } + }); + } + }); +}); \ No newline at end of file diff --git a/static/app_disabled.html b/static/app_disabled.html new file mode 100644 index 0000000..57d93d8 --- /dev/null +++ b/static/app_disabled.html @@ -0,0 +1,10 @@ + + + + phpMAE + + +

phpMAE

+

This is a phpMAE instance.

+ + \ No newline at end of file diff --git a/static/templates/helloworld.txt b/static/templates/helloworld.txt new file mode 100644 index 0000000..ad8c036 --- /dev/null +++ b/static/templates/helloworld.txt @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/static/templates/mathdemo.txt b/static/templates/mathdemo.txt new file mode 100644 index 0000000..d7df2e4 --- /dev/null +++ b/static/templates/mathdemo.txt @@ -0,0 +1,30 @@ + + + + + + + \ No newline at end of file diff --git a/stub.php b/stub.php new file mode 100644 index 0000000..d9f6993 --- /dev/null +++ b/stub.php @@ -0,0 +1,10 @@ +#!/usr/bin/php +validator = new ClassValidator; + } + + public function testValidate() { + $this->validator->validate($this->loadFromFile('class1.php'), + new IRI('coid://example.com/TestClass1')); + } + + public function testNonWhitelistedClass() { + $this->expectException(\PHPSandbox\Error::class); + $this->validator->validate($this->loadFromFile('class2.php'), + new IRI('coid://example.com/TestClass2')); + } + +} \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..8bb7710 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,3 @@ +get('mode'); +if ($mode == 'default') { + // Default mode + $container->get(Engine::class)->run(); +} elseif (substr($mode, 0, 7) == 'router:' || $mode == 'hybrid') { + // Router or hybrid mode + $container->get(Router::class)->run(); +} else { + // Error + echo "Invalid mode!"; +} \ No newline at end of file