diff --git a/.babelrc b/.babelrc deleted file mode 100644 index d8a888ed..00000000 --- a/.babelrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "presets": ["es2015"], - "compact": true, - "minified": true, - "only": "public/themes/pterodactyl/js/frontend/files/src/*.js", - "sourceMaps": "inline", - "comments": false -} diff --git a/.dev/vagrant/provision.sh b/.dev/vagrant/provision.sh index 38dc27ad..35a2219f 100644 --- a/.dev/vagrant/provision.sh +++ b/.dev/vagrant/provision.sh @@ -21,6 +21,12 @@ debconf-set-selections <<< 'mariadb-server-5.5 mysql-server/root_password_again # actually install apt-get install -y php7.2 php7.2-cli php7.2-gd php7.2-mysql php7.2-pdo php7.2-mbstring php7.2-tokenizer php7.2-bcmath php7.2-xml php7.2-fpm php7.2-memcached php7.2-curl php7.2-zip php-xdebug mariadb-server nginx curl tar unzip git memcached > /dev/null +echo "Install nodejs and yarn" +curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - +apt-get -y install nodejs yarn > /dev/null + echo "Install composer" curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer diff --git a/.env.dusk b/.env.dusk new file mode 100644 index 00000000..237f61d3 --- /dev/null +++ b/.env.dusk @@ -0,0 +1,26 @@ +APP_ENV=local +APP_DEBUG=false +APP_KEY=NDWgIKKi9ovNK1PXZpzfNVSBdfCXGb5i +APP_JWT_KEY=test1234 +APP_TIMEZONE=America/Los_Angeles +APP_URL=http://pterodactyl.local + +CACHE_DRIVER=file +SESSION_DRIVER=file + +HASHIDS_SALT=IqRr0g82tCTeuyxGs8RV +HASHIDS_LENGTH=8 + +MAIL_DRIVER=log +MAIL_FROM=support@pterodactyl.io +QUEUE_DRIVER=array + +APP_SERVICE_AUTHOR=testing@pterodactyl.io +MAIL_FROM_NAME="Pterodactyl Panel" +RECAPTCHA_ENABLED=false + +DB_CONNECTION=testing +TESTING_DB_HOST=192.168.1.202 +TESTING_DB_DATABASE=panel_test +TESTING_DB_USERNAME=panel_test +TESTING_DB_PASSWORD=Test1234 diff --git a/.env.example b/.env.example index 0b59de0c..9062de21 100644 --- a/.env.example +++ b/.env.example @@ -28,4 +28,4 @@ MAIL_FROM=no-reply@example.com QUEUE_HIGH=high QUEUE_STANDARD=standard -QUEUE_LOW=low \ No newline at end of file +QUEUE_LOW=low diff --git a/.gitignore b/.gitignore index 9fc4aee5..99ba2aec 100644 --- a/.gitignore +++ b/.gitignore @@ -7,15 +7,12 @@ storage/framework/* /.idea /nbproject -package-lock.json -composer.lock node_modules - -_ide_helper_models.php +*.log _ide_helper.php - -sami.phar -/.sami +.phpstorm.meta.php +.php_cs.cache +public/assets/* # For local development with docker # Remove if we ever put the Dockerfile in the repo @@ -32,3 +29,6 @@ coverage.xml # Vagrant *.log +resources/lang/locales.js +resources/assets/pterodactyl/scripts/helpers/ziggy.js +resources/assets/scripts/helpers/ziggy.js diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 00000000..286cc3c6 --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,57 @@ +# Local Development +Pterodactyl is now powered by Vuejs and Tailwindcss and uses webpack at its core to generate compiled assets. Release +versions of Pterodactyl will include pre-compiled, minified, and hashed assets ready-to-go. + +However, if you are interested in running custom themes or making modifications to the Vue files you'll need a build +system in place to generate these compiled assets. To get your environment setup, you'll first need to install at least Nodejs +`8`, and it is _highly_ recommended that you also install [Yarn](https://yarnpkg.com) to manage your `node_modules`. + +### Install Dependencies +```bash +yarn install +``` + +The command above will download all of the dependencies necessary to get Pterodactyl assets building. After that, its as +simple as running the command below to generate assets while you're developing. + +```bash +# build the compiled assets for development +yarn run build + +# build the assets automatically when files are modified +yarn run watch +``` + + +### Hot Module Reloading +For more advanced users, we also support 'Hot Module Reloading', allowing you to quickly see changes you're making +to the Vue template files without having to reload the page you're on. To Get started with this, you just need +to run the command below. + +```bash +PUBLIC_PATH=http://192.168.1.1:8080 yarn run serve --host 192.168.1.1 +``` + +There are two _very important_ parts of this command to take note of and change for your specific environment. The first +is the `--host` flag, which is required and should point to the machine where the `webpack-serve` server will be running. +The second is the `PUBLIC_PATH` environment variable which is the URL pointing to the HMR server and is appended to all of +the asset URLs used in Pterodactyl. + +#### Vagrant +If you want to use HMR with our Vagrant image, you can use `yarn run v:serve` as a shortcut for the correct parameters. +In order to have proper file change detection you can use the [`vagrant-notify-forwarder`](https://github.com/mhallin/vagrant-notify-forwarder) to notify file events from the host to the VM. +```sh +vagrant plugin install vagrant-notify-forwarder +vagrant reload +``` + +### Building for Production +Once you have your files squared away and ready for the live server, you'll be needing to generate compiled, minified, and +hashed assets to push live. To do so, run the command below: + +```bash +yarn run build:production +``` + +This will generate a production ready `bundle.js` and `bundle.css` as well as a `manifest.json` and store them in +the `/public/assets` directory where they can then be access by clients, and read by the Panel. diff --git a/CHANGELOG.md b/CHANGELOG.md index 41743418..d1f0a2a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -239,7 +239,7 @@ the response from the server `GET` endpoint. * Nest and Egg listings now show the associated ID in order to make API requests easier. * Added star indicators to user listing in Admin CP to indicate users who are set as a root admin. * Creating a new node will now requires a SSL connection if the Panel is configured to use SSL as well. -* Socketio error messages due to permissions are now rendered correctly in the UI rather than causing a silent failure. +* Connector error messages due to permissions are now rendered correctly in the UI rather than causing a silent failure. * File manager now supports mass deletion option for files and folders. * Support for CS:GO as a default service option selection. * Support for GMOD as a default service option selection. @@ -369,7 +369,7 @@ the response from the server `GET` endpoint. * Changed 2FA login process to be more secure. Previously authentication checking happened on the 2FA post page, now it happens prior and is passed along to the 2FA page to avoid storing any credentials. ### Added -* Socketio error messages due to permissions are now rendered correctly in the UI rather than causing a silent failure. +* Connector error messages due to permissions are now rendered correctly in the UI rather than causing a silent failure. ## v0.7.0-beta.1 (Derelict Dermodactylus) ### Added diff --git a/app/Contracts/Http/ClientPermissionsRequest.php b/app/Contracts/Http/ClientPermissionsRequest.php new file mode 100644 index 00000000..6b863fce --- /dev/null +++ b/app/Contracts/Http/ClientPermissionsRequest.php @@ -0,0 +1,15 @@ +expectsJson()) { - return response()->json(['error' => 'Unauthenticated.'], 401); + return response()->json(self::convertToArray($exception), 401); } return redirect()->guest(route('auth.login')); diff --git a/app/Http/Controllers/Api/Client/AccountController.php b/app/Http/Controllers/Api/Client/AccountController.php new file mode 100644 index 00000000..965d0126 --- /dev/null +++ b/app/Http/Controllers/Api/Client/AccountController.php @@ -0,0 +1,73 @@ +updateService = $updateService; + } + + /** + * @param Request $request + * @return array + */ + public function index(Request $request): array + { + return $this->fractal->item($request->user()) + ->transformWith($this->getTransformer(AccountTransformer::class)) + ->toArray(); + } + + /** + * Update the authenticated user's email address. + * + * @param \Pterodactyl\Http\Requests\Api\Client\Account\UpdateEmailRequest $request + * @return \Illuminate\Http\Response + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function updateEmail(UpdateEmailRequest $request): Response + { + $this->updateService->handle($request->user(), $request->validated()); + + return response('', Response::HTTP_CREATED); + } + + /** + * Update the authenticated user's password. + * + * @param \Pterodactyl\Http\Requests\Api\Client\Account\UpdatePasswordRequest $request + * @return \Illuminate\Http\Response + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function updatePassword(UpdatePasswordRequest $request): Response + { + $this->updateService->handle($request->user(), $request->validated()); + + return response('', Response::HTTP_CREATED); + } +} diff --git a/app/Http/Controllers/Api/Client/ClientController.php b/app/Http/Controllers/Api/Client/ClientController.php index 2dffba8f..62b5d2c4 100644 --- a/app/Http/Controllers/Api/Client/ClientController.php +++ b/app/Http/Controllers/Api/Client/ClientController.php @@ -35,7 +35,9 @@ class ClientController extends ClientApiController */ public function index(GetServersRequest $request): array { - $servers = $this->repository->filterUserAccessServers($request->user(), User::FILTER_LEVEL_SUBUSER, config('pterodactyl.paginate.frontend.servers')); + $servers = $this->repository + ->setSearchTerm($request->input('query')) + ->filterUserAccessServers($request->user(), User::FILTER_LEVEL_ALL); return $this->fractal->collection($servers) ->transformWith($this->getTransformer(ServerTransformer::class)) diff --git a/app/Http/Controllers/Api/Client/Servers/DatabaseController.php b/app/Http/Controllers/Api/Client/Servers/DatabaseController.php new file mode 100644 index 00000000..d440f321 --- /dev/null +++ b/app/Http/Controllers/Api/Client/Servers/DatabaseController.php @@ -0,0 +1,96 @@ +deployDatabaseService = $deployDatabaseService; + $this->repository = $repository; + $this->managementService = $managementService; + } + + /** + * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Databases\GetDatabasesRequest $request + * @return array + */ + public function index(GetDatabasesRequest $request): array + { + $databases = $this->repository->getDatabasesForServer($request->getModel(Server::class)->id); + + return $this->fractal->collection($databases) + ->transformWith($this->getTransformer(DatabaseTransformer::class)) + ->toArray(); + } + + /** + * Create a new database for the given server and return it. + * + * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Databases\StoreDatabaseRequest $request + * @return array + * + * @throws \Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException + */ + public function store(StoreDatabaseRequest $request): array + { + $database = $this->deployDatabaseService->handle($request->getModel(Server::class), $request->validated()); + + return $this->fractal->item($database) + ->parseIncludes(['password']) + ->transformWith($this->getTransformer(DatabaseTransformer::class)) + ->toArray(); + } + + /** + * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Databases\DeleteDatabaseRequest $request + * @return \Illuminate\Http\Response + * + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function delete(DeleteDatabaseRequest $request): Response + { + $this->managementService->delete($request->getModel(Database::class)->id); + + return Response::create('', Response::HTTP_NO_CONTENT); + } +} diff --git a/app/Http/Controllers/Api/Client/Servers/FileController.php b/app/Http/Controllers/Api/Client/Servers/FileController.php new file mode 100644 index 00000000..fd712246 --- /dev/null +++ b/app/Http/Controllers/Api/Client/Servers/FileController.php @@ -0,0 +1,79 @@ +cache = $cache; + $this->fileRepository = $fileRepository; + } + + /** + * Returns a listing of files in a given directory. + * + * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\ListFilesRequest $request + * @return \Illuminate\Http\JsonResponse + */ + public function listDirectory(ListFilesRequest $request): JsonResponse + { + return JsonResponse::create([ + 'contents' => $this->fileRepository->setServer($request->getModel(Server::class))->getDirectory( + $request->get('directory') ?? '/' + ), + ]); + } + + /** + * Configure a reference to a file to download in the cache so that when the + * user hits the Daemon and it verifies with the Panel they'll actually be able + * to download that file. + * + * Returns the token that needs to be used when downloading the file. + * + * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\DownloadFileRequest $request + * @return \Illuminate\Http\JsonResponse + * @throws \Exception + */ + public function download(DownloadFileRequest $request): JsonResponse + { + /** @var \Pterodactyl\Models\Server $server */ + $server = $request->getModel(Server::class); + $token = Uuid::uuid4()->toString(); + + $this->cache->put( + 'Server:Downloads:' . $token, ['server' => $server->uuid, 'path' => $request->route()->parameter('file')], Carbon::now()->addMinutes(5) + ); + + return JsonResponse::create(['token' => $token]); + } +} diff --git a/app/Http/Controllers/Api/Client/Servers/NetworkController.php b/app/Http/Controllers/Api/Client/Servers/NetworkController.php new file mode 100644 index 00000000..e7ecd107 --- /dev/null +++ b/app/Http/Controllers/Api/Client/Servers/NetworkController.php @@ -0,0 +1,49 @@ +repository = $repository; + } + + /** + * Lists all of the allocations available to a server and wether or + * not they are currently assigned as the primary for this server. + * + * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Network\GetNetworkRequest $request + * @return array + */ + public function index(GetNetworkRequest $request): array + { + $server = $request->getModel(Server::class); + + $allocations = $this->repository->findWhere([ + ['server_id', '=', $server->id], + ]); + + return $this->fractal->collection($allocations) + ->transformWith($this->getTransformer(AllocationTransformer::class)) + ->toArray(); + } +} diff --git a/app/Http/Controllers/Auth/AbstractLoginController.php b/app/Http/Controllers/Auth/AbstractLoginController.php new file mode 100644 index 00000000..c99ce85f --- /dev/null +++ b/app/Http/Controllers/Auth/AbstractLoginController.php @@ -0,0 +1,159 @@ +auth = $auth; + $this->cache = $cache; + $this->encrypter = $encrypter; + $this->google2FA = $google2FA; + $this->repository = $repository; + + $this->lockoutTime = config('auth.lockout.time'); + $this->maxLoginAttempts = config('auth.lockout.attempts'); + } + + /** + * Get the failed login response instance. + * + * @param \Illuminate\Http\Request $request + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user + * + * @throws \Pterodactyl\Exceptions\DisplayException + */ + protected function sendFailedLoginResponse(Request $request, Authenticatable $user = null) + { + $this->incrementLoginAttempts($request); + $this->fireFailedLoginEvent($user, [ + $this->getField($request->input('user')) => $request->input('user'), + ]); + + if ($request->route()->named('auth.login-checkpoint')) { + throw new DisplayException(trans('auth.two_factor.checkpoint_failed')); + } + + throw new DisplayException(trans('auth.failed')); + } + + /** + * Send the response after the user was authenticated. + * + * @param \Pterodactyl\Models\User $user + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse + */ + protected function sendLoginResponse(User $user, Request $request): JsonResponse + { + $request->session()->regenerate(); + $this->clearLoginAttempts($request); + + $this->auth->guard()->login($user, true); + + return response()->json([ + 'complete' => true, + 'intended' => $this->redirectPath(), + 'user' => $user->toVueObject(), + ]); + } + + /** + * Determine if the user is logging in using an email or username,. + * + * @param string $input + * @return string + */ + protected function getField(string $input = null): string + { + return str_contains($input, '@') ? 'email' : 'username'; + } + + /** + * Fire a failed login event. + * + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user + * @param array $credentials + */ + protected function fireFailedLoginEvent(Authenticatable $user = null, array $credentials = []) + { + event(new Failed('auth', $user, $credentials)); + } +} diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 896489f9..cb02cfc2 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -3,7 +3,7 @@ namespace Pterodactyl\Http\Controllers\Auth; use Illuminate\Http\Request; -use Illuminate\Http\RedirectResponse; +use Illuminate\Http\JsonResponse; use Illuminate\Support\Facades\Password; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Events\Auth\FailedPasswordReset; @@ -18,9 +18,9 @@ class ForgotPasswordController extends Controller * * @param \Illuminate\Http\Request * @param string $response - * @return \Illuminate\Http\RedirectResponse + * @return \Illuminate\Http\JsonResponse */ - protected function sendResetLinkFailedResponse(Request $request, $response): RedirectResponse + protected function sendResetLinkFailedResponse(Request $request, $response): JsonResponse { // As noted in #358 we will return success even if it failed // to avoid pointing out that an account does or does not @@ -29,4 +29,17 @@ class ForgotPasswordController extends Controller return $this->sendResetLinkResponse($request, Password::RESET_LINK_SENT); } + + /** + * Get the response for a successful password reset link. + * + * @param string $response + * @return \Illuminate\Http\JsonResponse + */ + protected function sendResetLinkResponse($response): JsonResponse + { + return response()->json([ + 'status' => trans($response), + ]); + } } diff --git a/app/Http/Controllers/Auth/LoginCheckpointController.php b/app/Http/Controllers/Auth/LoginCheckpointController.php new file mode 100644 index 00000000..33aa3e4a --- /dev/null +++ b/app/Http/Controllers/Auth/LoginCheckpointController.php @@ -0,0 +1,44 @@ +cache->pull($request->input('confirmation_token'), []); + $user = $this->repository->find(array_get($cache, 'user_id', 0)); + } catch (RecordNotFoundException $exception) { + return $this->sendFailedLoginResponse($request); + } + + if (array_get($cache, 'request_ip') !== $request->ip()) { + return $this->sendFailedLoginResponse($request, $user); + } + + if (! $this->google2FA->verifyKey( + $this->encrypter->decrypt($user->totp_secret), + $request->input('authentication_code'), + config('pterodactyl.auth.2fa.window') + )) { + return $this->sendFailedLoginResponse($request, $user); + } + + return $this->sendLoginResponse($user, $request); + } +} diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index d00b22fa..9707519b 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -3,116 +3,36 @@ namespace Pterodactyl\Http\Controllers\Auth; use Illuminate\Http\Request; -use Illuminate\Auth\AuthManager; -use PragmaRX\Google2FA\Google2FA; -use Illuminate\Auth\Events\Failed; -use Illuminate\Http\RedirectResponse; -use Pterodactyl\Http\Controllers\Controller; -use Illuminate\Contracts\Auth\Authenticatable; -use Illuminate\Contracts\Encryption\Encrypter; -use Illuminate\Foundation\Auth\AuthenticatesUsers; -use Illuminate\Contracts\Cache\Repository as CacheRepository; -use Pterodactyl\Contracts\Repository\UserRepositoryInterface; +use Illuminate\Http\JsonResponse; +use Illuminate\Contracts\View\View; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; -use Illuminate\Contracts\Config\Repository as ConfigRepository; -class LoginController extends Controller +class LoginController extends AbstractLoginController { - use AuthenticatesUsers; - - const USER_INPUT_FIELD = 'user'; - /** - * @var \Illuminate\Auth\AuthManager - */ - private $auth; - - /** - * @var \Illuminate\Contracts\Cache\Repository - */ - private $cache; - - /** - * @var \Illuminate\Contracts\Config\Repository - */ - private $config; - - /** - * @var \Illuminate\Contracts\Encryption\Encrypter - */ - private $encrypter; - - /** - * @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface - */ - private $repository; - - /** - * @var \PragmaRX\Google2FA\Google2FA - */ - private $google2FA; - - /** - * Where to redirect users after login / registration. + * Handle all incoming requests for the authentication routes and render the + * base authentication view component. Vuejs will take over at this point and + * turn the login area into a SPA. * - * @var string + * @return \Illuminate\Contracts\View\View */ - protected $redirectTo = '/'; - - /** - * Lockout time for failed login requests. - * - * @var int - */ - protected $lockoutTime; - - /** - * After how many attempts should logins be throttled and locked. - * - * @var int - */ - protected $maxLoginAttempts; - - /** - * LoginController constructor. - * - * @param \Illuminate\Auth\AuthManager $auth - * @param \Illuminate\Contracts\Cache\Repository $cache - * @param \Illuminate\Contracts\Config\Repository $config - * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter - * @param \PragmaRX\Google2FA\Google2FA $google2FA - * @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository - */ - public function __construct( - AuthManager $auth, - CacheRepository $cache, - ConfigRepository $config, - Encrypter $encrypter, - Google2FA $google2FA, - UserRepositoryInterface $repository - ) { - $this->auth = $auth; - $this->cache = $cache; - $this->config = $config; - $this->encrypter = $encrypter; - $this->google2FA = $google2FA; - $this->repository = $repository; - - $this->lockoutTime = $this->config->get('auth.lockout.time'); - $this->maxLoginAttempts = $this->config->get('auth.lockout.attempts'); + public function index(): View + { + return view('templates/auth.core'); } /** * Handle a login request to the application. * * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response + * @return \Illuminate\Http\JsonResponse * + * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Illuminate\Validation\ValidationException */ - public function login(Request $request) + public function login(Request $request): JsonResponse { - $username = $request->input(self::USER_INPUT_FIELD); + $username = $request->input('user'); $useColumn = $this->getField($username); if ($this->hasTooManyLoginAttempts($request)) { @@ -126,122 +46,29 @@ class LoginController extends Controller return $this->sendFailedLoginResponse($request); } - $validCredentials = password_verify($request->input('password'), $user->password); + // Ensure that the account is using a valid username and password before trying to + // continue. Previously this was handled in the 2FA checkpoint, however that has + // a flaw in which you can discover if an account exists simply by seeing if you + // can proceede to the next step in the login process. + if (! password_verify($request->input('password'), $user->password)) { + return $this->sendFailedLoginResponse($request, $user); + } + + // If the user is using 2FA we do not actually log them in at this step, we return + // a one-time token to link the 2FA credentials to this account via the UI. if ($user->use_totp) { - $token = str_random(64); - $this->cache->put($token, ['user_id' => $user->id, 'valid_credentials' => $validCredentials], 5); + $token = str_random(128); + $this->cache->put($token, [ + 'user_id' => $user->id, + 'request_ip' => $request->ip(), + ], 5); - return redirect()->route('auth.totp')->with('authentication_token', $token); + return response()->json([ + 'complete' => false, + 'login_token' => $token, + ]); } - if ($validCredentials) { - $this->auth->guard()->login($user, true); - - return $this->sendLoginResponse($request); - } - - return $this->sendFailedLoginResponse($request, $user); - } - - /** - * Handle a TOTP implementation page. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View - */ - public function totp(Request $request) - { - $token = $request->session()->get('authentication_token'); - if (is_null($token) || $this->auth->guard()->user()) { - return redirect()->route('auth.login'); - } - - return view('auth.totp', ['verify_key' => $token]); - } - - /** - * Handle a login where the user is required to provide a TOTP authentication - * token. In order to add additional layers of security, users are not - * informed of an incorrect password until this stage, forcing them to - * provide a token on each login attempt. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response - */ - public function loginUsingTotp(Request $request) - { - if (is_null($request->input('verify_token'))) { - return $this->sendFailedLoginResponse($request); - } - - try { - $cache = $this->cache->pull($request->input('verify_token'), []); - $user = $this->repository->find(array_get($cache, 'user_id', 0)); - } catch (RecordNotFoundException $exception) { - return $this->sendFailedLoginResponse($request); - } - - if (is_null($request->input('2fa_token')) || ! array_get($cache, 'valid_credentials')) { - return $this->sendFailedLoginResponse($request, $user); - } - - if (! $this->google2FA->verifyKey( - $this->encrypter->decrypt($user->totp_secret), - $request->input('2fa_token'), - $this->config->get('pterodactyl.auth.2fa.window') - )) { - return $this->sendFailedLoginResponse($request, $user); - } - - $this->auth->guard()->login($user, true); - - return $this->sendLoginResponse($request); - } - - /** - * Get the failed login response instance. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Contracts\Auth\Authenticatable|null $user - * @return \Illuminate\Http\RedirectResponse - */ - protected function sendFailedLoginResponse(Request $request, Authenticatable $user = null): RedirectResponse - { - $this->incrementLoginAttempts($request); - $this->fireFailedLoginEvent($user, [ - $this->getField($request->input(self::USER_INPUT_FIELD)) => $request->input(self::USER_INPUT_FIELD), - ]); - - $errors = [self::USER_INPUT_FIELD => trans('auth.failed')]; - - if ($request->expectsJson()) { - return response()->json($errors, 422); - } - - return redirect()->route('auth.login') - ->withInput($request->only(self::USER_INPUT_FIELD)) - ->withErrors($errors); - } - - /** - * Determine if the user is logging in using an email or username,. - * - * @param string $input - * @return string - */ - private function getField(string $input = null): string - { - return str_contains($input, '@') ? 'email' : 'username'; - } - - /** - * Fire a failed login event. - * - * @param \Illuminate\Contracts\Auth\Authenticatable|null $user - * @param array $credentials - */ - private function fireFailedLoginEvent(Authenticatable $user = null, array $credentials = []) - { - event(new Failed(config('auth.defaults.guard'), $user, $credentials)); + return $this->sendLoginResponse($user, $request); } } diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index f13511d9..22aee3eb 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -3,13 +3,15 @@ namespace Pterodactyl\Http\Controllers\Auth; use Illuminate\Support\Str; -use Illuminate\Http\Request; -use Prologue\Alerts\AlertsMessageBag; +use Illuminate\Http\JsonResponse; use Illuminate\Contracts\Hashing\Hasher; +use Illuminate\Support\Facades\Password; use Illuminate\Auth\Events\PasswordReset; use Illuminate\Contracts\Events\Dispatcher; +use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; use Illuminate\Foundation\Auth\ResetsPasswords; +use Pterodactyl\Http\Requests\Auth\ResetPasswordRequest; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; class ResetPasswordController extends Controller @@ -28,11 +30,6 @@ class ResetPasswordController extends Controller */ protected $hasTwoFactor = false; - /** - * @var \Prologue\Alerts\AlertsMessageBag - */ - private $alerts; - /** * @var \Illuminate\Contracts\Events\Dispatcher */ @@ -51,31 +48,44 @@ class ResetPasswordController extends Controller /** * ResetPasswordController constructor. * - * @param \Prologue\Alerts\AlertsMessageBag $alerts * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher * @param \Illuminate\Contracts\Hashing\Hasher $hasher * @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $userRepository */ - public function __construct(AlertsMessageBag $alerts, Dispatcher $dispatcher, Hasher $hasher, UserRepositoryInterface $userRepository) + public function __construct(Dispatcher $dispatcher, Hasher $hasher, UserRepositoryInterface $userRepository) { - $this->alerts = $alerts; $this->dispatcher = $dispatcher; $this->hasher = $hasher; $this->userRepository = $userRepository; } /** - * Return the rules used when validating password reset. + * Reset the given user's password. * - * @return array + * @param \Pterodactyl\Http\Requests\Auth\ResetPasswordRequest $request + * @return \Illuminate\Http\JsonResponse + * + * @throws \Pterodactyl\Exceptions\DisplayException */ - protected function rules(): array + public function __invoke(ResetPasswordRequest $request): JsonResponse { - return [ - 'token' => 'required', - 'email' => 'required|email', - 'password' => 'required|confirmed|min:8', - ]; + // Here we will attempt to reset the user's password. If it is successful we + // will update the password on an actual user model and persist it to the + // database. Otherwise we will parse the error and return the response. + $response = $this->broker()->reset( + $this->credentials($request), function ($user, $password) { + $this->resetPassword($user, $password); + } + ); + + // If the password was successfully reset, we will redirect the user back to + // the application's home authenticated view. If there is an error we can + // redirect them back to where they came from with their error message. + if ($response === Password::PASSWORD_RESET) { + return $this->sendResetResponse(); + } + + throw new DisplayException(trans($response)); } /** @@ -108,19 +118,16 @@ class ResetPasswordController extends Controller } /** - * Get the response for a successful password reset. + * Send a successful password reset response back to the callee. * - * @param \Illuminate\Http\Request $request - * @param string $response - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse + * @return \Illuminate\Http\JsonResponse */ - protected function sendResetResponse(Request $request, $response) + protected function sendResetResponse(): JsonResponse { - if ($this->hasTwoFactor) { - $this->alerts->success('Your password was successfully updated. Please log in to continue.')->flash(); - } - - return redirect($this->hasTwoFactor ? route('auth.login') : $this->redirectPath()) - ->with('status', trans($response)); + return response()->json([ + 'success' => true, + 'redirect_to' => $this->redirectTo, + 'send_to_login' => $this->hasTwoFactor, + ]); } } diff --git a/app/Http/Controllers/Base/AccountController.php b/app/Http/Controllers/Base/AccountController.php index 80811750..e69de29b 100644 --- a/app/Http/Controllers/Base/AccountController.php +++ b/app/Http/Controllers/Base/AccountController.php @@ -1,91 +0,0 @@ -alert = $alert; - $this->updateService = $updateService; - $this->sessionGuard = $authManager->guard(); - } - - /** - * Display base account information page. - * - * @return \Illuminate\View\View - */ - public function index() - { - return view('base.account', [ - 'languages' => $this->getAvailableLanguages(true), - ]); - } - - /** - * Update details for a user's account. - * - * @param \Pterodactyl\Http\Requests\Base\AccountDataFormRequest $request - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function update(AccountDataFormRequest $request) - { - // Prevent logging this specific session out when the password is changed. This will - // automatically update the user's password anyways, so no need to do anything else here. - if ($request->input('do_action') === 'password') { - $this->sessionGuard->logoutOtherDevices($request->input('new_password')); - } else { - if ($request->input('do_action') === 'email') { - $data = ['email' => $request->input('new_email')]; - } elseif ($request->input('do_action') === 'identity') { - $data = $request->only(['name_first', 'name_last', 'username', 'language']); - } else { - $data = []; - } - - $this->updateService->setUserLevel(User::USER_LEVEL_USER); - $this->updateService->handle($request->user(), $data); - } - - $this->alert->success(trans('base.account.details_updated'))->flash(); - - return redirect()->route('account'); - } -} diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index 20ef370e..625c9b23 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -53,13 +53,13 @@ class IndexController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function getIndex(Request $request) + public function index(Request $request) { $servers = $this->repository->setSearchTerm($request->input('query'))->filterUserAccessServers( $request->user(), User::FILTER_LEVEL_ALL, config('pterodactyl.paginate.frontend.servers') ); - return view('base.index', ['servers' => $servers]); + return view('templates/base.core', ['servers' => $servers]); } /** diff --git a/app/Http/Controllers/Base/SecurityController.php b/app/Http/Controllers/Base/SecurityController.php index 3bb85a0b..8b597141 100644 --- a/app/Http/Controllers/Base/SecurityController.php +++ b/app/Http/Controllers/Base/SecurityController.php @@ -3,6 +3,7 @@ namespace Pterodactyl\Http\Controllers\Base; use Illuminate\Http\Request; +use Illuminate\Http\JsonResponse; use Prologue\Alerts\AlertsMessageBag; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Services\Users\TwoFactorSetupService; @@ -62,36 +63,28 @@ class SecurityController extends Controller } /** - * Returns Security Management Page. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - */ - public function index(Request $request) - { - if ($this->config->get('session.driver') === 'database') { - $activeSessions = $this->repository->getUserSessions($request->user()->id); - } - - return view('base.security', [ - 'sessions' => $activeSessions ?? null, - ]); - } - - /** - * Generates TOTP Secret and returns popup data for user to verify - * that they can generate a valid response. + * Return information about the user's two-factor authentication status. If not enabled setup their + * secret and return information to allow the user to proceede with setup. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse - * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function generateTotp(Request $request) + public function index(Request $request): JsonResponse { - return response()->json([ - 'qrImage' => $this->twoFactorSetupService->handle($request->user()), + if ($request->user()->use_totp) { + return JsonResponse::create([ + 'enabled' => true, + ]); + } + + $response = $this->twoFactorSetupService->handle($request->user()); + + return JsonResponse::create([ + 'enabled' => false, + 'qr_image' => $response->get('image'), + 'secret' => $response->get('secret'), ]); } @@ -99,53 +92,43 @@ class SecurityController extends Controller * Verifies that 2FA token received is valid and will work on the account. * * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response + * @return \Illuminate\Http\JsonResponse * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function setTotp(Request $request) + public function store(Request $request): JsonResponse { try { $this->toggleTwoFactorService->handle($request->user(), $request->input('token') ?? ''); - - return response('true'); } catch (TwoFactorAuthenticationTokenInvalid $exception) { - return response('false'); + $error = true; } + + return JsonResponse::create([ + 'success' => ! isset($error), + ]); } /** * Disables TOTP on an account. * * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\RedirectResponse + * @return \Illuminate\Http\JsonResponse * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function disableTotp(Request $request) + public function delete(Request $request): JsonResponse { try { $this->toggleTwoFactorService->handle($request->user(), $request->input('token') ?? '', false); } catch (TwoFactorAuthenticationTokenInvalid $exception) { - $this->alert->danger(trans('base.security.2fa_disable_error'))->flash(); + $error = true; } - return redirect()->route('account.security'); - } - - /** - * Revokes a user session. - * - * @param \Illuminate\Http\Request $request - * @param string $id - * @return \Illuminate\Http\RedirectResponse - */ - public function revoke(Request $request, string $id) - { - $this->repository->deleteUserSession($request->user()->id, $id); - - return redirect()->route('account.security'); + return JsonResponse::create([ + 'success' => ! isset($error), + ]); } } diff --git a/app/Http/Controllers/Server/ConsoleController.php b/app/Http/Controllers/Server/ConsoleController.php deleted file mode 100644 index 0c195925..00000000 --- a/app/Http/Controllers/Server/ConsoleController.php +++ /dev/null @@ -1,72 +0,0 @@ -config = $config; - } - - /** - * Render server index page with the console and power options. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - */ - public function index(Request $request): View - { - $server = $request->attributes->get('server'); - - $this->setRequest($request)->injectJavascript([ - 'server' => [ - 'cpu' => $server->cpu, - ], - 'meta' => [ - 'saveFile' => route('server.files.save', $server->uuidShort), - 'csrfToken' => csrf_token(), - ], - 'config' => [ - 'console_count' => $this->config->get('pterodactyl.console.count'), - 'console_freq' => $this->config->get('pterodactyl.console.frequency'), - ], - ]); - - return view('server.index'); - } - - /** - * Render a stand-alone console in the browser. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - */ - public function console(Request $request): View - { - $this->setRequest($request)->injectJavascript(['config' => [ - 'console_count' => $this->config->get('pterodactyl.console.count'), - 'console_freq' => $this->config->get('pterodactyl.console.frequency'), - ]]); - - return view('server.console'); - } -} diff --git a/app/Http/Controllers/Server/CredentialsController.php b/app/Http/Controllers/Server/CredentialsController.php new file mode 100644 index 00000000..36e6489e --- /dev/null +++ b/app/Http/Controllers/Server/CredentialsController.php @@ -0,0 +1,48 @@ +keyProviderService = $keyProviderService; + } + + /** + * Return a set of credentials that the currently authenticated user can use to access + * a given server with. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function index(Request $request): JsonResponse + { + /** @var \Pterodactyl\Models\Server $server */ + $server = $request->attributes->get('server'); + $server->loadMissing('node'); + + return JsonResponse::create([ + 'node' => $server->getRelation('node')->getConnectionAddress(), + 'key' => $this->keyProviderService->handle($server, $request->user()), + ]); + } +} diff --git a/app/Http/Controllers/Server/DatabaseController.php b/app/Http/Controllers/Server/DatabaseController.php deleted file mode 100644 index 7d8e4cda..00000000 --- a/app/Http/Controllers/Server/DatabaseController.php +++ /dev/null @@ -1,165 +0,0 @@ -alert = $alert; - $this->databaseHostRepository = $databaseHostRepository; - $this->deployServerDatabaseService = $deployServerDatabaseService; - $this->managementService = $managementService; - $this->passwordService = $passwordService; - $this->repository = $repository; - } - - /** - * Render the database listing for a server. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('view-databases', $server); - $this->setRequest($request)->injectJavascript(); - - $canCreateDatabase = config('pterodactyl.client_features.databases.enabled'); - $allowRandom = config('pterodactyl.client_features.databases.allow_random'); - - if ($this->databaseHostRepository->findCountWhere([['node_id', '=', $server->node_id]]) === 0) { - if ($canCreateDatabase && ! $allowRandom) { - $canCreateDatabase = false; - } - } - - $databases = $this->repository->getDatabasesForServer($server->id); - - return view('server.databases.index', [ - 'allowCreation' => $canCreateDatabase, - 'overLimit' => ! is_null($server->database_limit) && count($databases) >= $server->database_limit, - 'databases' => $databases, - ]); - } - - /** - * Handle a request from a user to create a new database for the server. - * - * @param \Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest $request - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Exception - * @throws \Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException - */ - public function store(StoreServerDatabaseRequest $request): RedirectResponse - { - $this->deployServerDatabaseService->handle($request->getServer(), $request->validated()); - - $this->alert->success('Successfully created a new database.')->flash(); - - return redirect()->route('server.databases.index', $request->getServer()->uuidShort); - } - - /** - * Handle a request to update the password for a specific database. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\JsonResponse - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function update(Request $request): JsonResponse - { - $this->authorize('reset-db-password', $request->attributes->get('server')); - - $password = str_random(24); - $this->passwordService->handle($request->attributes->get('database'), $password); - - return response()->json(['password' => $password]); - } - - /** - * Delete a database for this server from the SQL server and Panel database. - * - * @param \Pterodactyl\Http\Requests\Server\Database\DeleteServerDatabaseRequest $request - * @return \Illuminate\Http\Response - * - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function delete(DeleteServerDatabaseRequest $request): Response - { - $this->managementService->delete($request->attributes->get('database')->id); - - return response('', Response::HTTP_NO_CONTENT); - } -} diff --git a/app/Http/Controllers/Server/FileController.php b/app/Http/Controllers/Server/FileController.php new file mode 100644 index 00000000..23bba17e --- /dev/null +++ b/app/Http/Controllers/Server/FileController.php @@ -0,0 +1,57 @@ +fileRepository = $fileRepository; + } + + /** + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse + * + * @throws \Illuminate\Auth\Access\AuthorizationException + * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException + */ + public function index(Request $request): JsonResponse + { + $server = $request->attributes->get('server'); + $this->authorize('list-files', $server); + + $requestDirectory = '/' . trim(urldecode($request->route()->parameter('directory', '/')), '/'); + + try { + $contents = $this->fileRepository->setServer($server)->setToken( + $request->attributes->get('server_token') + )->getDirectory($requestDirectory); + } catch (TransferException $exception) { + throw new DaemonConnectionException($exception, true); + } + + return JsonResponse::create([ + 'contents' => $contents, + 'editable' => config('pterodactyl.files.editable'), + 'current_directory' => $requestDirectory, + ]); + } +} diff --git a/app/Http/Controllers/Server/Files/DownloadController.php b/app/Http/Controllers/Server/Files/DownloadController.php deleted file mode 100644 index 04b16d08..00000000 --- a/app/Http/Controllers/Server/Files/DownloadController.php +++ /dev/null @@ -1,57 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Pterodactyl\Http\Controllers\Server\Files; - -use Ramsey\Uuid\Uuid; -use Illuminate\Http\Request; -use Illuminate\Cache\Repository; -use Illuminate\Http\RedirectResponse; -use Pterodactyl\Http\Controllers\Controller; - -class DownloadController extends Controller -{ - /** - * @var \Illuminate\Cache\Repository - */ - protected $cache; - - /** - * DownloadController constructor. - * - * @param \Illuminate\Cache\Repository $cache - */ - public function __construct(Repository $cache) - { - $this->cache = $cache; - } - - /** - * Setup a unique download link for a user to download a file from. - * - * @param \Illuminate\Http\Request $request - * @param string $uuid - * @param string $file - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Request $request, string $uuid, string $file): RedirectResponse - { - $server = $request->attributes->get('server'); - $this->authorize('download-files', $server); - - $token = Uuid::uuid4()->toString(); - $node = $server->getRelation('node'); - - $this->cache->put('Server:Downloads:' . $token, ['server' => $server->uuid, 'path' => $file], 5); - - return redirect(sprintf('%s://%s:%s/v1/server/file/download/%s', $node->scheme, $node->fqdn, $node->daemonListen, $token)); - } -} diff --git a/app/Http/Controllers/Server/Files/FileActionsController.php b/app/Http/Controllers/Server/Files/FileActionsController.php deleted file mode 100644 index bd63009a..00000000 --- a/app/Http/Controllers/Server/Files/FileActionsController.php +++ /dev/null @@ -1,120 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Pterodactyl\Http\Controllers\Server\Files; - -use Illuminate\View\View; -use Illuminate\Http\Request; -use GuzzleHttp\Exception\RequestException; -use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Traits\Controllers\JavascriptInjection; -use Pterodactyl\Http\Requests\Server\UpdateFileContentsFormRequest; -use Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface; -use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; - -class FileActionsController extends Controller -{ - use JavascriptInjection; - - /** - * @var \Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface - */ - protected $repository; - - /** - * FileActionsController constructor. - * - * @param \Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface $repository - */ - public function __construct(FileRepositoryInterface $repository) - { - $this->repository = $repository; - } - - /** - * Display server file index list. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('list-files', $server); - - $this->setRequest($request)->injectJavascript([ - 'meta' => [ - 'directoryList' => route('server.files.directory-list', $server->uuidShort), - 'csrftoken' => csrf_token(), - ], - 'permissions' => [ - 'moveFiles' => $request->user()->can('move-files', $server), - 'copyFiles' => $request->user()->can('copy-files', $server), - 'compressFiles' => $request->user()->can('compress-files', $server), - 'decompressFiles' => $request->user()->can('decompress-files', $server), - 'createFiles' => $request->user()->can('create-files', $server), - 'downloadFiles' => $request->user()->can('download-files', $server), - 'deleteFiles' => $request->user()->can('delete-files', $server), - ], - ]); - - return view('server.files.index'); - } - - /** - * Render page to manually create a file in the panel. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function create(Request $request): View - { - $this->authorize('create-files', $request->attributes->get('server')); - $this->setRequest($request)->injectJavascript(); - - return view('server.files.add', [ - 'directory' => (in_array($request->get('dir'), [null, '/', ''])) ? '' : trim($request->get('dir'), '/') . '/', - ]); - } - - /** - * Display a form to allow for editing of a file. - * - * @param \Pterodactyl\Http\Requests\Server\UpdateFileContentsFormRequest $request - * @param string $uuid - * @param string $file - * @return \Illuminate\View\View - * - * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException - */ - public function view(UpdateFileContentsFormRequest $request, string $uuid, string $file): View - { - $server = $request->attributes->get('server'); - - $dirname = str_replace('\\', '/', pathinfo($file, PATHINFO_DIRNAME)); - try { - $content = $this->repository->setServer($server)->setToken($request->attributes->get('server_token'))->getContent($file); - } catch (RequestException $exception) { - throw new DaemonConnectionException($exception); - } - - $this->setRequest($request)->injectJavascript(['stat' => $request->attributes->get('file_stats')]); - - return view('server.files.edit', [ - 'file' => $file, - 'stat' => $request->attributes->get('file_stats'), - 'contents' => $content, - 'directory' => (in_array($dirname, ['.', './', '/'])) ? '/' : trim($dirname, '/') . '/', - ]); - } -} diff --git a/app/Http/Controllers/Server/Files/RemoteRequestController.php b/app/Http/Controllers/Server/Files/RemoteRequestController.php deleted file mode 100644 index ab58037d..00000000 --- a/app/Http/Controllers/Server/Files/RemoteRequestController.php +++ /dev/null @@ -1,105 +0,0 @@ -config = $config; - $this->repository = $repository; - } - - /** - * Return a listing of a servers file directory. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function directory(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('list-files', $server); - - $requestDirectory = '/' . trim(urldecode($request->input('directory', '/')), '/'); - $directory = [ - 'header' => $requestDirectory !== '/' ? $requestDirectory : '', - 'first' => $requestDirectory !== '/', - ]; - - $goBack = explode('/', trim($requestDirectory, '/')); - if (! empty(array_filter($goBack)) && count($goBack) >= 2) { - array_pop($goBack); - - $directory['show'] = true; - $directory['link'] = '/' . implode('/', $goBack); - $directory['link_show'] = implode('/', $goBack) . '/'; - } - - try { - $listing = $this->repository->setServer($server)->setToken($request->attributes->get('server_token'))->getDirectory($requestDirectory); - } catch (RequestException $exception) { - throw new DaemonConnectionException($exception, true); - } - - return view('server.files.list', [ - 'files' => $listing['files'], - 'folders' => $listing['folders'], - 'editableMime' => $this->config->get('pterodactyl.files.editable'), - 'directory' => $directory, - ]); - } - - /** - * Put the contents of a file onto the daemon. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException - */ - public function store(Request $request): Response - { - $server = $request->attributes->get('server'); - $this->authorize('save-files', $server); - - try { - $this->repository->setServer($server)->setToken($request->attributes->get('server_token')) - ->putContent($request->input('file'), $request->input('contents') ?? ''); - - return response('', 204); - } catch (RequestException $exception) { - throw new DaemonConnectionException($exception); - } - } -} diff --git a/app/Http/Controllers/Server/Settings/AllocationController.php b/app/Http/Controllers/Server/Settings/AllocationController.php deleted file mode 100644 index 21baf7c0..00000000 --- a/app/Http/Controllers/Server/Settings/AllocationController.php +++ /dev/null @@ -1,96 +0,0 @@ -defaultAllocationService = $defaultAllocationService; - $this->hashids = $hashids; - $this->repository = $repository; - } - - /** - * Render the allocation management overview page for a server. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('view-allocations', $server); - $this->setRequest($request)->injectJavascript(); - - return view('server.settings.allocation', [ - 'allocations' => $this->repository->findWhere([['server_id', '=', $server->id]]), - ]); - } - - /** - * Update the default allocation for a server. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\JsonResponse - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function update(Request $request): JsonResponse - { - $server = $request->attributes->get('server'); - $this->authorize('edit-allocation', $server); - - $allocation = $this->hashids->decodeFirst($request->input('allocation'), 0); - - try { - $this->defaultAllocationService->handle($server->id, $allocation); - } catch (AllocationDoesNotBelongToServerException $exception) { - return response()->json(['error' => 'No matching allocation was located for this server.'], 404); - } - - return response()->json(); - } -} diff --git a/app/Http/Controllers/Server/Settings/NameController.php b/app/Http/Controllers/Server/Settings/NameController.php deleted file mode 100644 index 29cdb9ed..00000000 --- a/app/Http/Controllers/Server/Settings/NameController.php +++ /dev/null @@ -1,59 +0,0 @@ -repository = $repository; - } - - /** - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Request $request) - { - $this->authorize('view-name', $request->attributes->get('server')); - $this->setRequest($request)->injectJavascript(); - - return view('server.settings.name'); - } - - /** - * Update the stored name for a specific server. - * - * @param \Pterodactyl\Http\Requests\Server\Settings\ChangeServerNameRequest $request - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function update(ChangeServerNameRequest $request): RedirectResponse - { - $this->repository->update($request->getServer()->id, $request->validated()); - - return redirect()->route('server.settings.name', $request->getServer()->uuidShort); - } -} diff --git a/app/Http/Controllers/Server/Settings/SftpController.php b/app/Http/Controllers/Server/Settings/SftpController.php deleted file mode 100644 index 58b110bd..00000000 --- a/app/Http/Controllers/Server/Settings/SftpController.php +++ /dev/null @@ -1,29 +0,0 @@ -authorize('access-sftp', $request->attributes->get('server')); - $this->setRequest($request)->injectJavascript(); - - return view('server.settings.sftp'); - } -} diff --git a/app/Http/Controllers/Server/Settings/StartupController.php b/app/Http/Controllers/Server/Settings/StartupController.php deleted file mode 100644 index 8f17022b..00000000 --- a/app/Http/Controllers/Server/Settings/StartupController.php +++ /dev/null @@ -1,96 +0,0 @@ -alert = $alert; - $this->commandViewService = $commandViewService; - $this->modificationService = $modificationService; - } - - /** - * Render the server startup page. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function index(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('view-startup', $server); - $this->setRequest($request)->injectJavascript(); - - $data = $this->commandViewService->handle($server->id); - - return view('server.settings.startup', [ - 'variables' => $data->get('variables'), - 'server_values' => $data->get('server_values'), - 'startup' => $data->get('startup'), - ]); - } - - /** - * Handle request to update the startup variables for a server. Authorization - * is handled in the form request. - * - * @param \Pterodactyl\Http\Requests\Server\UpdateStartupParametersFormRequest $request - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Pterodactyl\Exceptions\DisplayException - * @throws \Illuminate\Validation\ValidationException - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function update(UpdateStartupParametersFormRequest $request): RedirectResponse - { - $this->modificationService->setUserLevel(User::USER_LEVEL_USER); - $this->modificationService->handle($request->attributes->get('server'), $request->normalize()); - $this->alert->success(trans('server.config.startup.edited'))->flash(); - - return redirect()->route('server.settings.startup', ['server' => $request->attributes->get('server')->uuidShort]); - } -} diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php deleted file mode 100644 index 008cfeaa..00000000 --- a/app/Http/Controllers/Server/SubuserController.php +++ /dev/null @@ -1,197 +0,0 @@ -alert = $alert; - $this->repository = $repository; - $this->subuserCreationService = $subuserCreationService; - $this->subuserDeletionService = $subuserDeletionService; - $this->subuserUpdateService = $subuserUpdateService; - } - - /** - * Displays the subuser overview index. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('list-subusers', $server); - $this->setRequest($request)->injectJavascript(); - - return view('server.users.index', [ - 'subusers' => $this->repository->findWhere([['server_id', '=', $server->id]]), - ]); - } - - /** - * Displays a single subuser overview. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function view(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('view-subuser', $server); - - $subuser = $this->repository->getWithPermissions($request->attributes->get('subuser')); - $this->setRequest($request)->injectJavascript(); - - return view('server.users.view', [ - 'subuser' => $subuser, - 'permlist' => Permission::getPermissions(), - 'permissions' => $subuser->getRelation('permissions')->mapWithKeys(function ($item) { - return [$item->permission => true]; - }), - ]); - } - - /** - * Handles editing a subuser. - * - * @param \Pterodactyl\Http\Requests\Server\Subuser\SubuserUpdateFormRequest $request - * @param string $uuid - * @param string $hash - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\DisplayException - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function update(SubuserUpdateFormRequest $request, string $uuid, string $hash): RedirectResponse - { - $this->subuserUpdateService->handle($request->attributes->get('subuser'), $request->input('permissions', [])); - $this->alert->success(trans('server.users.user_updated'))->flash(); - - return redirect()->route('server.subusers.view', ['uuid' => $uuid, 'subuser' => $hash]); - } - - /** - * Display new subuser creation page. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function create(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('create-subuser', $server); - $this->setRequest($request)->injectJavascript(); - - return view('server.users.new', ['permissions' => Permission::getPermissions()]); - } - - /** - * Handles creating a new subuser. - * - * @param \Pterodactyl\Http\Requests\Server\Subuser\SubuserStoreFormRequest $request - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Exception - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - * @throws \Pterodactyl\Exceptions\Service\Subuser\ServerSubuserExistsException - * @throws \Pterodactyl\Exceptions\Service\Subuser\UserIsServerOwnerException - */ - public function store(SubuserStoreFormRequest $request): RedirectResponse - { - $server = $request->attributes->get('server'); - - $subuser = $this->subuserCreationService->handle($server, $request->input('email'), $request->input('permissions', [])); - $this->alert->success(trans('server.users.user_assigned'))->flash(); - - return redirect()->route('server.subusers.view', [ - 'uuid' => $server->uuidShort, - 'id' => $subuser->hashid, - ]); - } - - /** - * Handles deleting a subuser. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\DisplayException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function delete(Request $request): Response - { - $server = $request->attributes->get('server'); - $this->authorize('delete-subuser', $server); - - $this->subuserDeletionService->handle($request->attributes->get('subuser')); - - return response('', 204); - } -} diff --git a/app/Http/Controllers/Server/Tasks/ActionController.php b/app/Http/Controllers/Server/Tasks/ActionController.php index 498db853..e69de29b 100644 --- a/app/Http/Controllers/Server/Tasks/ActionController.php +++ b/app/Http/Controllers/Server/Tasks/ActionController.php @@ -1,79 +0,0 @@ -processScheduleService = $processScheduleService; - $this->repository = $repository; - } - - /** - * Toggle a task to be active or inactive for a given server. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function toggle(Request $request): Response - { - $server = $request->attributes->get('server'); - $schedule = $request->attributes->get('schedule'); - $this->authorize('toggle-schedule', $server); - - $this->repository->update($schedule->id, [ - 'is_active' => ! $schedule->is_active, - ]); - - return response('', 204); - } - - /** - * Trigger a schedule to run now. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * - * @throws \Illuminate\Auth\Access\AuthorizationException - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function trigger(Request $request): Response - { - $server = $request->attributes->get('server'); - $this->authorize('toggle-schedule', $server); - - $this->processScheduleService->handle( - $request->attributes->get('schedule') - ); - - return response('', 204); - } -} diff --git a/app/Http/Controllers/Server/Tasks/TaskManagementController.php b/app/Http/Controllers/Server/Tasks/TaskManagementController.php deleted file mode 100644 index 9805b5cf..00000000 --- a/app/Http/Controllers/Server/Tasks/TaskManagementController.php +++ /dev/null @@ -1,198 +0,0 @@ -alert = $alert; - $this->creationService = $creationService; - $this->hashids = $hashids; - $this->repository = $repository; - $this->updateService = $updateService; - } - - /** - * Display the task page listing. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('list-schedules', $server); - $this->setRequest($request)->injectJavascript(); - - return view('server.schedules.index', [ - 'schedules' => $this->repository->findServerSchedules($server->id), - 'actions' => [ - 'command' => trans('server.schedule.actions.command'), - 'power' => trans('server.schedule.actions.power'), - ], - ]); - } - - /** - * Display the task creation page. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function create(Request $request): View - { - $server = $request->attributes->get('server'); - $this->authorize('create-schedule', $server); - $this->setRequest($request)->injectJavascript(); - - return view('server.schedules.new'); - } - - /** - * Handle request to store a new schedule and tasks in the database. - * - * @param \Pterodactyl\Http\Requests\Server\ScheduleCreationFormRequest $request - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Service\Schedule\Task\TaskIntervalTooLongException - */ - public function store(ScheduleCreationFormRequest $request): RedirectResponse - { - $server = $request->attributes->get('server'); - - $schedule = $this->creationService->handle($server, $request->normalize(), $request->getTasks()); - $this->alert->success(trans('server.schedule.schedule_created'))->flash(); - - return redirect()->route('server.schedules.view', [ - 'server' => $server->uuidShort, - 'schedule' => $schedule->hashid, - ]); - } - - /** - * Return a view to modify a schedule. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\View - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function view(Request $request): View - { - $server = $request->attributes->get('server'); - $schedule = $request->attributes->get('schedule'); - $this->authorize('view-schedule', $server); - - $this->setRequest($request)->injectJavascript([ - 'tasks' => $schedule->getRelation('tasks')->map(function ($task) { - /* @var \Pterodactyl\Models\Task $task */ - return collect($task->toArray())->only('action', 'time_offset', 'payload')->all(); - }), - ]); - - return view('server.schedules.view', ['schedule' => $schedule]); - } - - /** - * Update a specific parent task on the system. - * - * @param \Pterodactyl\Http\Requests\Server\ScheduleCreationFormRequest $request - * @return \Illuminate\Http\RedirectResponse - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - * @throws \Pterodactyl\Exceptions\Service\Schedule\Task\TaskIntervalTooLongException - */ - public function update(ScheduleCreationFormRequest $request): RedirectResponse - { - $server = $request->attributes->get('server'); - $schedule = $request->attributes->get('schedule'); - - $this->updateService->handle($schedule, $request->normalize(), $request->getTasks()); - $this->alert->success(trans('server.schedule.schedule_updated'))->flash(); - - return redirect()->route('server.schedules.view', [ - 'server' => $server->uuidShort, - 'schedule' => $schedule->hashid, - ]); - } - - /** - * Delete a parent task from the Panel. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function delete(Request $request): Response - { - $server = $request->attributes->get('server'); - $schedule = $request->attributes->get('schedule'); - $this->authorize('delete-schedule', $server); - - $this->repository->delete($schedule->id); - - return response('', 204); - } -} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 85c1190e..e1e7f008 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -49,6 +49,7 @@ class Kernel extends HttpKernel */ protected $middleware = [ CheckForMaintenanceMode::class, + EncryptCookies::class, ValidatePostSize::class, TrimStrings::class, ConvertEmptyStringsToNull::class, @@ -62,7 +63,6 @@ class Kernel extends HttpKernel */ protected $middlewareGroups = [ 'web' => [ - EncryptCookies::class, AddQueuedCookiesToResponse::class, StartSession::class, AuthenticateSession::class, @@ -73,7 +73,7 @@ class Kernel extends HttpKernel RequireTwoFactorAuthentication::class, ], 'api' => [ - 'throttle:120,1', + 'throttle:240,1', ApiSubstituteBindings::class, SetSessionDriver::class, 'api..key:' . ApiKey::TYPE_APPLICATION, @@ -81,9 +81,11 @@ class Kernel extends HttpKernel AuthenticateIPAccess::class, ], 'client-api' => [ - 'throttle:60,1', - SubstituteClientApiBindings::class, + 'throttle:240,1', + StartSession::class, SetSessionDriver::class, + AuthenticateSession::class, + SubstituteClientApiBindings::class, 'api..key:' . ApiKey::TYPE_ACCOUNT, AuthenticateIPAccess::class, ], diff --git a/app/Http/Middleware/Api/AuthenticateKey.php b/app/Http/Middleware/Api/AuthenticateKey.php index 8f400bb4..429c26f9 100644 --- a/app/Http/Middleware/Api/AuthenticateKey.php +++ b/app/Http/Middleware/Api/AuthenticateKey.php @@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Middleware\Api; use Closure; use Cake\Chronos\Chronos; use Illuminate\Http\Request; +use Pterodactyl\Models\User; use Pterodactyl\Models\ApiKey; use Illuminate\Auth\AuthManager; use Illuminate\Contracts\Encryption\Encrypter; @@ -58,13 +59,43 @@ class AuthenticateKey */ public function handle(Request $request, Closure $next, int $keyType) { - if (is_null($request->bearerToken())) { + if (is_null($request->bearerToken()) && is_null($request->user())) { throw new HttpException(401, null, null, ['WWW-Authenticate' => 'Bearer']); } $raw = $request->bearerToken(); - $identifier = substr($raw, 0, ApiKey::IDENTIFIER_LENGTH); - $token = substr($raw, ApiKey::IDENTIFIER_LENGTH); + + // This is a request coming through using cookies, we have an authenticated user not using + // an API key. Make some fake API key models and continue on through the process. + if (empty($raw) && $request->user() instanceof User) { + $model = (new ApiKey())->forceFill([ + 'user_id' => $request->user()->id, + 'key_type' => ApiKey::TYPE_ACCOUNT, + ]); + } else { + $model = $this->authenticateApiKey($raw, $keyType); + $this->auth->guard()->loginUsingId($model->user_id); + } + + $request->attributes->set('api_key', $model); + + return $next($request); + } + + /** + * Authenticate an API key. + * + * @param string $key + * @param int $keyType + * @return \Pterodactyl\Models\ApiKey + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + protected function authenticateApiKey(string $key, int $keyType): ApiKey + { + $identifier = substr($key, 0, ApiKey::IDENTIFIER_LENGTH); + $token = substr($key, ApiKey::IDENTIFIER_LENGTH); try { $model = $this->repository->findFirstWhere([ @@ -79,10 +110,8 @@ class AuthenticateKey throw new AccessDeniedHttpException; } - $this->auth->guard()->loginUsingId($model->user_id); - $request->attributes->set('api_key', $model); $this->repository->withoutFreshModel()->update($model->id, ['last_used_at' => Chronos::now()]); - return $next($request); + return $model; } } diff --git a/app/Http/Middleware/Api/Client/AuthenticateClientAccess.php b/app/Http/Middleware/Api/Client/AuthenticateClientAccess.php deleted file mode 100644 index e048b586..00000000 --- a/app/Http/Middleware/Api/Client/AuthenticateClientAccess.php +++ /dev/null @@ -1,60 +0,0 @@ -keyProviderService = $keyProviderService; - } - - /** - * Authenticate that the currently authenticated user has permission - * to access the specified server. This only checks that the user is an - * admin, owner, or a subuser. You'll need to do more specific checks in - * the API calls to determine if they can perform different actions. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - */ - public function handle(Request $request, Closure $next) - { - if (is_null($request->user())) { - throw new AccessDeniedHttpException('A request must be made using an authenticated client.'); - } - - /** @var \Pterodactyl\Models\Server $server */ - $server = $request->route()->parameter('server'); - - try { - $token = $this->keyProviderService->handle($server, $request->user()); - } catch (RecordNotFoundException $exception) { - throw new NotFoundHttpException('The requested server could not be located.'); - } - - $request->attributes->set('server_token', $token); - - return $next($request); - } -} diff --git a/app/Http/Middleware/Api/Client/Server/AuthenticateServerAccess.php b/app/Http/Middleware/Api/Client/Server/AuthenticateServerAccess.php new file mode 100644 index 00000000..e42417f6 --- /dev/null +++ b/app/Http/Middleware/Api/Client/Server/AuthenticateServerAccess.php @@ -0,0 +1,57 @@ +repository = $repository; + } + + /** + * Authenticate that this server exists and is not suspended or marked as installing. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle(Request $request, Closure $next) + { + $server = $request->route()->parameter('server'); + + if (! $server instanceof Server) { + throw new NotFoundHttpException; + } + + if ($server->suspended) { + throw new AccessDeniedHttpException('Cannot access a server that is marked as being suspended.'); + } + + if (! $server->isInstalled()) { + throw new ConflictHttpException('Server has not completed the installation process.'); + } + + $request->attributes->set('server', $server); + + return $next($request); + } +} diff --git a/app/Http/Middleware/Api/Client/SubstituteClientApiBindings.php b/app/Http/Middleware/Api/Client/SubstituteClientApiBindings.php index f8a35fdd..885187e3 100644 --- a/app/Http/Middleware/Api/Client/SubstituteClientApiBindings.php +++ b/app/Http/Middleware/Api/Client/SubstituteClientApiBindings.php @@ -4,9 +4,11 @@ namespace Pterodactyl\Http\Middleware\Api\Client; use Closure; use Illuminate\Container\Container; +use Pterodactyl\Contracts\Extensions\HashidsInterface; use Pterodactyl\Http\Middleware\Api\ApiSubstituteBindings; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; +use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; class SubstituteClientApiBindings extends ApiSubstituteBindings { @@ -34,6 +36,20 @@ class SubstituteClientApiBindings extends ApiSubstituteBindings } }); + $this->router->bind('database', function ($value) use ($request) { + try { + $id = Container::getInstance()->make(HashidsInterface::class)->decodeFirst($value); + + return Container::getInstance()->make(DatabaseRepositoryInterface::class)->findFirstWhere([ + ['id', '=', $id], + ]); + } catch (RecordNotFoundException $exception) { + $request->attributes->set('is_missing_model', true); + + return null; + } + }); + return parent::handle($request, $next); } } diff --git a/app/Http/Middleware/Api/SetSessionDriver.php b/app/Http/Middleware/Api/SetSessionDriver.php index 3d5c1661..8ce50a8b 100644 --- a/app/Http/Middleware/Api/SetSessionDriver.php +++ b/app/Http/Middleware/Api/SetSessionDriver.php @@ -4,17 +4,10 @@ namespace Pterodactyl\Http\Middleware\Api; use Closure; use Illuminate\Http\Request; -use Barryvdh\Debugbar\LaravelDebugbar; -use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Config\Repository as ConfigRepository; class SetSessionDriver { - /** - * @var \Illuminate\Contracts\Foundation\Application - */ - private $app; - /** * @var \Illuminate\Contracts\Config\Repository */ @@ -23,12 +16,10 @@ class SetSessionDriver /** * SetSessionDriver constructor. * - * @param \Illuminate\Contracts\Foundation\Application $app - * @param \Illuminate\Contracts\Config\Repository $config + * @param \Illuminate\Contracts\Config\Repository $config */ - public function __construct(Application $app, ConfigRepository $config) + public function __construct(ConfigRepository $config) { - $this->app = $app; $this->config = $config; } @@ -41,10 +32,6 @@ class SetSessionDriver */ public function handle(Request $request, Closure $next) { - if ($this->config->get('app.debug')) { - $this->app->make(LaravelDebugbar::class)->disable(); - } - $this->config->set('session.driver', 'array'); return $next($request); diff --git a/app/Http/Middleware/RequireTwoFactorAuthentication.php b/app/Http/Middleware/RequireTwoFactorAuthentication.php index aee1cf06..486b8e3c 100644 --- a/app/Http/Middleware/RequireTwoFactorAuthentication.php +++ b/app/Http/Middleware/RequireTwoFactorAuthentication.php @@ -10,6 +10,7 @@ namespace Pterodactyl\Http\Middleware; use Closure; +use Illuminate\Support\Str; use Illuminate\Http\Request; use Prologue\Alerts\AlertsMessageBag; @@ -24,27 +25,12 @@ class RequireTwoFactorAuthentication */ private $alert; - /** - * The names of routes that should be accessible without 2FA enabled. - * - * @var array - */ - protected $except = [ - 'account.security', - 'account.security.revoke', - 'account.security.totp', - 'account.security.totp.set', - 'account.security.totp.disable', - 'auth.totp', - 'auth.logout', - ]; - /** * The route to redirect a user to to enable 2FA. * * @var string */ - protected $redirectRoute = 'account.security'; + protected $redirectRoute = 'account'; /** * RequireTwoFactorAuthentication constructor. @@ -69,7 +55,8 @@ class RequireTwoFactorAuthentication return $next($request); } - if (in_array($request->route()->getName(), $this->except)) { + $current = $request->route()->getName(); + if (in_array($current, ['auth', 'account']) || Str::startsWith($current, ['auth.', 'account.'])) { return $next($request); } diff --git a/app/Http/Middleware/Server/AccessingValidServer.php b/app/Http/Middleware/Server/AccessingValidServer.php index ea29e0b9..894dcaa1 100644 --- a/app/Http/Middleware/Server/AccessingValidServer.php +++ b/app/Http/Middleware/Server/AccessingValidServer.php @@ -5,7 +5,6 @@ namespace Pterodactyl\Http\Middleware\Server; use Closure; use Illuminate\Http\Request; use Pterodactyl\Models\Server; -use Illuminate\Contracts\Session\Session; use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Contracts\Config\Repository as ConfigRepository; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; @@ -29,29 +28,21 @@ class AccessingValidServer */ private $response; - /** - * @var \Illuminate\Contracts\Session\Session - */ - private $session; - /** * AccessingValidServer constructor. * * @param \Illuminate\Contracts\Config\Repository $config * @param \Illuminate\Contracts\Routing\ResponseFactory $response * @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository - * @param \Illuminate\Contracts\Session\Session $session */ public function __construct( ConfigRepository $config, ResponseFactory $response, - ServerRepositoryInterface $repository, - Session $session + ServerRepositoryInterface $repository ) { $this->config = $config; $this->repository = $repository; $this->response = $response; - $this->session = $session; } /** @@ -61,7 +52,6 @@ class AccessingValidServer * @param \Closure $next * @return \Illuminate\Http\Response|mixed * - * @throws \Illuminate\Auth\AuthenticationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException @@ -90,10 +80,6 @@ class AccessingValidServer return $this->response->view('errors.installing', [], 409); } - // Store the server in the session. - // @todo remove from session. use request attributes. - $this->session->now('server_data.model', $server); - // Add server to the request attributes. This will replace sessions // as files are updated. $request->attributes->set('server', $server); diff --git a/app/Http/Requests/Api/Application/ApplicationApiRequest.php b/app/Http/Requests/Api/Application/ApplicationApiRequest.php index ca5f40dd..2471a8fd 100644 --- a/app/Http/Requests/Api/Application/ApplicationApiRequest.php +++ b/app/Http/Requests/Api/Application/ApplicationApiRequest.php @@ -126,10 +126,6 @@ abstract class ApplicationApiRequest extends FormRequest * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ - - /** - * @return bool - */ protected function passesAuthorization() { // If we have already validated we do not need to call this function diff --git a/app/Http/Requests/Api/Client/Account/UpdateEmailRequest.php b/app/Http/Requests/Api/Client/Account/UpdateEmailRequest.php new file mode 100644 index 00000000..a990e79b --- /dev/null +++ b/app/Http/Requests/Api/Client/Account/UpdateEmailRequest.php @@ -0,0 +1,39 @@ +input('password'), $this->user()->password)) { + throw new InvalidPasswordProvidedException(trans('validation.internal.invalid_password')); + } + + return true; + } + + /** + * @return array + */ + public function rules(): array + { + $rules = User::getUpdateRulesForId($this->user()->id); + + return ['email' => $rules['email']]; + } +} diff --git a/app/Http/Requests/Api/Client/Account/UpdatePasswordRequest.php b/app/Http/Requests/Api/Client/Account/UpdatePasswordRequest.php new file mode 100644 index 00000000..12079f68 --- /dev/null +++ b/app/Http/Requests/Api/Client/Account/UpdatePasswordRequest.php @@ -0,0 +1,39 @@ +input('current_password'), $this->user()->password)) { + throw new InvalidPasswordProvidedException(trans('validation.internal.invalid_password')); + } + + return true; + } + + /** + * @return array + */ + public function rules(): array + { + $rules = User::getUpdateRulesForId($this->user()->id); + + return ['password' => array_merge($rules['password'], ['confirmed'])]; + } +} diff --git a/app/Http/Requests/Api/Client/ClientApiRequest.php b/app/Http/Requests/Api/Client/ClientApiRequest.php index 92402e51..468b294f 100644 --- a/app/Http/Requests/Api/Client/ClientApiRequest.php +++ b/app/Http/Requests/Api/Client/ClientApiRequest.php @@ -2,18 +2,23 @@ namespace Pterodactyl\Http\Requests\Api\Client; +use Pterodactyl\Models\Server; +use Pterodactyl\Contracts\Http\ClientPermissionsRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; abstract class ClientApiRequest extends ApplicationApiRequest { /** - * Determine if the current user is authorized to perform - * the requested action against the API. + * Determine if the current user is authorized to perform the requested action against the API. * * @return bool */ public function authorize(): bool { + if ($this instanceof ClientPermissionsRequest || method_exists($this, 'permission')) { + return $this->user()->can($this->permission(), $this->getModel(Server::class)); + } + return true; } } diff --git a/app/Http/Requests/Api/Client/Servers/Databases/DeleteDatabaseRequest.php b/app/Http/Requests/Api/Client/Servers/Databases/DeleteDatabaseRequest.php new file mode 100644 index 00000000..b43dd0d5 --- /dev/null +++ b/app/Http/Requests/Api/Client/Servers/Databases/DeleteDatabaseRequest.php @@ -0,0 +1,27 @@ +getModel(Server::class)->id === $this->getModel(Database::class)->server_id; + } +} diff --git a/app/Http/Requests/Api/Client/Servers/Databases/GetDatabasesRequest.php b/app/Http/Requests/Api/Client/Servers/Databases/GetDatabasesRequest.php new file mode 100644 index 00000000..0e90d80b --- /dev/null +++ b/app/Http/Requests/Api/Client/Servers/Databases/GetDatabasesRequest.php @@ -0,0 +1,17 @@ + 'required|alpha_dash|min:1|max:100', + 'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/', + ]; + } +} diff --git a/app/Http/Requests/Api/Client/Servers/Files/DownloadFileRequest.php b/app/Http/Requests/Api/Client/Servers/Files/DownloadFileRequest.php new file mode 100644 index 00000000..a67a6efb --- /dev/null +++ b/app/Http/Requests/Api/Client/Servers/Files/DownloadFileRequest.php @@ -0,0 +1,20 @@ +user()->can('download-files', $this->getModel(Server::class)); + } +} diff --git a/app/Http/Requests/Api/Client/Servers/Files/ListFilesRequest.php b/app/Http/Requests/Api/Client/Servers/Files/ListFilesRequest.php new file mode 100644 index 00000000..ee571a07 --- /dev/null +++ b/app/Http/Requests/Api/Client/Servers/Files/ListFilesRequest.php @@ -0,0 +1,20 @@ +user()->can('list-files', $this->getModel(Server::class)); + } +} diff --git a/app/Http/Requests/Api/Client/Servers/Network/GetNetworkRequest.php b/app/Http/Requests/Api/Client/Servers/Network/GetNetworkRequest.php new file mode 100644 index 00000000..14fd1833 --- /dev/null +++ b/app/Http/Requests/Api/Client/Servers/Network/GetNetworkRequest.php @@ -0,0 +1,20 @@ +user()->can('view-allocations', $this->getModel(Server::class)); + } +} diff --git a/app/Http/Requests/Auth/LoginCheckpointRequest.php b/app/Http/Requests/Auth/LoginCheckpointRequest.php new file mode 100644 index 00000000..64fa7859 --- /dev/null +++ b/app/Http/Requests/Auth/LoginCheckpointRequest.php @@ -0,0 +1,31 @@ + 'required|string', + 'authentication_code' => 'required|int', + ]; + } +} diff --git a/app/Http/Requests/Auth/LoginRequest.php b/app/Http/Requests/Auth/LoginRequest.php new file mode 100644 index 00000000..7fed2093 --- /dev/null +++ b/app/Http/Requests/Auth/LoginRequest.php @@ -0,0 +1,27 @@ + 'required|string|min:1', + 'password' => 'required|string', + ]; + } +} diff --git a/app/Http/Requests/Auth/ResetPasswordRequest.php b/app/Http/Requests/Auth/ResetPasswordRequest.php new file mode 100644 index 00000000..e06883c2 --- /dev/null +++ b/app/Http/Requests/Auth/ResetPasswordRequest.php @@ -0,0 +1,28 @@ + 'required|string', + 'email' => 'required|email', + 'password' => 'required|string|confirmed|min:8', + ]; + } +} diff --git a/app/Http/Requests/Base/AccountDataFormRequest.php b/app/Http/Requests/Base/AccountDataFormRequest.php index 076cba9b..474d85ac 100644 --- a/app/Http/Requests/Base/AccountDataFormRequest.php +++ b/app/Http/Requests/Base/AccountDataFormRequest.php @@ -28,7 +28,7 @@ class AccountDataFormRequest extends FrontendUserFormRequest // Verify password matches when changing password or email. if (in_array($this->input('do_action'), ['password', 'email'])) { if (! password_verify($this->input('current_password'), $this->user()->password)) { - throw new InvalidPasswordProvidedException(trans('base.account.invalid_password')); + throw new InvalidPasswordProvidedException(trans('validation.internal.invalid_password')); } } diff --git a/app/Http/ViewComposers/AssetComposer.php b/app/Http/ViewComposers/AssetComposer.php new file mode 100644 index 00000000..41e5f7e1 --- /dev/null +++ b/app/Http/ViewComposers/AssetComposer.php @@ -0,0 +1,34 @@ +assetHashService = $assetHashService; + } + + /** + * Provide access to the asset service in the views. + * + * @param \Illuminate\View\View $view + */ + public function compose(View $view) + { + $view->with('asset', $this->assetHashService); + } +} diff --git a/app/Models/Node.php b/app/Models/Node.php index 1a412be9..256431ce 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -132,6 +132,16 @@ class Node extends Model implements CleansAttributes, ValidableContract 'maintenance_mode' => false, ]; + /** + * Get the connection address to use when making calls to this node. + * + * @return string + */ + public function getConnectionAddress(): string + { + return sprintf('%s://%s:%s', $this->scheme, $this->fqdn, $this->daemonListen); + } + /** * Returns the configuration in JSON format. * diff --git a/app/Models/Server.php b/app/Models/Server.php index b1a77ead..af80a05b 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -143,6 +143,14 @@ class Server extends Model implements CleansAttributes, ValidableContract return Schema::getColumnListing($this->getTable()); } + /** + * @return bool + */ + public function isInstalled(): bool + { + return $this->installed === 1; + } + /** * Gets the user who owns the server. * diff --git a/app/Models/User.php b/app/Models/User.php index 6732b23a..28f785e0 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -5,6 +5,7 @@ namespace Pterodactyl\Models; use Sofa\Eloquence\Eloquence; use Sofa\Eloquence\Validable; use Pterodactyl\Rules\Username; +use Illuminate\Support\Collection; use Illuminate\Validation\Rules\In; use Illuminate\Auth\Authenticatable; use Illuminate\Database\Eloquent\Model; @@ -177,6 +178,16 @@ class User extends Model implements return $rules; } + /** + * Return the user model in a format that can be passed over to Vue templates. + * + * @return array + */ + public function toVueObject(): array + { + return (new Collection($this->toArray()))->except(['id', 'external_id'])->toArray(); + } + /** * Send the password reset notification. * diff --git a/app/Providers/RepositoryServiceProvider.php b/app/Providers/RepositoryServiceProvider.php index aa5fbbaa..9813baa2 100644 --- a/app/Providers/RepositoryServiceProvider.php +++ b/app/Providers/RepositoryServiceProvider.php @@ -3,7 +3,7 @@ namespace Pterodactyl\Providers; use Illuminate\Support\ServiceProvider; -use Pterodactyl\Repositories\Daemon\FileRepository; +use Pterodactyl\Repositories\Wings\FileRepository; use Pterodactyl\Repositories\Daemon\PowerRepository; use Pterodactyl\Repositories\Eloquent\EggRepository; use Pterodactyl\Repositories\Eloquent\NestRepository; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index f0e97811..2ee187c6 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -22,20 +22,21 @@ class RouteServiceProvider extends ServiceProvider public function map() { Route::middleware(['web', 'auth', 'csrf']) - ->namespace($this->namespace . '\Base') - ->group(base_path('routes/base.php')); + ->namespace($this->namespace . '\Base') + ->group(base_path('routes/base.php')); Route::middleware(['web', 'auth', 'admin', 'csrf'])->prefix('/admin') - ->namespace($this->namespace . '\Admin') - ->group(base_path('routes/admin.php')); + ->namespace($this->namespace . '\Admin') + ->group(base_path('routes/admin.php')); Route::middleware(['web', 'csrf'])->prefix('/auth') - ->namespace($this->namespace . '\Auth') - ->group(base_path('routes/auth.php')); + ->namespace($this->namespace . '\Auth') + ->group(base_path('routes/auth.php')); - Route::middleware(['web', 'csrf', 'auth', 'server', 'subuser.auth', 'node.maintenance'])->prefix('/server/{server}') - ->namespace($this->namespace . '\Server') - ->group(base_path('routes/server.php')); + Route::middleware(['web', 'csrf', 'auth', 'server', 'subuser.auth', 'node.maintenance']) + ->prefix('/api/server/{server}') + ->namespace($this->namespace . '\Server') + ->group(base_path('routes/server.php')); Route::middleware(['api'])->prefix('/api/application') ->namespace($this->namespace . '\Api\Application') @@ -50,7 +51,7 @@ class RouteServiceProvider extends ServiceProvider ->group(base_path('routes/api-remote.php')); Route::middleware(['web', 'daemon-old'])->prefix('/daemon') - ->namespace($this->namespace . '\Daemon') - ->group(base_path('routes/daemon.php')); + ->namespace($this->namespace . '\Daemon') + ->group(base_path('routes/daemon.php')); } } diff --git a/app/Providers/ViewComposerServiceProvider.php b/app/Providers/ViewComposerServiceProvider.php index ab8c9e16..9490234f 100644 --- a/app/Providers/ViewComposerServiceProvider.php +++ b/app/Providers/ViewComposerServiceProvider.php @@ -3,6 +3,7 @@ namespace Pterodactyl\Providers; use Illuminate\Support\ServiceProvider; +use Pterodactyl\Http\ViewComposers\AssetComposer; use Pterodactyl\Http\ViewComposers\ServerListComposer; use Pterodactyl\Http\ViewComposers\Server\ServerDataComposer; @@ -13,6 +14,8 @@ class ViewComposerServiceProvider extends ServiceProvider */ public function boot() { + $this->app->make('view')->composer('*', AssetComposer::class); + $this->app->make('view')->composer('server.*', ServerDataComposer::class); // Add data to make the sidebar work when viewing a server. diff --git a/app/Repositories/Daemon/FileRepository.php b/app/Repositories/Daemon/FileRepository.php index 46117f3c..da55f4c1 100644 --- a/app/Repositories/Daemon/FileRepository.php +++ b/app/Repositories/Daemon/FileRepository.php @@ -84,33 +84,6 @@ class FileRepository extends BaseRepository implements FileRepositoryInterface { $response = $this->getHttpClient()->request('GET', sprintf('server/directory/%s', rawurlencode($path))); - $contents = json_decode($response->getBody()); - $files = $folders = []; - - foreach ($contents as $value) { - if ($value->directory) { - array_push($folders, [ - 'entry' => $value->name, - 'directory' => trim($path, '/'), - 'size' => null, - 'date' => strtotime($value->modified), - 'mime' => $value->mime, - ]); - } elseif ($value->file) { - array_push($files, [ - 'entry' => $value->name, - 'directory' => trim($path, '/'), - 'extension' => str_replace('\\', '/', pathinfo($value->name, PATHINFO_EXTENSION)), - 'size' => human_readable($value->size), - 'date' => strtotime($value->modified), - 'mime' => $value->mime, - ]); - } - } - - return [ - 'files' => $files, - 'folders' => $folders, - ]; + return json_decode($response->getBody()); } } diff --git a/app/Repositories/Eloquent/DatabaseRepository.php b/app/Repositories/Eloquent/DatabaseRepository.php index d3b615b9..a159324b 100644 --- a/app/Repositories/Eloquent/DatabaseRepository.php +++ b/app/Repositories/Eloquent/DatabaseRepository.php @@ -76,7 +76,7 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor */ public function getDatabasesForServer(int $server): Collection { - return $this->getBuilder()->where('server_id', $server)->get($this->getColumns()); + return $this->getBuilder()->with('host')->where('server_id', $server)->get($this->getColumns()); } /** diff --git a/app/Repositories/Wings/BaseWingsRepository.php b/app/Repositories/Wings/BaseWingsRepository.php new file mode 100644 index 00000000..b22f8f8d --- /dev/null +++ b/app/Repositories/Wings/BaseWingsRepository.php @@ -0,0 +1,33 @@ +getConfig(), [ + 'base_uri' => $this->getNode()->getConnectionAddress(), + 'headers' => [ + 'Authorization' => 'Bearer ' . ($this->getToken() ?? $this->getNode()->daemonSecret), + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ], + ])); + } +} diff --git a/app/Repositories/Wings/FileRepository.php b/app/Repositories/Wings/FileRepository.php new file mode 100644 index 00000000..5f2efa27 --- /dev/null +++ b/app/Repositories/Wings/FileRepository.php @@ -0,0 +1,69 @@ +getHttpClient()->get( + // Reason for the path check is because it is unnecessary on the Daemon but we need + // to respect the interface. + sprintf('/api/servers/%s/files/list/%s', $this->getServer()->uuid, $path === '/' ? '' : $path) + ); + + return json_decode($response->getBody(), true); + } +} diff --git a/app/Services/Helpers/AssetHashService.php b/app/Services/Helpers/AssetHashService.php new file mode 100644 index 00000000..33945578 --- /dev/null +++ b/app/Services/Helpers/AssetHashService.php @@ -0,0 +1,141 @@ +application = $application; + $this->cache = $cache; + $this->filesystem = $filesystem->createLocalDriver(['root' => public_path()]); + } + + /** + * Modify a URL to append the asset hash. + * + * @param string $resource + * @return string + * + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function url(string $resource): string + { + $file = last(explode('/', $resource)); + $data = array_get($this->manifest(), $file, $file); + + return str_replace($file, array_get($data, 'src', $file), $resource); + } + + /** + * Return the data integrity hash for a resource. + * + * @param string $resource + * @return string + * + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function integrity(string $resource): string + { + $file = last(explode('/', $resource)); + $data = array_get($this->manifest(), $file, $file); + + return array_get($data, 'integrity', ''); + } + + /** + * Return a built CSS import using the provided URL. + * + * @param string $resource + * @return string + * + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function css(string $resource): string + { + return ''; + } + + /** + * Return a built JS import using the provided URL. + * + * @param string $resource + * @return string + * + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function js(string $resource): string + { + return ''; + } + + /** + * Get the asset manifest and store it in the cache for quicker lookups. + * + * @return array + * + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + protected function manifest(): array + { + if (! is_null(self::$manifest)) { + return self::$manifest; + } + + // Skip checking the cache if we are not in production. + if ($this->application->environment() === 'production') { + $stored = $this->cache->get('Core:AssetManifest'); + if (! is_null($stored)) { + return self::$manifest = $stored; + } + } + + $contents = json_decode($this->filesystem->get(self::MANIFEST_PATH), true); + $this->cache->put('Core:AssetManifest', $contents, 1440); + + return self::$manifest = $contents; + } +} diff --git a/app/Services/Users/TwoFactorSetupService.php b/app/Services/Users/TwoFactorSetupService.php index 786cf3d3..57d572ca 100644 --- a/app/Services/Users/TwoFactorSetupService.php +++ b/app/Services/Users/TwoFactorSetupService.php @@ -10,6 +10,7 @@ namespace Pterodactyl\Services\Users; use Pterodactyl\Models\User; +use Illuminate\Support\Collection; use PragmaRX\Google2FAQRCode\Google2FA; use Illuminate\Contracts\Encryption\Encrypter; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; @@ -62,12 +63,12 @@ class TwoFactorSetupService * QR code image. * * @param \Pterodactyl\Models\User $user - * @return string + * @return \Illuminate\Support\Collection * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function handle(User $user): string + public function handle(User $user): Collection { $secret = $this->google2FA->generateSecretKey($this->config->get('pterodactyl.auth.2fa.bytes')); $image = $this->google2FA->getQRCodeInline($this->config->get('app.name'), $user->email, $secret); @@ -76,6 +77,9 @@ class TwoFactorSetupService 'totp_secret' => $this->encrypter->encrypt($secret), ]); - return $image; + return new Collection([ + 'image' => $image, + 'secret' => $secret, + ]); } } diff --git a/app/Transformers/Api/Client/AccountTransformer.php b/app/Transformers/Api/Client/AccountTransformer.php new file mode 100644 index 00000000..2cdc92e3 --- /dev/null +++ b/app/Transformers/Api/Client/AccountTransformer.php @@ -0,0 +1,37 @@ + $model->id, + 'admin' => $model->root_admin, + 'username' => $model->username, + 'email' => $model->email, + 'first_name' => $model->name_first, + 'last_name' => $model->name_last, + 'language' => $model->language, + ]; + } +} diff --git a/app/Transformers/Api/Client/AllocationTransformer.php b/app/Transformers/Api/Client/AllocationTransformer.php new file mode 100644 index 00000000..055afdae --- /dev/null +++ b/app/Transformers/Api/Client/AllocationTransformer.php @@ -0,0 +1,36 @@ +loadMissing('server'); + + return [ + 'ip' => $model->ip, + 'alias' => $model->ip_alias, + 'port' => $model->port, + 'default' => $model->getRelation('server')->allocation_id === $model->id, + ]; + } +} diff --git a/app/Transformers/Api/Client/DatabaseTransformer.php b/app/Transformers/Api/Client/DatabaseTransformer.php new file mode 100644 index 00000000..c7b3177c --- /dev/null +++ b/app/Transformers/Api/Client/DatabaseTransformer.php @@ -0,0 +1,78 @@ +encrypter = $encrypter; + $this->hashids = $hashids; + } + + /** + * @return string + */ + public function getResourceName(): string + { + return Database::RESOURCE_NAME; + } + + /** + * @param \Pterodactyl\Models\Database $model + * @return array + */ + public function transform(Database $model): array + { + $model->loadMissing('host'); + + return [ + 'id' => $this->hashids->encode($model->id), + 'host' => [ + 'address' => $model->getRelation('host')->host, + 'port' => $model->getRelation('host')->port, + ], + 'name' => $model->database, + 'username' => $model->username, + 'connections_from' => $model->remote, + ]; + } + + /** + * Include the database password in the request. + * + * @param \Pterodactyl\Models\Database $model + * @return \League\Fractal\Resource\Item + */ + public function includePassword(Database $model): Item + { + return $this->item($model, function (Database $model) { + return [ + 'password' => $this->encrypter->decrypt($model->password), + ]; + }, 'database_password'); + } +} diff --git a/app/Transformers/Api/Client/ServerTransformer.php b/app/Transformers/Api/Client/ServerTransformer.php index 6816d6d7..64282686 100644 --- a/app/Transformers/Api/Client/ServerTransformer.php +++ b/app/Transformers/Api/Client/ServerTransformer.php @@ -28,7 +28,12 @@ class ServerTransformer extends BaseClientTransformer 'identifier' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, + 'node' => $server->node->name, 'description' => $server->description, + 'allocation' => [ + 'ip' => $server->allocation->alias, + 'port' => $server->allocation->port, + ], 'limits' => [ 'memory' => $server->memory, 'swap' => $server->swap, diff --git a/app/Transformers/Api/Client/StatsTransformer.php b/app/Transformers/Api/Client/StatsTransformer.php index 01d8e3f2..d3e66eb9 100644 --- a/app/Transformers/Api/Client/StatsTransformer.php +++ b/app/Transformers/Api/Client/StatsTransformer.php @@ -3,6 +3,8 @@ namespace Pterodactyl\Transformers\Api\Client; use Pterodactyl\Models\Server; +use GuzzleHttp\Exception\RequestException; +use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface; class StatsTransformer extends BaseClientTransformer @@ -36,6 +38,8 @@ class StatsTransformer extends BaseClientTransformer * * @param \Pterodactyl\Models\Server $model * @return array + * + * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException */ public function transform(Server $model) { @@ -61,7 +65,10 @@ class StatsTransformer extends BaseClientTransformer 'disk' => [ 'current' => round(object_get($object, 'proc.disk.used', 0)), 'limit' => floatval($model->disk), + 'io' => $model->io, ], + 'installed' => $model->installed === 1, + 'suspended' => (bool) $model->suspended, ]; } diff --git a/composer.json b/composer.json index 95c96926..e3e3d532 100644 --- a/composer.json +++ b/composer.json @@ -48,10 +48,13 @@ "filp/whoops": "^2.1", "friendsofphp/php-cs-fixer": "^2.11.1", "fzaninotto/faker": "^1.6", + "laravel/dusk": "^3.0", + "martinlindhe/laravel-vue-i18n-generator": "^0.1.28", "mockery/mockery": "^1.0", "nunomaduro/collision": "^2.0", "php-mock/php-mock-phpunit": "^2.1", - "phpunit/phpunit": "~7.0" + "phpunit/phpunit": "~7.0", + "tightenco/ziggy": "^0.5.0" }, "autoload": { "classmap": [ @@ -66,6 +69,7 @@ }, "autoload-dev": { "psr-4": { + "Pterodactyl\\Tests\\Browser\\": "tests/Browser", "Pterodactyl\\Tests\\Integration\\": "tests/Integration", "Tests\\": "tests/" } diff --git a/composer.lock b/composer.lock index f1a7e59f..e0372b8b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9c03519785d01a8f710a0f7e65f602e8", + "content-hash": "d16e45e7d2f27afca05914fa627726e7", "packages": [ { "name": "appstract/laravel-blade-directives", @@ -61,16 +61,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.74.1", + "version": "3.81.6", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "e02575af8021ee57b818107c1fd8759110374044" + "reference": "0e07e92ec7042316ffc79ef290cf7bbb7d7be24b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e02575af8021ee57b818107c1fd8759110374044", - "reference": "e02575af8021ee57b818107c1fd8759110374044", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0e07e92ec7042316ffc79ef290cf7bbb7d7be24b", + "reference": "0e07e92ec7042316ffc79ef290cf7bbb7d7be24b", "shasum": "" }, "require": { @@ -140,7 +140,7 @@ "s3", "sdk" ], - "time": "2018-11-21T19:18:43+00:00" + "time": "2018-12-14T22:50:05+00:00" }, { "name": "bacon/bacon-qr-code", @@ -400,16 +400,16 @@ }, { "name": "doctrine/dbal", - "version": "v2.8.0", + "version": "v2.9.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "5140a64c08b4b607b9bedaae0cedd26f04a0e621" + "reference": "ec74d6e300d78fbc896669c3ca57ef9719adc9c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/5140a64c08b4b607b9bedaae0cedd26f04a0e621", - "reference": "5140a64c08b4b607b9bedaae0cedd26f04a0e621", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/ec74d6e300d78fbc896669c3ca57ef9719adc9c6", + "reference": "ec74d6e300d78fbc896669c3ca57ef9719adc9c6", "shasum": "" }, "require": { @@ -419,11 +419,10 @@ "php": "^7.1" }, "require-dev": { - "doctrine/coding-standard": "^4.0", + "doctrine/coding-standard": "^5.0", "jetbrains/phpstorm-stubs": "^2018.1.2", "phpstan/phpstan": "^0.10.1", - "phpunit/phpunit": "^7.1.2", - "phpunit/phpunit-mock-objects": "!=3.2.4,!=3.2.5", + "phpunit/phpunit": "^7.4", "symfony/console": "^2.0.5|^3.0|^4.0", "symfony/phpunit-bridge": "^3.4.5|^4.0.5" }, @@ -436,13 +435,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8.x-dev", + "dev-master": "2.9.x-dev", "dev-develop": "3.0.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\DBAL\\": "lib/" + "psr-4": { + "Doctrine\\DBAL\\": "lib/Doctrine/DBAL" } }, "notification-url": "https://packagist.org/downloads/", @@ -467,15 +466,19 @@ "email": "jonwage@gmail.com" } ], - "description": "Database Abstraction Layer", - "homepage": "http://www.doctrine-project.org", + "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", + "homepage": "https://www.doctrine-project.org/projects/dbal.html", "keywords": [ + "abstraction", "database", "dbal", + "mysql", "persistence", + "pgsql", + "php", "queryobject" ], - "time": "2018-07-13T03:16:35+00:00" + "time": "2018-12-14T04:51:13+00:00" }, { "name": "doctrine/event-manager", @@ -723,16 +726,16 @@ }, { "name": "egulias/email-validator", - "version": "2.1.6", + "version": "2.1.7", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "0578b32b30b22de3e8664f797cf846fc9246f786" + "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/0578b32b30b22de3e8664f797cf846fc9246f786", - "reference": "0578b32b30b22de3e8664f797cf846fc9246f786", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/709f21f92707308cdf8f9bcfa1af4cb26586521e", + "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e", "shasum": "" }, "require": { @@ -776,7 +779,7 @@ "validation", "validator" ], - "time": "2018-09-25T20:47:26+00:00" + "time": "2018-12-04T22:38:24+00:00" }, { "name": "erusev/parsedown", @@ -996,32 +999,33 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.4.2", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + "reference": "9f83dded91781a01c63574e387eaa769be769115" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115", + "reference": "9f83dded91781a01c63574e387eaa769be769115", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -1051,13 +1055,14 @@ "keywords": [ "http", "message", + "psr-7", "request", "response", "stream", "uri", "url" ], - "time": "2017-03-20T17:10:46+00:00" + "time": "2018-12-04T20:46:45+00:00" }, { "name": "hashids/hashids", @@ -1335,16 +1340,16 @@ }, { "name": "laravel/framework", - "version": "v5.7.14", + "version": "v5.7.17", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "ad6c1fe1e455c0f73a431928282704879ccbd856" + "reference": "a15898e2de5f5ae5548a09349c558ef0435d495a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/ad6c1fe1e455c0f73a431928282704879ccbd856", - "reference": "ad6c1fe1e455c0f73a431928282704879ccbd856", + "url": "https://api.github.com/repos/laravel/framework/zipball/a15898e2de5f5ae5548a09349c558ef0435d495a", + "reference": "a15898e2de5f5ae5548a09349c558ef0435d495a", "shasum": "" }, "require": { @@ -1353,6 +1358,8 @@ "erusev/parsedown": "^1.7", "ext-mbstring": "*", "ext-openssl": "*", + "laravel/nexmo-notification-channel": "^1.0", + "laravel/slack-notification-channel": "^1.0", "league/flysystem": "^1.0.8", "monolog/monolog": "^1.12", "nesbot/carbon": "^1.26.3", @@ -1475,7 +1482,121 @@ "framework", "laravel" ], - "time": "2018-11-21T13:46:08+00:00" + "time": "2018-12-12T14:38:09+00:00" + }, + { + "name": "laravel/nexmo-notification-channel", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/nexmo-notification-channel.git", + "reference": "03edd42a55b306ff980c9950899d5a2b03260d48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/nexmo-notification-channel/zipball/03edd42a55b306ff980c9950899d5a2b03260d48", + "reference": "03edd42a55b306ff980c9950899d5a2b03260d48", + "shasum": "" + }, + "require": { + "nexmo/client": "^1.0", + "php": "^7.1.3" + }, + "require-dev": { + "illuminate/notifications": "~5.7", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Illuminate\\Notifications\\NexmoChannelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Notifications\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Nexmo Notification Channel for laravel.", + "keywords": [ + "laravel", + "nexmo", + "notifications" + ], + "time": "2018-12-04T12:57:08+00:00" + }, + { + "name": "laravel/slack-notification-channel", + "version": "v1.0.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/slack-notification-channel.git", + "reference": "6e164293b754a95f246faf50ab2bbea3e4923cc9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/6e164293b754a95f246faf50ab2bbea3e4923cc9", + "reference": "6e164293b754a95f246faf50ab2bbea3e4923cc9", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": "^7.1.3" + }, + "require-dev": { + "illuminate/notifications": "~5.7", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Illuminate\\Notifications\\SlackChannelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Notifications\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Slack Notification Channel for laravel.", + "keywords": [ + "laravel", + "notifications", + "slack" + ], + "time": "2018-12-12T13:12:06+00:00" }, { "name": "laravel/tinker", @@ -1540,6 +1661,64 @@ ], "time": "2018-10-12T19:39:35+00:00" }, + { + "name": "lcobucci/jwt", + "version": "3.2.5", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "82be04b4753f8b7693b62852b7eab30f97524f9b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/82be04b4753f8b7693b62852b7eab30f97524f9b", + "reference": "82be04b4753f8b7693b62852b7eab30f97524f9b", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=5.5" + }, + "require-dev": { + "mdanter/ecc": "~0.3.1", + "mikey179/vfsstream": "~1.5", + "phpmd/phpmd": "~2.2", + "phpunit/php-invoker": "~1.1", + "phpunit/phpunit": "~4.5", + "squizlabs/php_codesniffer": "~2.3" + }, + "suggest": { + "mdanter/ecc": "Required to use Elliptic Curves based algorithms." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Otávio Cobucci Oblonczyk", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "time": "2018-11-11T12:22:26+00:00" + }, { "name": "league/flysystem", "version": "1.0.49", @@ -1974,6 +2153,54 @@ ], "time": "2018-11-22T18:23:02+00:00" }, + { + "name": "nexmo/client", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/Nexmo/nexmo-php.git", + "reference": "f192c84ec3cc3e2657fc754e0da1a17e39ac5542" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nexmo/nexmo-php/zipball/f192c84ec3cc3e2657fc754e0da1a17e39ac5542", + "reference": "f192c84ec3cc3e2657fc754e0da1a17e39ac5542", + "shasum": "" + }, + "require": { + "lcobucci/jwt": "^3.2", + "php": ">=5.6", + "php-http/client-implementation": "^1.0", + "php-http/guzzle6-adapter": "^1.0", + "zendframework/zend-diactoros": "^1.3" + }, + "require-dev": { + "estahn/phpunit-json-assertions": "^1.0.0", + "php-http/mock-client": "^0.3.0", + "phpunit/phpunit": "^5.7", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nexmo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tim Lytle", + "email": "tim@nexmo.com", + "homepage": "http://twitter.com/tjlytle", + "role": "Developer" + } + ], + "description": "PHP Client for using Nexmo's API.", + "time": "2018-11-14T14:12:22+00:00" + }, { "name": "nikic/php-parser", "version": "v4.1.0", @@ -2027,16 +2254,16 @@ }, { "name": "opis/closure", - "version": "3.1.1", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "d3209e46ad6c69a969b705df0738fd0dbe26ef9e" + "reference": "de00c69a2328d3ee5baa71fc584dc643222a574c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/d3209e46ad6c69a969b705df0738fd0dbe26ef9e", - "reference": "d3209e46ad6c69a969b705df0738fd0dbe26ef9e", + "url": "https://api.github.com/repos/opis/closure/zipball/de00c69a2328d3ee5baa71fc584dc643222a574c", + "reference": "de00c69a2328d3ee5baa71fc584dc643222a574c", "shasum": "" }, "require": { @@ -2044,7 +2271,7 @@ }, "require-dev": { "jeremeamia/superclosure": "^2.0", - "phpunit/phpunit": "^4.0" + "phpunit/phpunit": "^4.0|^5.0|^6.0|^7.0" }, "type": "library", "extra": { @@ -2084,7 +2311,7 @@ "serialization", "serialize" ], - "time": "2018-10-02T13:36:53+00:00" + "time": "2018-12-16T21:48:23+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -2197,6 +2424,172 @@ ], "time": "2018-07-04T16:31:37+00:00" }, + { + "name": "php-http/guzzle6-adapter", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-http/guzzle6-adapter.git", + "reference": "a56941f9dc6110409cfcddc91546ee97039277ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/guzzle6-adapter/zipball/a56941f9dc6110409cfcddc91546ee97039277ab", + "reference": "a56941f9dc6110409cfcddc91546ee97039277ab", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": ">=5.5.0", + "php-http/httplug": "^1.0" + }, + "provide": { + "php-http/async-client-implementation": "1.0", + "php-http/client-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "php-http/adapter-integration-tests": "^0.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Adapter\\Guzzle6\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + }, + { + "name": "David de Boer", + "email": "david@ddeboer.nl" + } + ], + "description": "Guzzle 6 HTTP Adapter", + "homepage": "http://httplug.io", + "keywords": [ + "Guzzle", + "http" + ], + "time": "2016-05-10T06:13:32+00:00" + }, + { + "name": "php-http/httplug", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/httplug.git", + "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/httplug/zipball/1c6381726c18579c4ca2ef1ec1498fdae8bdf018", + "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "php-http/promise": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eric GELOEN", + "email": "geloen.eric@gmail.com" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "HTTPlug, the HTTP client abstraction for PHP", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "http" + ], + "time": "2016-08-31T08:30:17+00:00" + }, + { + "name": "php-http/promise", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/promise.git", + "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/promise/zipball/dc494cdc9d7160b9a09bd5573272195242ce7980", + "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980", + "shasum": "" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + }, + { + "name": "Joel Wurtz", + "email": "joel.wurtz@gmail.com" + } + ], + "description": "Promise used for asynchronous HTTP requests", + "homepage": "http://httplug.io", + "keywords": [ + "promise" + ], + "time": "2016-01-26T13:27:02+00:00" + }, { "name": "pragmarx/google2fa", "version": "v5.0.0", @@ -2689,6 +3082,46 @@ ], "time": "2018-10-13T15:16:03+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.0", + "satooshi/php-coveralls": ">=1.0" + }, + "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.", + "time": "2016-02-11T07:05:27+00:00" + }, { "name": "ramsey/uuid", "version": "3.8.0", @@ -3215,20 +3648,21 @@ }, { "name": "symfony/console", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "432122af37d8cd52fba1b294b11976e0d20df595" + "reference": "4dff24e5d01e713818805c1862d2e3f901ee7dd0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/432122af37d8cd52fba1b294b11976e0d20df595", - "reference": "432122af37d8cd52fba1b294b11976e0d20df595", + "url": "https://api.github.com/repos/symfony/console/zipball/4dff24e5d01e713818805c1862d2e3f901ee7dd0", + "reference": "4dff24e5d01e713818805c1862d2e3f901ee7dd0", "shasum": "" }, "require": { "php": "^7.1.3", + "symfony/contracts": "^1.0", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { @@ -3252,7 +3686,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3279,20 +3713,88 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:30:44+00:00" + "time": "2018-11-27T07:40:44+00:00" }, { - "name": "symfony/css-selector", - "version": "v4.1.7", + "name": "symfony/contracts", + "version": "v1.0.2", "source": { "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "d67de79a70a27d93c92c47f37ece958bf8de4d8a" + "url": "https://github.com/symfony/contracts.git", + "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/d67de79a70a27d93c92c47f37ece958bf8de4d8a", - "reference": "d67de79a70a27d93c92c47f37ece958bf8de4d8a", + "url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf", + "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "require-dev": { + "psr/cache": "^1.0", + "psr/container": "^1.0" + }, + "suggest": { + "psr/cache": "When using the Cache contracts", + "psr/container": "When using the Service contracts", + "symfony/cache-contracts-implementation": "", + "symfony/service-contracts-implementation": "", + "symfony/translation-contracts-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\": "" + }, + "exclude-from-classmap": [ + "**/Tests/" + ] + }, + "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 set of abstractions extracted out of the Symfony components", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2018-12-05T08:06:11+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "aa9fa526ba1b2ec087ffdfb32753803d999fcfcd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/aa9fa526ba1b2ec087ffdfb32753803d999fcfcd", + "reference": "aa9fa526ba1b2ec087ffdfb32753803d999fcfcd", "shasum": "" }, "require": { @@ -3301,7 +3803,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3332,20 +3834,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-10-02T16:36:10+00:00" + "time": "2018-11-11T19:52:12+00:00" }, { "name": "symfony/debug", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "19090917b848a799cbae4800abf740fe4eb71c1d" + "reference": "e0a2b92ee0b5b934f973d90c2f58e18af109d276" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/19090917b848a799cbae4800abf740fe4eb71c1d", - "reference": "19090917b848a799cbae4800abf740fe4eb71c1d", + "url": "https://api.github.com/repos/symfony/debug/zipball/e0a2b92ee0b5b934f973d90c2f58e18af109d276", + "reference": "e0a2b92ee0b5b934f973d90c2f58e18af109d276", "shasum": "" }, "require": { @@ -3361,7 +3863,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3388,24 +3890,25 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:09:42+00:00" + "time": "2018-11-28T18:24:18+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "552541dad078c85d9414b09c041ede488b456cd5" + "reference": "921f49c3158a276d27c0d770a5a347a3b718b328" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/552541dad078c85d9414b09c041ede488b456cd5", - "reference": "552541dad078c85d9414b09c041ede488b456cd5", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/921f49c3158a276d27c0d770a5a347a3b718b328", + "reference": "921f49c3158a276d27c0d770a5a347a3b718b328", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.1.3", + "symfony/contracts": "^1.0" }, "conflict": { "symfony/dependency-injection": "<3.4" @@ -3424,7 +3927,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3451,20 +3954,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-10-10T13:52:42+00:00" + "time": "2018-12-01T08:52:38+00:00" }, { "name": "symfony/finder", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "1f17195b44543017a9c9b2d437c670627e96ad06" + "reference": "e53d477d7b5c4982d0e1bfd2298dbee63d01441d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/1f17195b44543017a9c9b2d437c670627e96ad06", - "reference": "1f17195b44543017a9c9b2d437c670627e96ad06", + "url": "https://api.github.com/repos/symfony/finder/zipball/e53d477d7b5c4982d0e1bfd2298dbee63d01441d", + "reference": "e53d477d7b5c4982d0e1bfd2298dbee63d01441d", "shasum": "" }, "require": { @@ -3473,7 +3976,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3500,20 +4003,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-10-03T08:47:56+00:00" + "time": "2018-11-11T19:52:12+00:00" }, { "name": "symfony/http-foundation", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "82d494c1492b0dd24bbc5c2d963fb02eb44491af" + "reference": "1b31f3017fadd8cb05cf2c8aebdbf3b12a943851" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/82d494c1492b0dd24bbc5c2d963fb02eb44491af", - "reference": "82d494c1492b0dd24bbc5c2d963fb02eb44491af", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/1b31f3017fadd8cb05cf2c8aebdbf3b12a943851", + "reference": "1b31f3017fadd8cb05cf2c8aebdbf3b12a943851", "shasum": "" }, "require": { @@ -3527,7 +4030,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3554,25 +4057,26 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:09:42+00:00" + "time": "2018-11-26T10:55:26+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "958be64ab13b65172ad646ef5ae20364c2305fae" + "reference": "b39ceffc0388232c309cbde3a7c3685f2ec0a624" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/958be64ab13b65172ad646ef5ae20364c2305fae", - "reference": "958be64ab13b65172ad646ef5ae20364c2305fae", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b39ceffc0388232c309cbde3a7c3685f2ec0a624", + "reference": "b39ceffc0388232c309cbde3a7c3685f2ec0a624", "shasum": "" }, "require": { "php": "^7.1.3", "psr/log": "~1.0", + "symfony/contracts": "^1.0.2", "symfony/debug": "~3.4|~4.0", "symfony/event-dispatcher": "~4.1", "symfony/http-foundation": "^4.1.1", @@ -3580,7 +4084,8 @@ }, "conflict": { "symfony/config": "<3.4", - "symfony/dependency-injection": "<4.1", + "symfony/dependency-injection": "<4.2", + "symfony/translation": "<4.2", "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" }, @@ -3593,7 +4098,7 @@ "symfony/config": "~3.4|~4.0", "symfony/console": "~3.4|~4.0", "symfony/css-selector": "~3.4|~4.0", - "symfony/dependency-injection": "^4.1", + "symfony/dependency-injection": "^4.2", "symfony/dom-crawler": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", @@ -3601,7 +4106,7 @@ "symfony/routing": "~3.4|~4.0", "symfony/stopwatch": "~3.4|~4.0", "symfony/templating": "~3.4|~4.0", - "symfony/translation": "~3.4|~4.0", + "symfony/translation": "~4.2", "symfony/var-dumper": "^4.1.1" }, "suggest": { @@ -3614,7 +4119,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3641,7 +4146,7 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2018-11-03T11:11:23+00:00" + "time": "2018-12-06T17:39:52+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3925,16 +4430,16 @@ }, { "name": "symfony/process", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3e83acef94d979b1de946599ef86b3a352abcdc9" + "reference": "2b341009ccec76837a7f46f59641b431e4d4c2b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3e83acef94d979b1de946599ef86b3a352abcdc9", - "reference": "3e83acef94d979b1de946599ef86b3a352abcdc9", + "url": "https://api.github.com/repos/symfony/process/zipball/2b341009ccec76837a7f46f59641b431e4d4c2b0", + "reference": "2b341009ccec76837a7f46f59641b431e4d4c2b0", "shasum": "" }, "require": { @@ -3943,7 +4448,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3970,34 +4475,34 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-10-14T20:48:13+00:00" + "time": "2018-11-20T16:22:05+00:00" }, { "name": "symfony/routing", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "d4a3c14cfbe6b9c05a1d6e948654022d4d1ad3fd" + "reference": "649460207e77da6c545326c7f53618d23ad2c866" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/d4a3c14cfbe6b9c05a1d6e948654022d4d1ad3fd", - "reference": "d4a3c14cfbe6b9c05a1d6e948654022d4d1ad3fd", + "url": "https://api.github.com/repos/symfony/routing/zipball/649460207e77da6c545326c7f53618d23ad2c866", + "reference": "649460207e77da6c545326c7f53618d23ad2c866", "shasum": "" }, "require": { "php": "^7.1.3" }, "conflict": { - "symfony/config": "<3.4", + "symfony/config": "<4.2", "symfony/dependency-injection": "<3.4", "symfony/yaml": "<3.4" }, "require-dev": { "doctrine/annotations": "~1.0", "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", + "symfony/config": "~4.2", "symfony/dependency-injection": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/http-foundation": "~3.4|~4.0", @@ -4014,7 +4519,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -4047,24 +4552,25 @@ "uri", "url" ], - "time": "2018-10-28T18:38:52+00:00" + "time": "2018-12-03T22:08:12+00:00" }, { "name": "symfony/translation", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "aa04dc1c75b7d3da7bd7003104cd0cfc5dff635c" + "reference": "c0e2191e9bed845946ab3d99767513b56ca7dcd6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/aa04dc1c75b7d3da7bd7003104cd0cfc5dff635c", - "reference": "aa04dc1c75b7d3da7bd7003104cd0cfc5dff635c", + "url": "https://api.github.com/repos/symfony/translation/zipball/c0e2191e9bed845946ab3d99767513b56ca7dcd6", + "reference": "c0e2191e9bed845946ab3d99767513b56ca7dcd6", "shasum": "" }, "require": { "php": "^7.1.3", + "symfony/contracts": "^1.0.2", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { @@ -4072,6 +4578,9 @@ "symfony/dependency-injection": "<3.4", "symfony/yaml": "<3.4" }, + "provide": { + "symfony/translation-contracts-implementation": "1.0" + }, "require-dev": { "psr/log": "~1.0", "symfony/config": "~3.4|~4.0", @@ -4089,7 +4598,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -4116,20 +4625,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2018-10-28T18:38:52+00:00" + "time": "2018-12-06T10:45:32+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "60319b45653580b0cdacca499344577d87732f16" + "reference": "db61258540350725f4beb6b84006e32398acd120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/60319b45653580b0cdacca499344577d87732f16", - "reference": "60319b45653580b0cdacca499344577d87732f16", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/db61258540350725f4beb6b84006e32398acd120", + "reference": "db61258540350725f4beb6b84006e32398acd120", "shasum": "" }, "require": { @@ -4157,7 +4666,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -4191,7 +4700,7 @@ "debug", "dump" ], - "time": "2018-10-02T16:36:10+00:00" + "time": "2018-11-25T12:50:42+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -4339,6 +4848,70 @@ "validate" ], "time": "2018-01-29T19:49:41+00:00" + }, + { + "name": "zendframework/zend-diactoros", + "version": "1.8.6", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-diactoros.git", + "reference": "20da13beba0dde8fb648be3cc19765732790f46e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/20da13beba0dde8fb648be3cc19765732790f46e", + "reference": "20da13beba0dde8fb648be3cc19765732790f46e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-dom": "*", + "ext-libxml": "*", + "php-http/psr7-integration-tests": "dev-master", + "phpunit/phpunit": "^5.7.16 || ^6.0.8 || ^7.2.7", + "zendframework/zend-coding-standard": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev", + "dev-develop": "1.9.x-dev", + "dev-release-2.0": "2.0.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php" + ], + "psr-4": { + "Zend\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://github.com/zendframework/zend-diactoros", + "keywords": [ + "http", + "psr", + "psr-7" + ], + "time": "2018-09-05T19:29:37+00:00" } ], "packages-dev": [ @@ -4687,16 +5260,16 @@ }, { "name": "composer/composer", - "version": "1.7.3", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "e965b9aaa8854c3067f1ed2ae45f436572d73eb7" + "reference": "d8aef3af866b28786ce9b8647e52c42496436669" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/e965b9aaa8854c3067f1ed2ae45f436572d73eb7", - "reference": "e965b9aaa8854c3067f1ed2ae45f436572d73eb7", + "url": "https://api.github.com/repos/composer/composer/zipball/d8aef3af866b28786ce9b8647e52c42496436669", + "reference": "d8aef3af866b28786ce9b8647e52c42496436669", "shasum": "" }, "require": { @@ -4732,7 +5305,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.8-dev" } }, "autoload": { @@ -4763,7 +5336,7 @@ "dependency", "package" ], - "time": "2018-11-01T09:05:06+00:00" + "time": "2018-12-03T09:31:16+00:00" }, { "name": "composer/semver", @@ -4890,16 +5463,16 @@ }, { "name": "composer/xdebug-handler", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "b8e9745fb9b06ea6664d8872c4505fb16df4611c" + "reference": "dc523135366eb68f22268d069ea7749486458562" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/b8e9745fb9b06ea6664d8872c4505fb16df4611c", - "reference": "b8e9745fb9b06ea6664d8872c4505fb16df4611c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/dc523135366eb68f22268d069ea7749486458562", + "reference": "dc523135366eb68f22268d069ea7749486458562", "shasum": "" }, "require": { @@ -4930,7 +5503,7 @@ "Xdebug", "performance" ], - "time": "2018-08-31T19:07:57+00:00" + "time": "2018-11-29T10:59:02+00:00" }, { "name": "doctrine/annotations", @@ -5054,6 +5627,66 @@ ], "time": "2017-07-22T11:58:36+00:00" }, + { + "name": "facebook/webdriver", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-webdriver.git", + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bd8c740097eb9f2fc3735250fc1912bc811a954e", + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-zip": "*", + "php": "^5.6 || ~7.0", + "symfony/process": "^2.8 || ^3.1 || ^4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "php-coveralls/php-coveralls": "^2.0", + "php-mock/php-mock-phpunit": "^1.1", + "phpunit/phpunit": "^5.7", + "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", + "squizlabs/php_codesniffer": "^2.6", + "symfony/var-dumper": "^3.3 || ^4.0" + }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-community": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "Facebook\\WebDriver\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "A PHP client for Selenium WebDriver", + "homepage": "https://github.com/facebook/php-webdriver", + "keywords": [ + "facebook", + "php", + "selenium", + "webdriver" + ], + "time": "2018-05-16T17:37:13+00:00" + }, { "name": "filp/whoops", "version": "2.3.1", @@ -5427,6 +6060,120 @@ ], "time": "2018-02-14T22:26:30+00:00" }, + { + "name": "laravel/dusk", + "version": "v3.0.10", + "source": { + "type": "git", + "url": "https://github.com/laravel/dusk.git", + "reference": "8bfb9f01ae09d1d9ca3ce53e36b1f020c0f8dc8f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/dusk/zipball/8bfb9f01ae09d1d9ca3ce53e36b1f020c0f8dc8f", + "reference": "8bfb9f01ae09d1d9ca3ce53e36b1f020c0f8dc8f", + "shasum": "" + }, + "require": { + "facebook/webdriver": "~1.3", + "illuminate/console": "~5.6", + "illuminate/support": "~5.6", + "nesbot/carbon": "~1.20", + "php": ">=7.1.0", + "symfony/console": "~4.0", + "symfony/process": "~4.0" + }, + "require-dev": { + "mockery/mockery": "~1.0", + "phpunit/phpunit": "~7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Dusk\\DuskServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Dusk\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Dusk provides simple end-to-end testing and browser automation.", + "keywords": [ + "laravel", + "testing", + "webdriver" + ], + "time": "2018-08-06T20:22:46+00:00" + }, + { + "name": "martinlindhe/laravel-vue-i18n-generator", + "version": "0.1.35", + "source": { + "type": "git", + "url": "https://github.com/martinlindhe/laravel-vue-i18n-generator.git", + "reference": "55c2d33c0bd3c681f38dc683b6f4ac600b1da557" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/martinlindhe/laravel-vue-i18n-generator/zipball/55c2d33c0bd3c681f38dc683b6f4ac600b1da557", + "reference": "55c2d33c0bd3c681f38dc683b6f4ac600b1da557", + "shasum": "" + }, + "require": { + "illuminate/console": "~5.1.0|~5.2.0|~5.3.0|~5.4.0|~5.5.0|~5.6.0|~5.7.0", + "illuminate/support": "~5.1.0|~5.2.0|~5.3.0|~5.4.0|~5.5.0|~5.6.0|~5.7.0", + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.7" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "MartinLindhe\\VueInternationalizationGenerator\\GeneratorProvider" + ] + } + }, + "autoload": { + "psr-4": { + "MartinLindhe\\VueInternationalizationGenerator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Martin Lindhe", + "email": "martin@ubique.se" + } + ], + "description": "Generates a vue-i18n compatible include file from your Laravel translations.", + "homepage": "http://github.com/martinlindhe/laravel-vue-i18n-generator", + "keywords": [ + "laravel", + "vue-i18n" + ], + "time": "2018-12-07T16:53:14+00:00" + }, { "name": "maximebf/debugbar", "version": "v1.15.0", @@ -6455,16 +7202,16 @@ }, { "name": "phpunit/phpunit", - "version": "7.4.4", + "version": "7.5.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b1be2c8530c4c29c3519a052c9fb6cee55053bbd" + "reference": "c23d78776ad415d5506e0679723cb461d71f488f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b1be2c8530c4c29c3519a052c9fb6cee55053bbd", - "reference": "b1be2c8530c4c29c3519a052c9fb6cee55053bbd", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c23d78776ad415d5506e0679723cb461d71f488f", + "reference": "c23d78776ad415d5506e0679723cb461d71f488f", "shasum": "" }, "require": { @@ -6485,7 +7232,7 @@ "phpunit/php-timer": "^2.0", "sebastian/comparator": "^3.0", "sebastian/diff": "^3.0", - "sebastian/environment": "^3.1 || ^4.0", + "sebastian/environment": "^4.0", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", "sebastian/object-enumerator": "^3.0.3", @@ -6509,7 +7256,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.4-dev" + "dev-master": "7.5-dev" } }, "autoload": { @@ -6535,7 +7282,7 @@ "testing", "xunit" ], - "time": "2018-11-14T16:52:02+00:00" + "time": "2018-12-12T07:20:32+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -7195,16 +7942,16 @@ }, { "name": "symfony/filesystem", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "fd7bd6535beb1f0a0a9e3ee960666d0598546981" + "reference": "2f4c8b999b3b7cadb2a69390b01af70886753710" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/fd7bd6535beb1f0a0a9e3ee960666d0598546981", - "reference": "fd7bd6535beb1f0a0a9e3ee960666d0598546981", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/2f4c8b999b3b7cadb2a69390b01af70886753710", + "reference": "2f4c8b999b3b7cadb2a69390b01af70886753710", "shasum": "" }, "require": { @@ -7214,7 +7961,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -7241,20 +7988,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-10-30T13:18:25+00:00" + "time": "2018-11-11T19:52:12+00:00" }, { "name": "symfony/options-resolver", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "40f0e40d37c1c8a762334618dea597d64bbb75ff" + "reference": "a9c38e8a3da2c03b3e71fdffa6efb0bda51390ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/40f0e40d37c1c8a762334618dea597d64bbb75ff", - "reference": "40f0e40d37c1c8a762334618dea597d64bbb75ff", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a9c38e8a3da2c03b3e71fdffa6efb0bda51390ba", + "reference": "a9c38e8a3da2c03b3e71fdffa6efb0bda51390ba", "shasum": "" }, "require": { @@ -7263,7 +8010,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -7295,7 +8042,7 @@ "configuration", "options" ], - "time": "2018-09-18T12:45:12+00:00" + "time": "2018-11-11T19:52:12+00:00" }, { "name": "symfony/polyfill-php70", @@ -7358,25 +8105,26 @@ }, { "name": "symfony/stopwatch", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "5bfc064125b73ff81229e19381ce1c34d3416f4b" + "reference": "ec076716412274e51f8a7ea675d9515e5c311123" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5bfc064125b73ff81229e19381ce1c34d3416f4b", - "reference": "5bfc064125b73ff81229e19381ce1c34d3416f4b", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/ec076716412274e51f8a7ea675d9515e5c311123", + "reference": "ec076716412274e51f8a7ea675d9515e5c311123", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.1.3", + "symfony/contracts": "^1.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -7403,20 +8151,20 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:40:59+00:00" + "time": "2018-11-11T19:52:12+00:00" }, { "name": "symfony/yaml", - "version": "v4.1.7", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "367e689b2fdc19965be435337b50bc8adf2746c9" + "reference": "c41175c801e3edfda90f32e292619d10c27103d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/367e689b2fdc19965be435337b50bc8adf2746c9", - "reference": "367e689b2fdc19965be435337b50bc8adf2746c9", + "url": "https://api.github.com/repos/symfony/yaml/zipball/c41175c801e3edfda90f32e292619d10c27103d7", + "reference": "c41175c801e3edfda90f32e292619d10c27103d7", "shasum": "" }, "require": { @@ -7435,7 +8183,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -7462,7 +8210,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-10-02T16:36:10+00:00" + "time": "2018-11-11T19:52:12+00:00" }, { "name": "theseer/tokenizer", @@ -7503,6 +8251,57 @@ ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "time": "2017-04-07T12:08:54+00:00" + }, + { + "name": "tightenco/ziggy", + "version": "v0.5.0", + "source": { + "type": "git", + "url": "https://github.com/tightenco/ziggy.git", + "reference": "a289378d08ee16f573140820eae002cd1616e9ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tightenco/ziggy/zipball/a289378d08ee16f573140820eae002cd1616e9ec", + "reference": "a289378d08ee16f573140820eae002cd1616e9ec", + "shasum": "" + }, + "require": { + "laravel/framework": "^5.4.29" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "orchestra/testbench": "~3.4" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Tightenco\\Ziggy\\ZiggyServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Tightenco\\Ziggy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Stauffer", + "email": "matt@tighten.co" + }, + { + "name": "Daniel Coulbourne", + "email": "daniel@tighten.co" + } + ], + "description": "Generates a Blade directive exporting all of your named Laravel routes. Also provides a nice route() helper function in JavaScript.", + "time": "2017-10-30T07:55:42+00:00" } ], "aliases": [], diff --git a/config/session.php b/config/session.php index 4f3a2e6d..2007acb2 100644 --- a/config/session.php +++ b/config/session.php @@ -28,7 +28,7 @@ return [ | */ - 'lifetime' => env('SESSION_LIFETIME', 10080), + 'lifetime' => env('SESSION_LIFETIME', 720), 'expire_on_close' => false, diff --git a/config/vue-i18n-generator.php b/config/vue-i18n-generator.php new file mode 100644 index 00000000..92a20fd7 --- /dev/null +++ b/config/vue-i18n-generator.php @@ -0,0 +1,50 @@ + '/resources/lang', + + /* + |-------------------------------------------------------------------------- + | Laravel translation files + |-------------------------------------------------------------------------- + | + | You can choose which translation files to be generated. + | Note: leave this empty for all the translation files to be generated. + | + */ + + 'langFiles' => [], + + /* + |-------------------------------------------------------------------------- + | Output file + |-------------------------------------------------------------------------- + | + | The javascript path where I will place the generated file. + | Note: the path will be prepended to point to the App directory. + | + */ + 'jsPath' => '/resources/lang/i18n', + 'jsFile' => '/resources/lang/locales.js', + + /* + |-------------------------------------------------------------------------- + | i18n library + |-------------------------------------------------------------------------- + | + | Specify the library you use for localization. + | Options are vue-i18n or vuex-i18n. + | + */ + 'i18nLib' => 'vuex-i18n', +]; diff --git a/package.json b/package.json index 2a969740..2ffaa935 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,73 @@ { - "name": "pterodactyl-panel", - "devDependencies": { - "babel-cli": "6.18.0", - "babel-plugin-transform-strict-mode": "^6.18.0", - "babel-preset-es2015": "6.18.0" - }, - "scripts": { - "build": "./node_modules/babel-cli/bin/babel.js public/themes/pterodactyl/js/frontend/files/src --source-maps --out-file public/themes/pterodactyl/js/frontend/files/filemanager.min.js" - } + "name": "pterodactyl-panel", + "dependencies": { + "axios": "^0.18.0", + "date-fns": "^1.29.0", + "feather-icons": "^4.10.0", + "jquery": "^3.3.1", + "lodash": "^4.17.11", + "socket.io-client": "^2.2.0", + "vee-validate": "^2.1.7", + "vue": "^2.6.4", + "vue-axios": "^2.1.1", + "vue-i18n": "^8.6.0", + "vue-router": "^3.0.1", + "vuex": "^3.0.1", + "vuex-router-sync": "^5.0.0", + "ws-wrapper": "^2.0.0", + "xterm": "^3.5.1" + }, + "devDependencies": { + "@babel/cli": "^7.2.3", + "@babel/core": "^7.2.2", + "@babel/plugin-proposal-class-properties": "^7.3.0", + "@babel/plugin-proposal-object-rest-spread": "^7.3.1", + "@babel/preset-env": "^7.3.1", + "@types/feather-icons": "^4.7.0", + "@types/lodash": "^4.14.119", + "@types/node": "^10.12.15", + "@types/socket.io-client": "^1.4.32", + "@types/webpack-env": "^1.13.6", + "babel-loader": "^8.0.5", + "clean-webpack-plugin": "^0.1.19", + "css-loader": "^2.1.0", + "cssnano": "^4.0.3", + "fork-ts-checker-webpack-plugin": "^0.5.2", + "glob-all": "^3.1.0", + "html-webpack-plugin": "^3.2.0", + "mini-css-extract-plugin": "^0.5.0", + "postcss": "^6.0.21", + "postcss-import": "^11.1.0", + "postcss-loader": "^3.0.0", + "postcss-preset-env": "^3.4.0", + "precss": "^3.1.2", + "purgecss-webpack-plugin": "^1.1.0", + "resolve-url-loader": "^3.0.0", + "style-loader": "^0.23.1", + "tailwindcss": "^0.7.4", + "ts-loader": "^5.3.3", + "typescript": "^3.3.1", + "uglifyjs-webpack-plugin": "^2.1.1", + "vue-devtools": "^3.1.9", + "vue-feather-icons": "^4.7.1", + "vue-loader": "^15.6.2", + "vue-mc": "^0.2.4", + "vue-template-compiler": "^2.6.4", + "vueify-insert-css": "^1.0.0", + "webpack": "^4.29.0", + "webpack-assets-manifest": "^3.1.1", + "webpack-cli": "^3.0.2", + "webpack-dev-server": "^3.1.14", + "webpack-manifest-plugin": "^2.0.3", + "webpack-shell-plugin": "^0.5.0", + "webpack-stream": "^4.0.3" + }, + "scripts": { + "watch": "NODE_ENV=development ./node_modules/.bin/webpack --watch --progress", + "build": "NODE_ENV=development ./node_modules/.bin/webpack --progress", + "build:production": "NODE_ENV=production ./node_modules/.bin/webpack", + "serve": "NODE_ENV=development webpack-dev-server --host 0.0.0.0 --hot", + "v:serve": "PUBLIC_PATH=http://pterodactyl.test:8080 yarn run serve", + "compile:assets": "php artisan vue-i18n:generate & php artisan ziggy:generate resources/assets/scripts/helpers/ziggy.js" + } } diff --git a/phpunit.dusk.xml b/phpunit.dusk.xml new file mode 100644 index 00000000..60392c93 --- /dev/null +++ b/phpunit.dusk.xml @@ -0,0 +1,21 @@ + + + + + ./tests/Browser + + + + + ./app + + + diff --git a/phpunit.xml b/phpunit.xml index c0a7cf83..e4e18e41 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -10,6 +10,9 @@ processIsolation="false" stopOnFailure="false"> + + ./tests/Browser/Processes + ./tests/Integration diff --git a/public/favicons/android-icon-144x144.png b/public/favicons/android-icon-144x144.png new file mode 100644 index 00000000..7e98c1c3 Binary files /dev/null and b/public/favicons/android-icon-144x144.png differ diff --git a/public/favicons/android-icon-192x192.png b/public/favicons/android-icon-192x192.png new file mode 100644 index 00000000..80ce4d33 Binary files /dev/null and b/public/favicons/android-icon-192x192.png differ diff --git a/public/favicons/android-icon-36x36.png b/public/favicons/android-icon-36x36.png new file mode 100644 index 00000000..729e2126 Binary files /dev/null and b/public/favicons/android-icon-36x36.png differ diff --git a/public/favicons/android-icon-48x48.png b/public/favicons/android-icon-48x48.png new file mode 100644 index 00000000..9e5fe265 Binary files /dev/null and b/public/favicons/android-icon-48x48.png differ diff --git a/public/favicons/android-icon-72x72.png b/public/favicons/android-icon-72x72.png new file mode 100644 index 00000000..e6bb769c Binary files /dev/null and b/public/favicons/android-icon-72x72.png differ diff --git a/public/favicons/android-icon-96x96.png b/public/favicons/android-icon-96x96.png new file mode 100644 index 00000000..f9b8fbef Binary files /dev/null and b/public/favicons/android-icon-96x96.png differ diff --git a/public/favicons/apple-icon-114x114.png b/public/favicons/apple-icon-114x114.png new file mode 100644 index 00000000..3920011b Binary files /dev/null and b/public/favicons/apple-icon-114x114.png differ diff --git a/public/favicons/apple-icon-120x120.png b/public/favicons/apple-icon-120x120.png new file mode 100644 index 00000000..81b72ba8 Binary files /dev/null and b/public/favicons/apple-icon-120x120.png differ diff --git a/public/favicons/apple-icon-144x144.png b/public/favicons/apple-icon-144x144.png new file mode 100644 index 00000000..7e98c1c3 Binary files /dev/null and b/public/favicons/apple-icon-144x144.png differ diff --git a/public/favicons/apple-icon-152x152.png b/public/favicons/apple-icon-152x152.png new file mode 100644 index 00000000..6623bd58 Binary files /dev/null and b/public/favicons/apple-icon-152x152.png differ diff --git a/public/favicons/apple-icon-180x180.png b/public/favicons/apple-icon-180x180.png new file mode 100644 index 00000000..0503d522 Binary files /dev/null and b/public/favicons/apple-icon-180x180.png differ diff --git a/public/favicons/apple-icon-57x57.png b/public/favicons/apple-icon-57x57.png new file mode 100644 index 00000000..466878ee Binary files /dev/null and b/public/favicons/apple-icon-57x57.png differ diff --git a/public/favicons/apple-icon-60x60.png b/public/favicons/apple-icon-60x60.png new file mode 100644 index 00000000..09a79d99 Binary files /dev/null and b/public/favicons/apple-icon-60x60.png differ diff --git a/public/favicons/apple-icon-72x72.png b/public/favicons/apple-icon-72x72.png new file mode 100644 index 00000000..e6bb769c Binary files /dev/null and b/public/favicons/apple-icon-72x72.png differ diff --git a/public/favicons/apple-icon-76x76.png b/public/favicons/apple-icon-76x76.png new file mode 100644 index 00000000..f656479b Binary files /dev/null and b/public/favicons/apple-icon-76x76.png differ diff --git a/public/favicons/apple-icon-precomposed.png b/public/favicons/apple-icon-precomposed.png new file mode 100644 index 00000000..277e51bf Binary files /dev/null and b/public/favicons/apple-icon-precomposed.png differ diff --git a/public/favicons/apple-icon.png b/public/favicons/apple-icon.png new file mode 100644 index 00000000..277e51bf Binary files /dev/null and b/public/favicons/apple-icon.png differ diff --git a/public/favicons/browserconfig.xml b/public/favicons/browserconfig.xml index e3cb776e..c5541482 100644 --- a/public/favicons/browserconfig.xml +++ b/public/favicons/browserconfig.xml @@ -1,9 +1,2 @@ - - - - - #165ed4 - - - +#ffffff \ No newline at end of file diff --git a/public/favicons/df4b367461890fa5fd0d9339d3c3f9c6.ico.zip b/public/favicons/df4b367461890fa5fd0d9339d3c3f9c6.ico.zip new file mode 100644 index 00000000..8d2efae0 Binary files /dev/null and b/public/favicons/df4b367461890fa5fd0d9339d3c3f9c6.ico.zip differ diff --git a/public/favicons/favicon-16x16.png b/public/favicons/favicon-16x16.png index d568bd20..9597c6f3 100644 Binary files a/public/favicons/favicon-16x16.png and b/public/favicons/favicon-16x16.png differ diff --git a/public/favicons/favicon-32x32.png b/public/favicons/favicon-32x32.png index edfd1340..737917e1 100644 Binary files a/public/favicons/favicon-32x32.png and b/public/favicons/favicon-32x32.png differ diff --git a/public/favicons/favicon-96x96.png b/public/favicons/favicon-96x96.png new file mode 100644 index 00000000..f9b8fbef Binary files /dev/null and b/public/favicons/favicon-96x96.png differ diff --git a/public/favicons/favicon.ico b/public/favicons/favicon.ico index 99e5bffe..bc222883 100644 Binary files a/public/favicons/favicon.ico and b/public/favicons/favicon.ico differ diff --git a/public/favicons/manifest.json b/public/favicons/manifest.json index 796d1ff0..013d4a6a 100644 --- a/public/favicons/manifest.json +++ b/public/favicons/manifest.json @@ -1,18 +1,41 @@ { - "name": "", - "icons": [ - { - "src": "favicons/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "favicons/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" + "name": "App", + "icons": [ + { + "src": "\/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "\/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "\/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "\/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "\/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "\/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] } \ No newline at end of file diff --git a/public/favicons/ms-icon-144x144.png b/public/favicons/ms-icon-144x144.png new file mode 100644 index 00000000..7e98c1c3 Binary files /dev/null and b/public/favicons/ms-icon-144x144.png differ diff --git a/public/favicons/ms-icon-150x150.png b/public/favicons/ms-icon-150x150.png new file mode 100644 index 00000000..cdd392c8 Binary files /dev/null and b/public/favicons/ms-icon-150x150.png differ diff --git a/public/favicons/ms-icon-310x310.png b/public/favicons/ms-icon-310x310.png new file mode 100644 index 00000000..7b84fc12 Binary files /dev/null and b/public/favicons/ms-icon-310x310.png differ diff --git a/public/favicons/ms-icon-70x70.png b/public/favicons/ms-icon-70x70.png new file mode 100644 index 00000000..383bb767 Binary files /dev/null and b/public/favicons/ms-icon-70x70.png differ diff --git a/public/themes/pterodactyl/js/frontend/console.js b/public/themes/pterodactyl/js/frontend/console.js index 8943da42..41a3d716 100644 --- a/public/themes/pterodactyl/js/frontend/console.js +++ b/public/themes/pterodactyl/js/frontend/console.js @@ -65,7 +65,7 @@ $(document).ready(function () { if (e.which === 13) { saveToHistory($(this).val()); - Socket.emit((ConsoleServerStatus !== 0) ? 'send command' : 'set status', $(this).val()); + Socket.emit((ConsoleServerStatus !== 0) ? 'send command' : 'set state', $(this).val()); $(this).val(''); } @@ -233,7 +233,7 @@ function updateServerPowerControls (data) { $(document).ready(function () { $('[data-attr="power"]').click(function (event) { if (! $(this).hasClass('disabled')) { - Socket.emit('set status', $(this).data('action')); + Socket.emit('set state', $(this).data('action')); } }); diff --git a/resources/assets/index.html b/resources/assets/index.html new file mode 100644 index 00000000..2d007694 --- /dev/null +++ b/resources/assets/index.html @@ -0,0 +1,18 @@ + + + Pterodactyl Dev + + + + + + +
+ +
+

+

+
+
+ + diff --git a/resources/assets/scripts/api/http.ts b/resources/assets/scripts/api/http.ts new file mode 100644 index 00000000..36749bb5 --- /dev/null +++ b/resources/assets/scripts/api/http.ts @@ -0,0 +1,40 @@ +import axios, {AxiosInstance, AxiosRequestConfig} from 'axios'; +import {ServerApplicationCredentials} from "@/store/types"; + +// This token is set in the bootstrap.js file at the beginning of the request +// and is carried through from there. +// const token: string = ''; + +const http: AxiosInstance = axios.create({ + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, +}); + +// If we have a phpdebugbar instance registered at this point in time go +// ahead and route the response data through to it so things show up. +// @ts-ignore +if (typeof window.phpdebugbar !== 'undefined') { + http.interceptors.response.use(response => { + // @ts-ignore + window.phpdebugbar.ajaxHandler.handle(response.request); + + return response; + }); +} + +export default http; + +/** + * Creates a request object for the node that uses the server UUID and connection + * credentials. Basically just a tiny wrapper to set this quickly. + */ +export function withCredentials(server: string, credentials: ServerApplicationCredentials): AxiosInstance { + http.defaults.baseURL = credentials.node; + http.defaults.headers['X-Access-Server'] = server; + http.defaults.headers['X-Access-Token'] = credentials.key; + + return http; +} diff --git a/resources/assets/scripts/api/server/createDatabase.ts b/resources/assets/scripts/api/server/createDatabase.ts new file mode 100644 index 00000000..927a328b --- /dev/null +++ b/resources/assets/scripts/api/server/createDatabase.ts @@ -0,0 +1,30 @@ +import http from '@/api/http'; +// @ts-ignore +import route from '../../../../../vendor/tightenco/ziggy/src/js/route'; +import {AxiosError} from "axios"; +import {ServerDatabase} from "@/api/server/types"; + +/** + * Creates a new database on the system for the currently active server. + */ +export function createDatabase(server: string, database: string, remote: string): Promise { + return new Promise((resolve, reject) => { + http.post(route('api.client.servers.databases', {server}), {database, remote}) + .then(response => { + const copy: any = response.data.attributes; + copy.password = copy.relationships.password.attributes.password; + copy.showPassword = false; + + delete copy.relationships; + + resolve(copy); + }) + .catch((err: AxiosError) => { + if (err.response && err.response.data && Array.isArray(err.response.data.errors)) { + return reject(err.response.data.errors[0].detail); + } + + return reject(err); + }); + }); +} diff --git a/resources/assets/scripts/api/server/files/copyElement.ts b/resources/assets/scripts/api/server/files/copyElement.ts new file mode 100644 index 00000000..a65c50c2 --- /dev/null +++ b/resources/assets/scripts/api/server/files/copyElement.ts @@ -0,0 +1,29 @@ +import {withCredentials} from "@/api/http"; +import {ServerApplicationCredentials} from "@/store/types"; + +type PathChangeObject = { + currentPath: string, + newPath: string, +} +/** + * Creates a copy of the given file or directory on the Daemon. Expects a fully resolved path + * to be passed through for both data arguments. + */ +export function copyElement(server: string, credentials: ServerApplicationCredentials, data: PathChangeObject, isMove = false): Promise { + return new Promise((resolve, reject) => { + withCredentials(server, credentials).post(`/v1/server/file/${isMove ? 'move' : 'copy'}`, { + from: data.currentPath, + to: data.newPath, + }) + .then(() => resolve()) + .catch(reject); + }); +} + +/** + * Moves a file or folder to a new location on the server. Works almost exactly the same as the copy + * file logic, so it really just passes an extra argument to copy to indicate that it is a move. + */ +export function moveElement(server: string, credentials: ServerApplicationCredentials, data: PathChangeObject): Promise { + return copyElement(server, credentials, data, true); +} diff --git a/resources/assets/scripts/api/server/files/createFolder.ts b/resources/assets/scripts/api/server/files/createFolder.ts new file mode 100644 index 00000000..f28f7d3e --- /dev/null +++ b/resources/assets/scripts/api/server/files/createFolder.ts @@ -0,0 +1,13 @@ +import {ServerApplicationCredentials} from "@/store/types"; +import {withCredentials} from "@/api/http"; + +/** + * Connects to the remote daemon and creates a new folder on the server. + */ +export function createFolder(server: string, credentials: ServerApplicationCredentials, path: string): Promise { + return new Promise((resolve, reject) => { + withCredentials(server, credentials).post('/v1/server/file/folder', { path }) + .then(() => resolve()) + .catch(reject); + }); +} diff --git a/resources/assets/scripts/api/server/files/deleteElement.ts b/resources/assets/scripts/api/server/files/deleteElement.ts new file mode 100644 index 00000000..6cb85139 --- /dev/null +++ b/resources/assets/scripts/api/server/files/deleteElement.ts @@ -0,0 +1,14 @@ +import {withCredentials} from "@/api/http"; +import {ServerApplicationCredentials} from "@/store/types"; + +/** + * Deletes files and/or folders from the server. You should pass through an array of + * file or folder paths to be deleted. + */ +export function deleteElement(server: string, credentials: ServerApplicationCredentials, items: Array): Promise { + return new Promise((resolve, reject) => { + withCredentials(server, credentials).post('/v1/server/file/delete', { items }) + .then(() => resolve()) + .catch(reject); + }) +} diff --git a/resources/assets/scripts/api/server/files/getDownloadToken.ts b/resources/assets/scripts/api/server/files/getDownloadToken.ts new file mode 100644 index 00000000..4e784195 --- /dev/null +++ b/resources/assets/scripts/api/server/files/getDownloadToken.ts @@ -0,0 +1,14 @@ +import http from "@/api/http"; +// @ts-ignore +import route from '../../../../../../vendor/tightenco/ziggy/src/js/route'; + +/** + * Gets a download token for a file on the server. + */ +export function getDownloadToken(server: string, file: string): Promise { + return new Promise((resolve, reject) => { + http.post(route('api.client.servers.files.download', { server, file })) + .then(response => resolve(response.data ? response.data.token || null : null)) + .catch(reject); + }); +} diff --git a/resources/assets/scripts/api/server/files/renameElement.ts b/resources/assets/scripts/api/server/files/renameElement.ts new file mode 100644 index 00000000..efd991b1 --- /dev/null +++ b/resources/assets/scripts/api/server/files/renameElement.ts @@ -0,0 +1,23 @@ +import {withCredentials} from "@/api/http"; +import {ServerApplicationCredentials} from "@/store/types"; +import { join } from 'path'; + +type RenameObject = { + path: string, + fromName: string, + toName: string, +} + +/** + * Renames a file or folder on the server using the node. + */ +export function renameElement(server: string, credentials: ServerApplicationCredentials, data: RenameObject): Promise { + return new Promise((resolve, reject) => { + withCredentials(server, credentials).post('/v1/server/file/rename', { + from: join(data.path, data.fromName), + to: join(data.path, data.toName), + }) + .then(() => resolve()) + .catch(reject); + }); +} diff --git a/resources/assets/scripts/api/server/getDirectoryContents.ts b/resources/assets/scripts/api/server/getDirectoryContents.ts new file mode 100644 index 00000000..6138fd62 --- /dev/null +++ b/resources/assets/scripts/api/server/getDirectoryContents.ts @@ -0,0 +1,40 @@ +import http from '../http'; +import {filter, isObject} from 'lodash'; +import {DirectoryContentObject, DirectoryContents} from "./types"; + +/** + * Get the contents of a specific directory for a given server. + */ +export function getDirectoryContents(server: string, directory: string): Promise { + return new Promise((resolve, reject) => { + http.get(`/api/client/servers/${server}/files/list`, { + params: {directory} + }) + .then((response) => { + return resolve({ + files: filter(response.data.contents, function (o: DirectoryContentObject) { + return o.file; + }), + directories: filter(response.data.contents, function (o: DirectoryContentObject) { + return o.directory; + }), + editable: response.data.editable, + }); + }) + .catch(err => { + if (err.response && err.response.status === 404) { + return reject('The directory you requested could not be located on the server'); + } + + if (err.response.data && isObject(err.response.data.errors)) { + err.response.data.errors.forEach((error: any) => { + return reject(error.detail); + }); + } + + return reject(err); + }); + }); +} + +export default getDirectoryContents; diff --git a/resources/assets/scripts/api/server/types.ts b/resources/assets/scripts/api/server/types.ts new file mode 100644 index 00000000..30015389 --- /dev/null +++ b/resources/assets/scripts/api/server/types.ts @@ -0,0 +1,30 @@ +export type DirectoryContents = { + files: Array, + directories: Array, + editable: Array +} + +export type DirectoryContentObject = { + name: string, + created: string, + modified: string, + mode: string, + size: number, + directory: boolean, + file: boolean, + symlink: boolean, + mime: string, +} + +export type ServerDatabase = { + id: string, + name: string, + connections_from: string, + username: string, + host: { + address: string, + port: number, + }, + password: string, + showPassword: boolean, +} diff --git a/resources/assets/scripts/app.ts b/resources/assets/scripts/app.ts new file mode 100644 index 00000000..147e312d --- /dev/null +++ b/resources/assets/scripts/app.ts @@ -0,0 +1,41 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import VueI18n from 'vue-i18n'; +import VueRouter from 'vue-router'; +import VeeValidate from 'vee-validate'; +// Helpers +// @ts-ignore +import {Ziggy} from './helpers/ziggy'; +// @ts-ignore +import Locales from './../../../resources/lang/locales'; + +import {FlashMixin} from './mixins/flash'; +import store from './store/index'; +import router from './router'; + +Vue.config.productionTip = false; +require('./bootstrap'); + +window.events = new Vue(); +window.Ziggy = Ziggy; + +Vue.use(Vuex); +Vue.use(VueRouter); +Vue.use(VeeValidate); +Vue.use(VueI18n); + +const route = require('./../../../vendor/tightenco/ziggy/src/js/route').default; + +Vue.mixin({methods: {route}}); +Vue.mixin(FlashMixin); + +const i18n = new VueI18n({ + locale: 'en', + messages: {...Locales}, +}); + +if (module.hot) { + module.hot.accept(); +} + +new Vue({store, router, i18n}).$mount('#pterodactyl'); diff --git a/resources/assets/scripts/bootstrap.ts b/resources/assets/scripts/bootstrap.ts new file mode 100644 index 00000000..905ad5fa --- /dev/null +++ b/resources/assets/scripts/bootstrap.ts @@ -0,0 +1,33 @@ +import axios from './api/http'; + +window._ = require('lodash'); + +/** + * We'll load jQuery and the Bootstrap jQuery plugin which provides support + * for JavaScript based Bootstrap features such as modals and tabs. This + * code may be modified to fit the specific needs of your application. + */ + +try { + window.$ = window.jQuery = require('jquery'); +} catch (e) { +} + +window.axios = axios; + +/** + * Next we will register the CSRF Token as a common header with Axios so that + * all outgoing HTTP requests automatically have it attached. This is just + * a simple convenience so we don't have to attach every token manually. + */ + +let token = document.head.querySelector('meta[name="csrf-token"]'); + +if (token) { + // @ts-ignore + window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content; + // @ts-ignore + window.X_CSRF_TOKEN = token.content; +} else { + console.error('CSRF token not found in document.'); +} diff --git a/resources/assets/scripts/components/Flash.vue b/resources/assets/scripts/components/Flash.vue new file mode 100644 index 00000000..fad2821e --- /dev/null +++ b/resources/assets/scripts/components/Flash.vue @@ -0,0 +1,103 @@ + + + diff --git a/resources/assets/scripts/components/MessageBox.vue b/resources/assets/scripts/components/MessageBox.vue new file mode 100644 index 00000000..02a07aa2 --- /dev/null +++ b/resources/assets/scripts/components/MessageBox.vue @@ -0,0 +1,18 @@ + + + diff --git a/resources/assets/scripts/components/auth/ForgotPassword.vue b/resources/assets/scripts/components/auth/ForgotPassword.vue new file mode 100644 index 00000000..8489c0ec --- /dev/null +++ b/resources/assets/scripts/components/auth/ForgotPassword.vue @@ -0,0 +1,98 @@ + + + diff --git a/resources/assets/scripts/components/auth/Login.vue b/resources/assets/scripts/components/auth/Login.vue new file mode 100644 index 00000000..9ce85b1e --- /dev/null +++ b/resources/assets/scripts/components/auth/Login.vue @@ -0,0 +1,18 @@ + + + diff --git a/resources/assets/scripts/components/auth/LoginForm.vue b/resources/assets/scripts/components/auth/LoginForm.vue new file mode 100644 index 00000000..b021a391 --- /dev/null +++ b/resources/assets/scripts/components/auth/LoginForm.vue @@ -0,0 +1,104 @@ + + + diff --git a/resources/assets/scripts/components/auth/ResetPassword.vue b/resources/assets/scripts/components/auth/ResetPassword.vue new file mode 100644 index 00000000..4a41e365 --- /dev/null +++ b/resources/assets/scripts/components/auth/ResetPassword.vue @@ -0,0 +1,128 @@ + + + diff --git a/resources/assets/scripts/components/auth/TwoFactorForm.vue b/resources/assets/scripts/components/auth/TwoFactorForm.vue new file mode 100644 index 00000000..24823529 --- /dev/null +++ b/resources/assets/scripts/components/auth/TwoFactorForm.vue @@ -0,0 +1,87 @@ + + + diff --git a/resources/assets/scripts/components/core/Icon.vue b/resources/assets/scripts/components/core/Icon.vue new file mode 100644 index 00000000..6b928d06 --- /dev/null +++ b/resources/assets/scripts/components/core/Icon.vue @@ -0,0 +1,18 @@ + + + diff --git a/resources/assets/scripts/components/core/Modal.vue b/resources/assets/scripts/components/core/Modal.vue new file mode 100644 index 00000000..f83ad756 --- /dev/null +++ b/resources/assets/scripts/components/core/Modal.vue @@ -0,0 +1,52 @@ + + + diff --git a/resources/assets/scripts/components/core/Navigation.vue b/resources/assets/scripts/components/core/Navigation.vue new file mode 100644 index 00000000..0942afc9 --- /dev/null +++ b/resources/assets/scripts/components/core/Navigation.vue @@ -0,0 +1,142 @@ + + + diff --git a/resources/assets/scripts/components/core/SpinnerModal.vue b/resources/assets/scripts/components/core/SpinnerModal.vue new file mode 100644 index 00000000..d5ebd8bd --- /dev/null +++ b/resources/assets/scripts/components/core/SpinnerModal.vue @@ -0,0 +1,24 @@ + + + diff --git a/resources/assets/scripts/components/dashboard/Account.vue b/resources/assets/scripts/components/dashboard/Account.vue new file mode 100644 index 00000000..3fd420f0 --- /dev/null +++ b/resources/assets/scripts/components/dashboard/Account.vue @@ -0,0 +1,62 @@ + + + diff --git a/resources/assets/scripts/components/dashboard/Dashboard.vue b/resources/assets/scripts/components/dashboard/Dashboard.vue new file mode 100644 index 00000000..3c1c174c --- /dev/null +++ b/resources/assets/scripts/components/dashboard/Dashboard.vue @@ -0,0 +1,128 @@ + + + diff --git a/resources/assets/scripts/components/dashboard/ServerBox.vue b/resources/assets/scripts/components/dashboard/ServerBox.vue new file mode 100644 index 00000000..5aeca1f4 --- /dev/null +++ b/resources/assets/scripts/components/dashboard/ServerBox.vue @@ -0,0 +1,200 @@ + + + diff --git a/resources/assets/scripts/components/dashboard/account/ChangePassword.vue b/resources/assets/scripts/components/dashboard/account/ChangePassword.vue new file mode 100644 index 00000000..a544749a --- /dev/null +++ b/resources/assets/scripts/components/dashboard/account/ChangePassword.vue @@ -0,0 +1,94 @@ + + + diff --git a/resources/assets/scripts/components/dashboard/account/TwoFactorAuthentication.vue b/resources/assets/scripts/components/dashboard/account/TwoFactorAuthentication.vue new file mode 100644 index 00000000..ed4e5c46 --- /dev/null +++ b/resources/assets/scripts/components/dashboard/account/TwoFactorAuthentication.vue @@ -0,0 +1,193 @@ + + + diff --git a/resources/assets/scripts/components/dashboard/account/UpdateEmail.vue b/resources/assets/scripts/components/dashboard/account/UpdateEmail.vue new file mode 100644 index 00000000..815a0969 --- /dev/null +++ b/resources/assets/scripts/components/dashboard/account/UpdateEmail.vue @@ -0,0 +1,80 @@ + + + diff --git a/resources/assets/scripts/components/forms/CSRF.vue b/resources/assets/scripts/components/forms/CSRF.vue new file mode 100644 index 00000000..f0e830f0 --- /dev/null +++ b/resources/assets/scripts/components/forms/CSRF.vue @@ -0,0 +1,16 @@ + + + diff --git a/resources/assets/scripts/components/server/Server.vue b/resources/assets/scripts/components/server/Server.vue new file mode 100644 index 00000000..30b66a34 --- /dev/null +++ b/resources/assets/scripts/components/server/Server.vue @@ -0,0 +1,126 @@ + + + diff --git a/resources/assets/scripts/components/server/components/PowerButtons.vue b/resources/assets/scripts/components/server/components/PowerButtons.vue new file mode 100644 index 00000000..131c332e --- /dev/null +++ b/resources/assets/scripts/components/server/components/PowerButtons.vue @@ -0,0 +1,52 @@ + + + diff --git a/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.vue b/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.vue new file mode 100644 index 00000000..a3dbcdac --- /dev/null +++ b/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.vue @@ -0,0 +1,89 @@ + + + diff --git a/resources/assets/scripts/components/server/components/database/DatabaseRow.vue b/resources/assets/scripts/components/server/components/database/DatabaseRow.vue new file mode 100644 index 00000000..3a8f87ac --- /dev/null +++ b/resources/assets/scripts/components/server/components/database/DatabaseRow.vue @@ -0,0 +1,70 @@ + + + diff --git a/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.vue b/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.vue new file mode 100644 index 00000000..728cedc2 --- /dev/null +++ b/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.vue @@ -0,0 +1,109 @@ + + + diff --git a/resources/assets/scripts/components/server/components/filemanager/FileContextMenu.vue b/resources/assets/scripts/components/server/components/filemanager/FileContextMenu.vue new file mode 100644 index 00000000..cb541d33 --- /dev/null +++ b/resources/assets/scripts/components/server/components/filemanager/FileContextMenu.vue @@ -0,0 +1,81 @@ + + + diff --git a/resources/assets/scripts/components/server/components/filemanager/FileRow.vue b/resources/assets/scripts/components/server/components/filemanager/FileRow.vue new file mode 100644 index 00000000..6a069d7f --- /dev/null +++ b/resources/assets/scripts/components/server/components/filemanager/FileRow.vue @@ -0,0 +1,182 @@ + + + diff --git a/resources/assets/scripts/components/server/components/filemanager/modals/CopyFileModal.vue b/resources/assets/scripts/components/server/components/filemanager/modals/CopyFileModal.vue new file mode 100644 index 00000000..b8465656 --- /dev/null +++ b/resources/assets/scripts/components/server/components/filemanager/modals/CopyFileModal.vue @@ -0,0 +1,58 @@ + + + diff --git a/resources/assets/scripts/components/server/components/filemanager/modals/CreateFolderModal.vue b/resources/assets/scripts/components/server/components/filemanager/modals/CreateFolderModal.vue new file mode 100644 index 00000000..865b7d0a --- /dev/null +++ b/resources/assets/scripts/components/server/components/filemanager/modals/CreateFolderModal.vue @@ -0,0 +1,103 @@ + + + diff --git a/resources/assets/scripts/components/server/components/filemanager/modals/DeleteFileModal.vue b/resources/assets/scripts/components/server/components/filemanager/modals/DeleteFileModal.vue new file mode 100644 index 00000000..ac161721 --- /dev/null +++ b/resources/assets/scripts/components/server/components/filemanager/modals/DeleteFileModal.vue @@ -0,0 +1,91 @@ + + + diff --git a/resources/assets/scripts/components/server/components/filemanager/modals/DownloadFileModal.vue b/resources/assets/scripts/components/server/components/filemanager/modals/DownloadFileModal.vue new file mode 100644 index 00000000..a669f45a --- /dev/null +++ b/resources/assets/scripts/components/server/components/filemanager/modals/DownloadFileModal.vue @@ -0,0 +1,50 @@ + + + diff --git a/resources/assets/scripts/components/server/components/filemanager/modals/MoveFileModal.vue b/resources/assets/scripts/components/server/components/filemanager/modals/MoveFileModal.vue new file mode 100644 index 00000000..e64f6334 --- /dev/null +++ b/resources/assets/scripts/components/server/components/filemanager/modals/MoveFileModal.vue @@ -0,0 +1,130 @@ + + + diff --git a/resources/assets/scripts/components/server/components/filemanager/modals/RenameModal.vue b/resources/assets/scripts/components/server/components/filemanager/modals/RenameModal.vue new file mode 100644 index 00000000..288974ac --- /dev/null +++ b/resources/assets/scripts/components/server/components/filemanager/modals/RenameModal.vue @@ -0,0 +1,136 @@ + + + diff --git a/resources/assets/scripts/components/server/subpages/Console.vue b/resources/assets/scripts/components/server/subpages/Console.vue new file mode 100644 index 00000000..a833ba92 --- /dev/null +++ b/resources/assets/scripts/components/server/subpages/Console.vue @@ -0,0 +1,181 @@ + + + diff --git a/resources/assets/scripts/components/server/subpages/Databases.vue b/resources/assets/scripts/components/server/subpages/Databases.vue new file mode 100644 index 00000000..8feb1a64 --- /dev/null +++ b/resources/assets/scripts/components/server/subpages/Databases.vue @@ -0,0 +1,115 @@ + + + diff --git a/resources/assets/scripts/components/server/subpages/FileManager.vue b/resources/assets/scripts/components/server/subpages/FileManager.vue new file mode 100644 index 00000000..42c2e797 --- /dev/null +++ b/resources/assets/scripts/components/server/subpages/FileManager.vue @@ -0,0 +1,194 @@ + + + diff --git a/resources/assets/scripts/helpers/.gitignore b/resources/assets/scripts/helpers/.gitignore new file mode 100644 index 00000000..232ae1dd --- /dev/null +++ b/resources/assets/scripts/helpers/.gitignore @@ -0,0 +1 @@ +ziggy.js diff --git a/resources/assets/scripts/helpers/axios.ts b/resources/assets/scripts/helpers/axios.ts new file mode 100644 index 00000000..5a0c76f0 --- /dev/null +++ b/resources/assets/scripts/helpers/axios.ts @@ -0,0 +1,22 @@ +import axios, {AxiosResponse} from 'axios'; + +/** + * We'll load the axios HTTP library which allows us to easily issue requests + * to our Laravel back-end. This library automatically handles sending the + * CSRF token as a header based on the value of the "XSRF" token cookie. + */ +axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; +axios.defaults.headers.common['Accept'] = 'application/json'; + +// Attach the response data to phpdebugbar so that we can see everything happening. +// @ts-ignore +if (typeof phpdebugbar !== 'undefined') { + axios.interceptors.response.use(function (response: AxiosResponse) { + // @ts-ignore + phpdebugbar.ajaxHandler.handle(response.request); + + return response; + }); +} + +export default axios; diff --git a/resources/assets/scripts/helpers/index.ts b/resources/assets/scripts/helpers/index.ts new file mode 100644 index 00000000..4768c4da --- /dev/null +++ b/resources/assets/scripts/helpers/index.ts @@ -0,0 +1,28 @@ +import {format} from 'date-fns'; + +/** + * Return the human readable filesize for a given number of bytes. This + * uses 1024 as the base, so the response is denoted accordingly. + */ +export function readableSize(bytes: number): string { + if (Math.abs(bytes) < 1024) { + return `${bytes} Bytes`; + } + + let u: number = -1; + const units: Array = ['KiB', 'MiB', 'GiB', 'TiB']; + + do { + bytes /= 1024; + u++; + } while (Math.abs(bytes) >= 1024 && u < units.length - 1); + + return `${bytes.toFixed(1)} ${units[u]}`; +} + +/** + * Format the given date as a human readable string. + */ +export function formatDate(date: string): string { + return format(date, 'MMM D, YYYY [at] HH:MM'); +} diff --git a/resources/assets/scripts/helpers/statuses.ts b/resources/assets/scripts/helpers/statuses.ts new file mode 100644 index 00000000..662a3a6f --- /dev/null +++ b/resources/assets/scripts/helpers/statuses.ts @@ -0,0 +1,6 @@ +export default { + STATUS_OFF: 'offline', + STATUS_ON: 'running', + STATUS_STARTING: 'starting', + STATUS_STOPPING: 'stopping', +}; diff --git a/resources/assets/scripts/helpers/ziggy.js b/resources/assets/scripts/helpers/ziggy.js new file mode 100644 index 00000000..8f8d46af --- /dev/null +++ b/resources/assets/scripts/helpers/ziggy.js @@ -0,0 +1,11 @@ + var Ziggy = { + namedRoutes: JSON.parse('{"debugbar.openhandler":{"uri":"_debugbar\/open","methods":["GET","HEAD"],"domain":null},"debugbar.clockwork":{"uri":"_debugbar\/clockwork\/{id}","methods":["GET","HEAD"],"domain":null},"debugbar.assets.css":{"uri":"_debugbar\/assets\/stylesheets","methods":["GET","HEAD"],"domain":null},"debugbar.assets.js":{"uri":"_debugbar\/assets\/javascript","methods":["GET","HEAD"],"domain":null},"debugbar.cache.delete":{"uri":"_debugbar\/cache\/{key}\/{tags?}","methods":["DELETE"],"domain":null},"index":{"uri":"\/","methods":["GET","HEAD"],"domain":null},"account":{"uri":"account","methods":["GET","HEAD"],"domain":null},"account.api":{"uri":"account\/api","methods":["GET","HEAD"],"domain":null},"account.api.new":{"uri":"account\/api\/new","methods":["GET","HEAD"],"domain":null},"account.api.revoke":{"uri":"account\/api\/revoke\/{identifier}","methods":["DELETE"],"domain":null},"account.two_factor":{"uri":"account\/two_factor","methods":["GET","HEAD"],"domain":null},"account.two_factor.enable":{"uri":"account\/two_factor\/totp","methods":["POST"],"domain":null},"account.two_factor.disable":{"uri":"account\/two_factor\/totp\/disable","methods":["POST"],"domain":null},"admin.index":{"uri":"admin","methods":["GET","HEAD"],"domain":null},"admin.statistics":{"uri":"admin\/statistics","methods":["GET","HEAD"],"domain":null},"admin.api.index":{"uri":"admin\/api","methods":["GET","HEAD"],"domain":null},"admin.api.new":{"uri":"admin\/api\/new","methods":["GET","HEAD"],"domain":null},"admin.api.delete":{"uri":"admin\/api\/revoke\/{identifier}","methods":["DELETE"],"domain":null},"admin.locations":{"uri":"admin\/locations","methods":["GET","HEAD"],"domain":null},"admin.locations.view":{"uri":"admin\/locations\/view\/{location}","methods":["GET","HEAD"],"domain":null},"admin.databases":{"uri":"admin\/databases","methods":["GET","HEAD"],"domain":null},"admin.databases.view":{"uri":"admin\/databases\/view\/{host}","methods":["GET","HEAD"],"domain":null},"admin.settings":{"uri":"admin\/settings","methods":["GET","HEAD"],"domain":null},"admin.settings.mail":{"uri":"admin\/settings\/mail","methods":["GET","HEAD"],"domain":null},"admin.settings.mail.test":{"uri":"admin\/settings\/mail\/test","methods":["GET","HEAD"],"domain":null},"admin.settings.advanced":{"uri":"admin\/settings\/advanced","methods":["GET","HEAD"],"domain":null},"admin.users":{"uri":"admin\/users","methods":["GET","HEAD"],"domain":null},"admin.users.json":{"uri":"admin\/users\/accounts.json","methods":["GET","HEAD"],"domain":null},"admin.users.new":{"uri":"admin\/users\/new","methods":["GET","HEAD"],"domain":null},"admin.users.view":{"uri":"admin\/users\/view\/{user}","methods":["GET","HEAD"],"domain":null},"admin.servers":{"uri":"admin\/servers","methods":["GET","HEAD"],"domain":null},"admin.servers.new":{"uri":"admin\/servers\/new","methods":["GET","HEAD"],"domain":null},"admin.servers.view":{"uri":"admin\/servers\/view\/{server}","methods":["GET","HEAD"],"domain":null},"admin.servers.view.details":{"uri":"admin\/servers\/view\/{server}\/details","methods":["GET","HEAD"],"domain":null},"admin.servers.view.build":{"uri":"admin\/servers\/view\/{server}\/build","methods":["GET","HEAD"],"domain":null},"admin.servers.view.startup":{"uri":"admin\/servers\/view\/{server}\/startup","methods":["GET","HEAD"],"domain":null},"admin.servers.view.database":{"uri":"admin\/servers\/view\/{server}\/database","methods":["GET","HEAD"],"domain":null},"admin.servers.view.manage":{"uri":"admin\/servers\/view\/{server}\/manage","methods":["GET","HEAD"],"domain":null},"admin.servers.view.delete":{"uri":"admin\/servers\/view\/{server}\/delete","methods":["GET","HEAD"],"domain":null},"admin.servers.view.manage.toggle":{"uri":"admin\/servers\/view\/{server}\/manage\/toggle","methods":["POST"],"domain":null},"admin.servers.view.manage.rebuild":{"uri":"admin\/servers\/view\/{server}\/manage\/rebuild","methods":["POST"],"domain":null},"admin.servers.view.manage.suspension":{"uri":"admin\/servers\/view\/{server}\/manage\/suspension","methods":["POST"],"domain":null},"admin.servers.view.manage.reinstall":{"uri":"admin\/servers\/view\/{server}\/manage\/reinstall","methods":["POST"],"domain":null},"admin.servers.view.database.delete":{"uri":"admin\/servers\/view\/{server}\/database\/{database}\/delete","methods":["DELETE"],"domain":null},"admin.nodes":{"uri":"admin\/nodes","methods":["GET","HEAD"],"domain":null},"admin.nodes.new":{"uri":"admin\/nodes\/new","methods":["GET","HEAD"],"domain":null},"admin.nodes.view":{"uri":"admin\/nodes\/view\/{node}","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.settings":{"uri":"admin\/nodes\/view\/{node}\/settings","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.configuration":{"uri":"admin\/nodes\/view\/{node}\/configuration","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.allocation":{"uri":"admin\/nodes\/view\/{node}\/allocation","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.servers":{"uri":"admin\/nodes\/view\/{node}\/servers","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.configuration.token":{"uri":"admin\/nodes\/view\/{node}\/settings\/token","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.allocation.removeBlock":{"uri":"admin\/nodes\/view\/{node}\/allocation\/remove","methods":["POST"],"domain":null},"admin.nodes.view.allocation.setAlias":{"uri":"admin\/nodes\/view\/{node}\/allocation\/alias","methods":["POST"],"domain":null},"admin.nodes.view.delete":{"uri":"admin\/nodes\/view\/{node}\/delete","methods":["DELETE"],"domain":null},"admin.nodes.view.allocation.removeSingle":{"uri":"admin\/nodes\/view\/{node}\/allocation\/remove\/{allocation}","methods":["DELETE"],"domain":null},"admin.nodes.view.allocation.removeMultiple":{"uri":"admin\/nodes\/view\/{node}\/allocations","methods":["DELETE"],"domain":null},"admin.nests":{"uri":"admin\/nests","methods":["GET","HEAD"],"domain":null},"admin.nests.new":{"uri":"admin\/nests\/new","methods":["GET","HEAD"],"domain":null},"admin.nests.view":{"uri":"admin\/nests\/view\/{nest}","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.new":{"uri":"admin\/nests\/egg\/new","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.view":{"uri":"admin\/nests\/egg\/{egg}","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.export":{"uri":"admin\/nests\/egg\/{egg}\/export","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.variables":{"uri":"admin\/nests\/egg\/{egg}\/variables","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.scripts":{"uri":"admin\/nests\/egg\/{egg}\/scripts","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.import":{"uri":"admin\/nests\/import","methods":["POST"],"domain":null},"admin.nests.egg.variables.edit":{"uri":"admin\/nests\/egg\/{egg}\/variables\/{variable}","methods":["PATCH"],"domain":null},"admin.packs":{"uri":"admin\/packs","methods":["GET","HEAD"],"domain":null},"admin.packs.new":{"uri":"admin\/packs\/new","methods":["GET","HEAD"],"domain":null},"admin.packs.new.template":{"uri":"admin\/packs\/new\/template","methods":["GET","HEAD"],"domain":null},"admin.packs.view":{"uri":"admin\/packs\/view\/{pack}","methods":["GET","HEAD"],"domain":null},"admin.packs.view.export":{"uri":"admin\/packs\/view\/{pack}\/export\/{files?}","methods":["POST"],"domain":null},"auth.login":{"uri":"auth\/login","methods":["GET","HEAD"],"domain":null},"auth.forgot-password":{"uri":"auth\/password","methods":["GET","HEAD"],"domain":null},"auth.reset":{"uri":"auth\/password\/reset\/{token}","methods":["GET","HEAD"],"domain":null},"auth.login-checkpoint":{"uri":"auth\/login\/checkpoint","methods":["POST"],"domain":null},"auth.reset-password":{"uri":"auth\/password\/reset","methods":["POST"],"domain":null},"auth.logout":{"uri":"auth\/logout","methods":["GET","HEAD"],"domain":null},"server.credentials":{"uri":"api\/server\/{server}\/credentials","methods":["GET","HEAD"],"domain":null},"server.files":{"uri":"api\/server\/{server}\/files\/{directory?}","methods":["GET","HEAD"],"domain":null},"server.index":{"uri":"api\/server\/{server}","methods":["GET","HEAD"],"domain":null},"server.console":{"uri":"api\/server\/{server}\/console","methods":["GET","HEAD"],"domain":null},"api.application.users":{"uri":"api\/application\/users","methods":["GET","HEAD"],"domain":null},"api.application.users.view":{"uri":"api\/application\/users\/{user}","methods":["GET","HEAD"],"domain":null},"api.application.users.external":{"uri":"api\/application\/users\/external\/{external_id}","methods":["GET","HEAD"],"domain":null},"api.application.nodes":{"uri":"api\/application\/nodes","methods":["GET","HEAD"],"domain":null},"api.application.nodes.view":{"uri":"api\/application\/nodes\/{node}","methods":["GET","HEAD"],"domain":null},"api.application.allocations":{"uri":"api\/application\/nodes\/{node}\/allocations","methods":["GET","HEAD"],"domain":null},"api.application.allocations.view":{"uri":"api\/application\/nodes\/{node}\/allocations\/{allocation}","methods":["DELETE"],"domain":null},"api.applications.locations":{"uri":"api\/application\/locations","methods":["GET","HEAD"],"domain":null},"api.application.locations.view":{"uri":"api\/application\/locations\/{location}","methods":["GET","HEAD"],"domain":null},"api.application.servers":{"uri":"api\/application\/servers","methods":["GET","HEAD"],"domain":null},"api.application.servers.view":{"uri":"api\/application\/servers\/{server}","methods":["GET","HEAD"],"domain":null},"api.application.servers.external":{"uri":"api\/application\/servers\/external\/{external_id}","methods":["GET","HEAD"],"domain":null},"api.application.servers.details":{"uri":"api\/application\/servers\/{server}\/details","methods":["PATCH"],"domain":null},"api.application.servers.build":{"uri":"api\/application\/servers\/{server}\/build","methods":["PATCH"],"domain":null},"api.application.servers.startup":{"uri":"api\/application\/servers\/{server}\/startup","methods":["PATCH"],"domain":null},"api.application.servers.suspend":{"uri":"api\/application\/servers\/{server}\/suspend","methods":["POST"],"domain":null},"api.application.servers.unsuspend":{"uri":"api\/application\/servers\/{server}\/unsuspend","methods":["POST"],"domain":null},"api.application.servers.reinstall":{"uri":"api\/application\/servers\/{server}\/reinstall","methods":["POST"],"domain":null},"api.application.servers.rebuild":{"uri":"api\/application\/servers\/{server}\/rebuild","methods":["POST"],"domain":null},"api.application.servers.databases":{"uri":"api\/application\/servers\/{server}\/databases","methods":["GET","HEAD"],"domain":null},"api.application.servers.databases.view":{"uri":"api\/application\/servers\/{server}\/databases\/{database}","methods":["GET","HEAD"],"domain":null},"api.application.nests":{"uri":"api\/application\/nests","methods":["GET","HEAD"],"domain":null},"api.application.nests.view":{"uri":"api\/application\/nests\/{nest}","methods":["GET","HEAD"],"domain":null},"api.application.nests.eggs":{"uri":"api\/application\/nests\/{nest}\/eggs","methods":["GET","HEAD"],"domain":null},"api.application.nests.eggs.view":{"uri":"api\/application\/nests\/{nest}\/eggs\/{egg}","methods":["GET","HEAD"],"domain":null},"api.client.index":{"uri":"api\/client","methods":["GET","HEAD"],"domain":null},"api.client.account":{"uri":"api\/client\/account","methods":["GET","HEAD"],"domain":null},"api.client.account.update-email":{"uri":"api\/client\/account\/email","methods":["PUT"],"domain":null},"api.client.account.update-password":{"uri":"api\/client\/account\/password","methods":["PUT"],"domain":null},"api.client.servers.view":{"uri":"api\/client\/servers\/{server}","methods":["GET","HEAD"],"domain":null},"api.client.servers.resources":{"uri":"api\/client\/servers\/{server}\/utilization","methods":["GET","HEAD"],"domain":null},"api.client.servers.command":{"uri":"api\/client\/servers\/{server}\/command","methods":["POST"],"domain":null},"api.client.servers.power":{"uri":"api\/client\/servers\/{server}\/power","methods":["POST"],"domain":null},"api.client.servers.databases":{"uri":"api\/client\/servers\/{server}\/databases","methods":["GET","HEAD"],"domain":null},"api.client.servers.databases.delete":{"uri":"api\/client\/servers\/{server}\/databases\/{database}","methods":["DELETE"],"domain":null},"api.client.servers.files.download":{"uri":"api\/client\/servers\/{server}\/files\/download\/{file}","methods":["POST"],"domain":null},"api.client.servers.network":{"uri":"api\/client\/servers\/{server}\/network","methods":["GET","HEAD"],"domain":null},"api.remote.authenticate":{"uri":"api\/remote\/authenticate\/{token}","methods":["GET","HEAD"],"domain":null},"api.remote.download_file":{"uri":"api\/remote\/download-file","methods":["POST"],"domain":null},"api.remote.eggs":{"uri":"api\/remote\/eggs","methods":["GET","HEAD"],"domain":null},"api.remote.eggs.download":{"uri":"api\/remote\/eggs\/{uuid}","methods":["GET","HEAD"],"domain":null},"api.remote.scripts":{"uri":"api\/remote\/scripts\/{uuid}","methods":["GET","HEAD"],"domain":null},"api.remote.sftp":{"uri":"api\/remote\/sftp","methods":["POST"],"domain":null},"daemon.pack.pull":{"uri":"daemon\/packs\/pull\/{uuid}","methods":["GET","HEAD"],"domain":null},"daemon.pack.hash":{"uri":"daemon\/packs\/pull\/{uuid}\/hash","methods":["GET","HEAD"],"domain":null},"daemon.configuration":{"uri":"daemon\/configure\/{token}","methods":["GET","HEAD"],"domain":null},"daemon.install":{"uri":"daemon\/install","methods":["POST"],"domain":null}}'), + baseUrl: 'http://pterodactyl.test/', + baseProtocol: 'http', + baseDomain: 'pterodactyl.test', + basePort: false + }; + + export { + Ziggy + } diff --git a/resources/assets/scripts/mixins/flash.ts b/resources/assets/scripts/mixins/flash.ts new file mode 100644 index 00000000..c90b9864 --- /dev/null +++ b/resources/assets/scripts/mixins/flash.ts @@ -0,0 +1,58 @@ +import {ComponentOptions} from "vue"; +import {Vue} from "vue/types/vue"; +import {TranslateResult} from "vue-i18n"; + +export interface FlashInterface { + flash(message: string | TranslateResult, title: string, severity: string): void; + + clear(): void, + + success(message: string | TranslateResult): void, + + info(message: string | TranslateResult): void, + + warning(message: string | TranslateResult): void, + + error(message: string | TranslateResult): void, +} + +class Flash implements FlashInterface { + flash(message: string, title: string, severity: string = 'info'): void { + severity = severity || 'info'; + if (['danger', 'fatal', 'error'].includes(severity)) { + severity = 'error'; + } + + // @ts-ignore + window.events.$emit('flash', {message, title, severity}); + } + + clear(): void { + // @ts-ignore + window.events.$emit('clear-flashes'); + } + + success(message: string): void { + this.flash(message, 'Success', 'success'); + } + + info(message: string): void { + this.flash(message, 'Info', 'info'); + } + + warning(message: string): void { + this.flash(message, 'Warning', 'warning'); + } + + error(message: string): void { + this.flash(message, 'Error', 'error'); + } +} + +export const FlashMixin: ComponentOptions = { + computed: { + '$flash': function () { + return new Flash(); + } + }, +}; diff --git a/resources/assets/scripts/mixins/socketio/connector.ts b/resources/assets/scripts/mixins/socketio/connector.ts new file mode 100644 index 00000000..a46a2815 --- /dev/null +++ b/resources/assets/scripts/mixins/socketio/connector.ts @@ -0,0 +1,132 @@ +import {camelCase} from 'lodash'; +import SocketEmitter from './emitter'; +import {Store} from "vuex"; + +const SOCKET_CONNECT = 'connect'; +const SOCKET_ERROR = 'error'; +const SOCKET_DISCONNECT = 'disconnect'; + +// This is defined in the wings daemon code and referenced here so that it is obvious +// where we are pulling these random data objects from. +type WingsWebsocketResponse = { + event: string, + args: Array +} + +export default class SocketioConnector { + /** + * The socket instance. + */ + socket: null | WebSocket; + + /** + * The vuex store being used to persist data and socket state. + */ + store: Store | undefined; + + constructor(store: Store | undefined) { + this.socket = null; + this.store = store; + } + + /** + * Initialize a new Socket connection. + */ + connect(url: string, protocols?: string | string[]): void { + this.socket = new WebSocket(url, protocols); + this.registerEventListeners(); + } + + /** + * Return the socket instance we are working with. + */ + instance(): WebSocket | null { + return this.socket; + } + + /** + * Sends an event along to the websocket. If there is no active connection, a void + * result is returned. + */ + emit(event: string, payload?: string | Array): void | false { + if (!this.socket) { + return false + } + + this.socket.send(JSON.stringify({ + event, args: typeof payload === 'string' ? [payload] : payload + })); + } + + /** + * Register the event listeners for this socket including user-defined ones in the store as + * well as global system events from Socekt.io. + */ + registerEventListeners() { + if (!this.socket) { + return; + } + + this.socket.onopen = () => this.emitAndPassToStore(SOCKET_CONNECT); + this.socket.onclose = () => this.emitAndPassToStore(SOCKET_DISCONNECT); + this.socket.onerror = () => { + // @todo reconnect? + if (this.socket && this.socket.readyState !== 1) { + this.emitAndPassToStore(SOCKET_ERROR, ['Failed to connect to websocket.']); + } + }; + + this.socket.onmessage = (wse): void => { + console.log('Socket message:', wse.data); + + try { + let {event, args}: WingsWebsocketResponse = JSON.parse(wse.data); + + this.emitAndPassToStore(event, args); + } catch (ex) { + // do nothing, bad JSON response + console.error(ex); + return + } + }; + } + + /** + * Emits the event over the event emitter and also passes it along to the vuex store. + */ + emitAndPassToStore(event: string, payload?: Array) { + payload ? SocketEmitter.emit(event, ...payload) : SocketEmitter.emit(event); + this.passToStore(event, payload); + } + + /** + * Pass event calls off to the Vuex store if there is a corresponding function. + */ + passToStore(event: string, payload?: Array) { + if (!this.store) { + return; + } + + const s: Store = this.store; + const mutation = `SOCKET_${event.toUpperCase()}`; + const action = `socket_${camelCase(event)}`; + + // @ts-ignore + Object.keys(this.store._mutations).filter((namespaced: string): boolean => { + return namespaced.split('/').pop() === mutation; + }).forEach((namespaced: string): void => { + s.commit(namespaced, payload ? this.unwrap(payload) : null); + }); + + // @ts-ignore + Object.keys(this.store._actions).filter((namespaced: string): boolean => { + return namespaced.split('/').pop() === action; + }).forEach((namespaced: string): void => { + s.dispatch(namespaced, payload ? this.unwrap(payload) : null).catch(console.error); + }); + } + + unwrap(args: Array) { + return (args && args.length <= 1) ? args[0] : args; + } +} diff --git a/resources/assets/scripts/mixins/socketio/emitter.ts b/resources/assets/scripts/mixins/socketio/emitter.ts new file mode 100644 index 00000000..8a97772e --- /dev/null +++ b/resources/assets/scripts/mixins/socketio/emitter.ts @@ -0,0 +1,60 @@ +import {isFunction} from 'lodash'; +import {ComponentOptions} from "vue"; +import {Vue} from "vue/types/vue"; + +export default new class SocketEmitter { + listeners: Map) => void, + vm: ComponentOptions, + }>>; + + constructor() { + this.listeners = new Map(); + } + + /** + * Add an event listener for socket events. + */ + addListener(event: string | number, callback: (...data: any[]) => void, vm: ComponentOptions) { + if (!isFunction(callback)) { + return; + } + + if (!this.listeners.has(event)) { + this.listeners.set(event, []); + } + + // @ts-ignore + this.listeners.get(event).push({callback, vm}); + } + + /** + * Remove an event listener for socket events based on the context passed through. + */ + removeListener(event: string | number, callback: (...data: any[]) => void, vm: ComponentOptions) { + if (!isFunction(callback) || !this.listeners.has(event)) { + return; + } + + // @ts-ignore + const filtered = this.listeners.get(event).filter((listener) => { + return listener.callback !== callback || listener.vm !== vm; + }); + + if (filtered.length > 0) { + this.listeners.set(event, filtered); + } else { + this.listeners.delete(event); + } + } + + /** + * Emit a socket event. + */ + emit(event: string | number, ...args: any) { + (this.listeners.get(event) || []).forEach((listener) => { + // @ts-ignore + listener.callback.call(listener.vm, ...args); + }); + } +} diff --git a/resources/assets/scripts/mixins/socketio/index.ts b/resources/assets/scripts/mixins/socketio/index.ts new file mode 100644 index 00000000..118bccf9 --- /dev/null +++ b/resources/assets/scripts/mixins/socketio/index.ts @@ -0,0 +1,57 @@ +import SocketEmitter from './emitter'; +import SocketioConnector from './connector'; +import {ComponentOptions} from 'vue'; +import {Vue} from "vue/types/vue"; + +let connector: SocketioConnector | null = null; + +export const Socketio: ComponentOptions = { + /** + * Setup the socket when we create the first component using the mixin. This is the Server.vue + * file, unless you mess up all of this code. Subsequent components to use this mixin will + * receive the existing connector instance, so it is very important that the top-most component + * calls the connectors destroy function when it is destroyed. + */ + created: function () { + if (!connector) { + connector = new SocketioConnector(this.$store); + } + + const sockets = (this.$options || {}).sockets || {}; + Object.keys(sockets).forEach((event) => { + SocketEmitter.addListener(event, sockets[event], this); + }); + }, + + /** + * Before destroying the component we need to remove any event listeners registered for it. + */ + beforeDestroy: function () { + const sockets = (this.$options || {}).sockets || {}; + Object.keys(sockets).forEach((event) => { + SocketEmitter.removeListener(event, sockets[event], this); + }); + }, + + methods: { + '$socket': function (): SocketioConnector | null { + return connector; + }, + + /** + * Disconnects from the active socket and sets the connector to null. + */ + removeSocket: function () { + if (!connector) { + return; + } + + const instance = connector.instance(); + if (instance) { + instance.close(); + } + + connector = null; + }, + }, +}; diff --git a/resources/assets/scripts/models/server.ts b/resources/assets/scripts/models/server.ts new file mode 100644 index 00000000..f3b85d0f --- /dev/null +++ b/resources/assets/scripts/models/server.ts @@ -0,0 +1,87 @@ +type ServerAllocation = { + ip: string, + port: number, +}; + +type ServerLimits = { + memory: number, + swap: number, + disk: number, + io: number, + cpu: number, +} + +type ServerFeatureLimits = { + databases: number, + allocations: number, +}; + +export type ServerData = { + identifier: string, + uuid: string, + name: string, + node: string, + description: string, + allocation: ServerAllocation, + limits: ServerLimits, + feature_limits: ServerFeatureLimits, +}; + +/** + * A model representing a server returned by the client API. + */ +export default class Server { + /** + * The server identifier, generally the 8-character representation of the server UUID. + */ + identifier: string; + + /** + * The long form identifier for this server. + */ + uuid: string; + + /** + * The human friendy name for this server. + */ + name: string; + + /** + * The name of the node that this server belongs to. + */ + node: string; + + /** + * A description of this server. + */ + description: string; + + /** + * The primary allocation details for this server. + */ + allocation: ServerAllocation; + + /** + * The base limits for this server when it comes to the actual docker container. + */ + limits: ServerLimits; + + /** + * The feature limits for this server, database & allocations currently. + */ + featureLimits: ServerFeatureLimits; + + /** + * Construct a new server model instance. + */ + constructor(data: ServerData) { + this.identifier = data.identifier; + this.uuid = data.uuid; + this.name = data.name; + this.node = data.node; + this.description = data.description; + this.allocation = data.allocation; + this.limits = data.limits; + this.featureLimits = data.feature_limits; + } +} diff --git a/resources/assets/scripts/models/user.ts b/resources/assets/scripts/models/user.ts new file mode 100644 index 00000000..93053681 --- /dev/null +++ b/resources/assets/scripts/models/user.ts @@ -0,0 +1,53 @@ +export type UserData = { + root_admin: boolean, + username: string, + email: string, + first_name: string, + last_name: string, + language: string, +}; + +/** + * A user model that represents an user in Pterodactyl. + */ +export default class User { + /** + * Determines wether or not the user is an admin. + */ + admin: boolean; + + /** + * The username for the currently authenticated user. + */ + username: string; + + /** + * The currently authenticated users email address. + */ + email: string; + + /** + * The full name of the logged in user. + */ + name: string; + first_name: string; + last_name: string; + + /** + * The language the user has selected to use. + */ + language: string; + + /** + * Create a new user model. + */ + constructor(data: UserData) { + this.admin = data.root_admin; + this.username = data.username; + this.email = data.email; + this.name = `${data.first_name} ${data.last_name}`; + this.first_name = data.first_name; + this.last_name = data.last_name; + this.language = data.language; + } +} diff --git a/resources/assets/scripts/pterodactyl-shims.d.ts b/resources/assets/scripts/pterodactyl-shims.d.ts new file mode 100644 index 00000000..ea89db12 --- /dev/null +++ b/resources/assets/scripts/pterodactyl-shims.d.ts @@ -0,0 +1,44 @@ +import Vue from "vue"; +import {Store} from "vuex"; +import {FlashInterface} from "./mixins/flash"; +import {AxiosInstance} from "axios"; +import {Vue as VueType} from "vue/types/vue"; +import {ApplicationState} from "./store/types"; +import {Route} from "vue-router"; +// @ts-ignore +import {Ziggy} from './helpers/ziggy'; + +declare global { + interface Window { + X_CSRF_TOKEN: string, + _: any, + $: any, + jQuery: any, + axios: AxiosInstance, + events: VueType, + Ziggy: Ziggy, + } +} + +declare module 'vue/types/options' { + interface ComponentOptions { + $store?: Store, + $options?: { + sockets?: { + [s: string]: (data: any) => void, + } + }, + sockets?: { + [s: string]: (data: any) => void, + } + } +} + +declare module 'vue/types/vue' { + interface Vue { + $route: Route, + $store: Store, + $flash: FlashInterface, + route: (name: string, params?: object, absolute?: boolean) => string, + } +} diff --git a/resources/assets/scripts/router.ts b/resources/assets/scripts/router.ts new file mode 100644 index 00000000..e5dedd59 --- /dev/null +++ b/resources/assets/scripts/router.ts @@ -0,0 +1,80 @@ +import VueRouter, {Route} from 'vue-router'; +import store from './store/index'; +import User from './models/user'; +// Base Vuejs Templates +import Login from './components/auth/Login.vue'; +import Dashboard from './components/dashboard/Dashboard.vue'; +import Account from './components/dashboard/Account.vue'; +import ResetPassword from './components/auth/ResetPassword.vue'; +import LoginForm from "@/components/auth/LoginForm.vue"; +import ForgotPassword from "@/components/auth/ForgotPassword.vue"; +import TwoFactorForm from "@/components/auth/TwoFactorForm.vue"; +import Server from "@/components/server/Server.vue"; +import ConsolePage from "@/components/server/subpages/Console.vue"; +import FileManagerPage from "@/components/server/subpages/FileManager.vue"; +import DatabasesPage from "@/components/server/subpages/Databases.vue"; + +const route = require('./../../../vendor/tightenco/ziggy/src/js/route').default; + +const routes = [ + { + path: '/auth', component: Login, + children: [ + {name: 'login', path: 'login', component: LoginForm}, + {name: 'forgot-password', path: 'password', component: ForgotPassword}, + {name: 'checkpoint', path: 'checkpoint', component: TwoFactorForm}, + ] + }, + + { + name: 'reset-password', + path: '/auth/password/reset/:token', + component: ResetPassword, + props: function (route: Route) { + return {token: route.params.token, email: route.query.email || ''}; + }, + }, + + {name: 'dashboard', path: '/', component: Dashboard}, + {name: 'account', path: '/account', component: Account}, + {name: 'account.api', path: '/account/api', component: Account}, + {name: 'account.security', path: '/account/security', component: Account}, + + { + path: '/server/:id', component: Server, + children: [ + {name: 'server', path: '', component: ConsolePage}, + {name: 'server-files', path: 'files/:path(.*)?', component: FileManagerPage}, + // {name: 'server-subusers', path: 'subusers', component: ServerSubusers}, + // {name: 'server-schedules', path: 'schedules', component: ServerSchedules}, + {name: 'server-databases', path: 'databases', component: DatabasesPage}, + // {name: 'server-allocations', path: 'allocations', component: ServerAllocations}, + // {name: 'server-settings', path: 'settings', component: ServerSettings}, + ], + }, +]; + +const router = new VueRouter({ + mode: 'history', routes, +}); + +// Redirect the user to the login page if they try to access a protected route and +// have no JWT or the JWT is expired and wouldn't be accepted by the Panel. +router.beforeEach((to, from, next) => { + if (to.path === route('auth.logout')) { + return window.location = route('auth.logout'); + } + + const user = store.getters['auth/getUser']; + + // Check that if we're accessing a non-auth route that a user exists on the page. + if (!to.path.startsWith('/auth') && !(user instanceof User)) { + store.commit('auth/logout'); + return window.location = route('auth.logout'); + } + + // Continue on through the pipeline. + return next(); +}); + +export default router; diff --git a/resources/assets/scripts/store/index.ts b/resources/assets/scripts/store/index.ts new file mode 100644 index 00000000..045785fd --- /dev/null +++ b/resources/assets/scripts/store/index.ts @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import auth from './modules/auth'; +import dashboard from './modules/dashboard'; +import server from './modules/server'; +import socket from './modules/socket'; +import {ApplicationState} from "./types"; + +Vue.use(Vuex); + +const store = new Vuex.Store({ + strict: process.env.NODE_ENV !== 'production', + modules: {auth, dashboard, server, socket}, +}); + +if (module.hot) { + module.hot.accept(['./modules/auth'], () => { + const newAuthModule = require('./modules/auth').default; + const newDashboardModule = require('./modules/dashboard').default; + const newServerModule = require('./modules/server').default; + const newSocketModule = require('./modules/socket').default; + + store.hotUpdate({ + modules: { + auth: newAuthModule, + dashboard: newDashboardModule, + server: newServerModule, + socket: newSocketModule + }, + }); + }); +} + +export default store; diff --git a/resources/assets/scripts/store/modules/auth.ts b/resources/assets/scripts/store/modules/auth.ts new file mode 100644 index 00000000..6fba4ec9 --- /dev/null +++ b/resources/assets/scripts/store/modules/auth.ts @@ -0,0 +1,106 @@ +import User, {UserData} from '../../models/user'; +import {ActionContext} from "vuex"; +import {AuthenticationState} from "../types"; + +const route = require('./../../../../../vendor/tightenco/ziggy/src/js/route').default; + +type LoginAction = { + user: string, + password: string, +} + +type UpdateEmailAction = { + email: string, + password: string, +} + +export default { + namespaced: true, + state: { + // @ts-ignore + user: typeof window.PterodactylUser === 'object' ? new User(window.PterodactylUser) : null, + }, + getters: { + /** + * Return the currently authenticated user. + */ + getUser: function (state: AuthenticationState): null | User { + return state.user; + }, + }, + setters: {}, + actions: { + /** + * Log a user into the Panel. + */ + login: ({commit}: ActionContext, {user, password}: LoginAction): Promise<{ + complete: boolean, + intended?: string, + token?: string, + }> => { + return new Promise((resolve, reject) => { + // @ts-ignore + window.axios.post(route('auth.login'), {user, password}) + // @ts-ignore + .then(response => { + commit('logout'); + + // If there is a 302 redirect or some other odd behavior (basically, response that isnt + // in JSON format) throw an error and don't try to continue with the login. + if (!(response.data instanceof Object)) { + return reject(new Error('An error was encountered while processing this request.')); + } + + if (response.data.complete) { + commit('login', response.data.user); + return resolve({ + complete: true, + intended: response.data.intended, + }); + } + + return resolve({ + complete: false, + token: response.data.login_token, + }); + }) + .catch(reject); + }); + }, + + /** + * Update a user's email address on the Panel and store the updated result in Vuex. + */ + updateEmail: function ({commit}: ActionContext, {email, password}: UpdateEmailAction): Promise { + return new Promise((resolve, reject) => { + // @ts-ignore + window.axios.put(route('api.client.account.update-email'), {email, password}) + // @ts-ignore + .then(response => { + // If there is a 302 redirect or some other odd behavior (basically, response that isnt + // in JSON format) throw an error and don't try to continue with the login. + if (!(response.data instanceof Object) && response.status !== 201) { + return reject(new Error('An error was encountered while processing this request.')); + } + + commit('setEmail', email); + return resolve(); + }) + .catch(reject); + }); + }, + }, + mutations: { + setEmail: function (state: AuthenticationState, email: string) { + if (state.user) { + state.user.email = email; + } + }, + login: function (state: AuthenticationState, data: UserData) { + state.user = new User(data); + }, + logout: function (state: AuthenticationState) { + state.user = null; + }, + }, +}; diff --git a/resources/assets/scripts/store/modules/dashboard.ts b/resources/assets/scripts/store/modules/dashboard.ts new file mode 100644 index 00000000..1ea907ea --- /dev/null +++ b/resources/assets/scripts/store/modules/dashboard.ts @@ -0,0 +1,66 @@ +import Server, {ServerData} from '../../models/server'; +import {ActionContext} from "vuex"; +import {DashboardState} from "../types"; + +const route = require('./../../../../../vendor/tightenco/ziggy/src/js/route').default; + +export default { + namespaced: true, + state: { + servers: [], + searchTerm: '', + }, + getters: { + getSearchTerm: function (state: DashboardState): string { + return state.searchTerm; + }, + }, + actions: { + /** + * Retrieve all of the servers for a user matching the query. + */ + loadServers: ({commit, state}: ActionContext): Promise => { + return new Promise((resolve, reject) => { + // @ts-ignore + window.axios.get(route('api.client.index'), { + params: {query: state.searchTerm}, + }) + // @ts-ignore + .then(response => { + // If there is a 302 redirect or some other odd behavior (basically, response that isnt + // in JSON format) throw an error and don't try to continue with the request processing. + if (!(response.data instanceof Object)) { + return reject(new Error('An error was encountered while processing this request.')); + } + + // Remove all of the existing servers. + commit('clearServers'); + + response.data.data.forEach((obj: { attributes: ServerData }) => { + commit('addServer', obj.attributes); + }); + + resolve(); + }) + .catch(reject); + }); + }, + + setSearchTerm: ({commit}: ActionContext, term: string) => { + commit('setSearchTerm', term); + }, + }, + mutations: { + addServer: function (state: DashboardState, data: ServerData) { + state.servers.push( + new Server(data) + ); + }, + clearServers: function (state: DashboardState) { + state.servers = []; + }, + setSearchTerm: function (state: DashboardState, term: string) { + state.searchTerm = term; + }, + }, +}; diff --git a/resources/assets/scripts/store/modules/server.ts b/resources/assets/scripts/store/modules/server.ts new file mode 100644 index 00000000..abe43505 --- /dev/null +++ b/resources/assets/scripts/store/modules/server.ts @@ -0,0 +1,93 @@ +// @ts-ignore +import route from '../../../../../vendor/tightenco/ziggy/src/js/route'; +import {ActionContext} from "vuex"; +import {ServerData} from "@/models/server"; +import {ServerApplicationCredentials, ServerState} from "../types"; + +export default { + namespaced: true, + state: { + server: {}, + credentials: {node: '', key: ''}, + console: [], + fm: { + currentDirectory: '/', + }, + }, + getters: {}, + actions: { + /** + * Fetches the active server from the API and stores it in vuex. + */ + getServer: ({commit}: ActionContext, {server}: { server: string }): Promise => { + return new Promise((resolve, reject) => { + // @ts-ignore + window.axios.get(route('api.client.servers.view', {server})) + // @ts-ignore + .then(response => { + // If there is a 302 redirect or some other odd behavior (basically, response that isnt + // in JSON format) throw an error and don't try to continue with the login. + if (!(response.data instanceof Object)) { + return reject(new Error('An error was encountered while processing this request.')); + } + + if (response.data.object === 'server' && response.data.attributes) { + commit('SERVER_DATA', response.data.attributes) + } + + return resolve(); + }) + .catch(reject); + }); + }, + + /** + * Get authentication credentials that the client should use when connecting to the daemon to + * retrieve server information. + */ + getCredentials: ({commit}: ActionContext, {server}: { server: string }) => { + return new Promise((resolve, reject) => { + // @ts-ignore + window.axios.get(route('server.credentials', {server})) + // @ts-ignore + .then(response => { + // If there is a 302 redirect or some other odd behavior (basically, response that isnt + // in JSON format) throw an error and don't try to continue with the login. + if (!(response.data instanceof Object)) { + return reject(new Error('An error was encountered while processing this request.')); + } + + if (response.data.key) { + commit('SERVER_CREDENTIALS', response.data) + } + + return resolve(); + }) + .catch(reject); + }); + }, + + /** + * Update the last viewed directory for the server the user is currently viewing. This allows + * us to quickly navigate back to that directory, as well as ensure that actions taken are + * performed aganist the correct directory without having to pass that mess everywhere. + */ + updateCurrentDirectory: ({commit}: ActionContext, directory: string) => { + commit('SET_CURRENT_DIRECTORY', directory); + }, + }, + mutations: { + SET_CURRENT_DIRECTORY: function (state: ServerState, directory: string) { + state.fm.currentDirectory = directory; + }, + SERVER_DATA: function (state: ServerState, data: ServerData) { + state.server = data; + }, + SERVER_CREDENTIALS: function (state: ServerState, credentials: ServerApplicationCredentials) { + state.credentials = credentials; + }, + CONSOLE_DATA: function (state: ServerState, data: string) { + state.console.push(data); + }, + }, +} diff --git a/resources/assets/scripts/store/modules/socket.ts b/resources/assets/scripts/store/modules/socket.ts new file mode 100644 index 00000000..ba74296d --- /dev/null +++ b/resources/assets/scripts/store/modules/socket.ts @@ -0,0 +1,30 @@ +import Status from '../../helpers/statuses'; +import {SocketState} from "../types"; + +export default { + namespaced: true, + state: { + connected: false, + connectionError: false, + status: Status.STATUS_OFF, + }, + mutations: { + SOCKET_CONNECT: (state: SocketState) => { + state.connected = true; + state.connectionError = false; + }, + + SOCKET_ERROR: (state: SocketState, err: Error) => { + state.connected = false; + state.connectionError = err; + }, + + 'SOCKET_INITIAL STATUS': (state: SocketState, data: string) => { + state.status = data; + }, + + SOCKET_STATUS: (state: SocketState, data: string) => { + state.status = data; + } + }, +}; diff --git a/resources/assets/scripts/store/types.ts b/resources/assets/scripts/store/types.ts new file mode 100644 index 00000000..f4f5ddfd --- /dev/null +++ b/resources/assets/scripts/store/types.ts @@ -0,0 +1,41 @@ +import Server, {ServerData} from "../models/server"; +import User from "../models/user"; + +export type ApplicationState = { + socket: SocketState, + server: ServerState, + auth: AuthenticationState, + dashboard: DashboardState, +} + +export type SocketState = { + connected: boolean, + connectionError: boolean | Error, + status: string, +} + +export type ServerApplicationCredentials = { + node: string, + key: string, +}; + +export type FileManagerState = { + currentDirectory: string, +} + +export type ServerState = { + server: ServerData, + credentials: ServerApplicationCredentials, + console: Array, + fm: FileManagerState, +}; + +export type DashboardState = { + searchTerm: string, + servers: Array, +}; + + +export type AuthenticationState = { + user: null | User, +} diff --git a/resources/assets/scripts/vue-shims.d.ts b/resources/assets/scripts/vue-shims.d.ts new file mode 100644 index 00000000..b93ce222 --- /dev/null +++ b/resources/assets/scripts/vue-shims.d.ts @@ -0,0 +1,4 @@ +declare module '*.vue' { + import Vue from 'vue' + export default Vue +} diff --git a/resources/assets/styles/components/animations.css b/resources/assets/styles/components/animations.css new file mode 100644 index 00000000..25b3985a --- /dev/null +++ b/resources/assets/styles/components/animations.css @@ -0,0 +1,68 @@ +.animate { + &.fadein { + animation: fadein 500ms; + } +} + +.animated-fade-in { + animation: fadein 500ms; +} + +.fade-enter-active { + animation: fadein 500ms; +} + +.fade-leave-active { + animation: fadein 500ms reverse; +} + +@keyframes fadein { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes onlineblink { + 0% { + @apply .bg-green-500; + } + 100% { + @apply .bg-green-600; + } +} + +@keyframes offlineblink { + 0% { + @apply .bg-red-500; + } + 100% { + @apply .bg-red-600; + } +} + +/* + * transition="modal" + */ +.modal-enter, .modal-leave-active { + opacity: 0; +} + +.modal-enter .modal-container, +.modal-leave-active .modal-container { + animation: opacity 250ms linear; +} + +/** + * name="slide-fade" mode="out-in" + */ +.slide-fade-enter-active { + transition: all 250ms ease; +} + +.slide-fade-leave-active { + transition: all 250ms cubic-bezier(1.0, 0.5, 0.8, 1.0); +} + +.slide-fade-enter, .slide-fade-leave-to { + transform: translateX(10px); + opacity: 0; +} diff --git a/resources/assets/styles/components/authentication.css b/resources/assets/styles/components/authentication.css new file mode 100644 index 00000000..1f99a29f --- /dev/null +++ b/resources/assets/styles/components/authentication.css @@ -0,0 +1,9 @@ +.login-box { + @apply .bg-white .shadow-lg .rounded-lg .pt-10 .px-8 .pb-6 .mb-4; + + @screen xsx { + @apply .rounded-none; + margin-top: 25%; + box-shadow: 0 15px 30px 0 rgba(0, 0, 0, .2), 0 -15px 30px 0 rgba(0, 0, 0, .2); + } +} diff --git a/resources/assets/styles/components/filemanager.css b/resources/assets/styles/components/filemanager.css new file mode 100644 index 00000000..329f90ea --- /dev/null +++ b/resources/assets/styles/components/filemanager.css @@ -0,0 +1,81 @@ +.filemanager { + & .header { + @apply .flex .text-xs .text-neutral-600 .pb-4 .font-bold .border-b .border-neutral-200 .mb-3 .uppercase; + + & > div:not(:last-of-type) { + @apply .pr-4; + } + } + + & .row { + @apply .flex .text-sm .py-3 .text-sm .border .border-transparent .text-black .rounded .no-underline; + + & > div:not(:last-of-type) { + @apply .pr-4; + } + + &.active-selection, &:hover { + @apply .bg-neutral-50 .text-neutral-900; + } + + & > .icon { + @apply .w-8 .text-center; + + & > svg { + @apply .h-4; + } + } + } + + .context-menu { + @apply .absolute .bg-white .py-2 .border .border-neutral-300 .shadow-lg .rounded .text-neutral-600 .text-sm .cursor-pointer; + + & > div:not(:last-of-type) { + @apply .border-b .border-neutral-100 .pb-2 .mb-2; + } + + & .context-row { + @apply .flex .flex-row .items-center .py-2 .px-8 .mx-2 .rounded; + transition: background-color 50ms linear; + + & > .icon { + @apply .flex-none; + + & > svg { + @apply .h-4; + } + } + + & > .action { + @apply .flex-auto .pl-2; + } + + &:hover { + @apply .bg-neutral-50 .text-neutral-800; + } + + &.danger { + @apply .border .border-transparent; + transition: border 50ms linear; + + &:hover { + @apply .bg-red-50 .border-red-100; + } + } + + } + } +} + +.filemanager-breadcrumbs { + @apply .px-4 .py-3 .mb-6 .rounded .bg-white .text-neutral-400 .border .border-neutral-100 .shadow; + + & a { + @apply .no-underline .text-neutral-400; + transition: color 100ms linear; + + &:hover { + @apply .text-primary-500; + } + } +} diff --git a/resources/assets/styles/components/forms.css b/resources/assets/styles/components/forms.css new file mode 100644 index 00000000..0220a442 --- /dev/null +++ b/resources/assets/styles/components/forms.css @@ -0,0 +1,152 @@ +textarea, select, input, button { + outline: none; +} + +input[type=number]::-webkit-outer-spin-button, +input[type=number]::-webkit-inner-spin-button { + -webkit-appearance: none !important; + margin: 0; +} + +input[type=number] { + -moz-appearance: textfield !important; +} + +/** + * Styles for the login form open input boxes. Label floats up above it when content + * is input and then sinks back down into the field if left empty. + */ +.input-open { + @apply .w-full .px-3 .relative; +} + +.input-open > .input { + @apply .appearance-none .block .w-full .text-neutral-800 .border-b-2 .border-neutral-200 .py-3 .mb-3; + + &:focus { + @apply .border-primary-400; + outline: 0; + transition: border 500ms ease-out; + } + + &:focus + label, &:valid + label, &.has-content + label { + @apply .text-neutral-800 .px-0 .cursor-pointer; + transform:translateY(-26px) + } + + &:required { + box-shadow: none; + } +} + +.input-open > label { + @apply .block .uppercase .tracking-wide .text-neutral-500 .text-xs .mb-2 .absolute; + top: 14px; + transition: transform 200ms ease-out; +} + +/** + * Styling for other forms throughout the Panel. + */ +.input:not(.open-label) { + @apply .appearance-none .p-3 .rounded .border .border-neutral-200 .text-neutral-800 .w-full; + transition: border 150ms linear; + + &:focus { + @apply .border-primary-400; + } + + &:required, &:invalid { + box-shadow: none; + } + + &.error { + @apply .text-red-600 .border-red-500; + } +} + +.input-label { + @apply .block .uppercase .tracking-wide .text-neutral-800 .text-xs .font-bold .mb-2; +} + +.input-help { + @apply .text-xs .text-neutral-400 .pt-2; + + &.error { + @apply .text-red-600; + } +} + +a.btn { + @apply .no-underline; +} + +.btn { + @apply .rounded .p-2; + transition: all 150ms linear; + + /** + * Button Colors + */ + &.btn-primary { + @apply .bg-primary-500 .border-primary-600 .border .text-white; + + &:hover:not(:disabled) { + @apply .bg-primary-600 .border-primary-800; + } + } + + &.btn-green { + @apply .bg-green-500 .border-green-600 .border .text-white; + + &:hover:not(:disabled) { + @apply .bg-green-600 .border-green-800; + } + } + + &.btn-red { + &:not(.btn-secondary) { + @apply .bg-red-500 .border-red-600 .border .text-white; + } + + &:hover:not(:disabled) { + @apply .bg-red-600 .border-red-800; + } + } + + &.btn-secondary { + @apply .border .border-neutral-200 .text-neutral-400; + + &:hover:not(:disabled) { + @apply .border-neutral-500 .text-neutral-700; + } + + &.btn-red:hover:not(:disabled) { + @apply .bg-red-600 .border-red-800 .text-white; + } + } + + /** + * Button Sizes + */ + &.btn-jumbo { + @apply .p-4 .w-full .uppercase .tracking-wide .text-sm; + } + + &.btn-lg { + @apply .p-4 .uppercase .tracking-wide .text-sm; + } + + &.btn-sm { + @apply .px-6 .py-3 .uppercase .tracking-wide .text-sm; + } + + &.btn-xs { + @apply .py-2 .px-2 .uppercase .text-xs; + } + + &:disabled, &.disabled { + opacity: 0.55; + cursor: default; + } +} diff --git a/resources/assets/styles/components/miscellaneous.css b/resources/assets/styles/components/miscellaneous.css new file mode 100644 index 00000000..8df2576e --- /dev/null +++ b/resources/assets/styles/components/miscellaneous.css @@ -0,0 +1,120 @@ +code { + @apply .font-mono .px-2 .py-1; + background-color: #eef1f6; + color: #596981; + border-radius: 2px; + border: 1px solid rgba(0, 0, 0, .1); + display: inline-block; +} + +/** + * Indicators for server online status. + */ +.indicator { + @apply .bg-neutral-800 .border .border-primary-500; + border-radius: 50%; + width: 16px; + height: 16px; + + &.online { + @apply .bg-green-600 .border-green-500; + animation: onlineblink 2s infinite alternate; + } + + &.offline { + @apply .bg-green-600 .border-red-500; + animation: offlineblink 2s infinite alternate; + } +} + +/** + * Usage indicator labels for the server listing. + */ +.usage { + @apply .flex-1 .text-center .relative; + + & > .indicator-title { + @apply .text-xs .uppercase .font-hairline .bg-white .absolute .text-primary-500; + margin-top:-9px; + padding: 0 8px; + left: 50%; + transform: translate(-50%, 0); + } +} + +/** + * Styling for elements that contain the core page content. + */ +.content-box { + @apply .bg-white .p-6 .rounded .shadow .border .border-neutral-100; +} + +/** + * Flex boxes for server listing on user dashboard. + */ +.server-card-container { + @apply .mb-4 .w-full; + + @screen md { + @apply .w-1/2 .pr-4; + + &:nth-of-type(2n) { + @apply .pr-0; + } + } + + @screen lg { + @apply .w-1/3 .pr-4; + + &:nth-of-type(2n) { + @apply .pr-4; + } + + &:nth-of-type(3n) { + @apply .pr-0; + } + } + + & > div { + @apply .flex .flex-col; + transition: box-shadow 150ms ease-in; + + &:hover { + @apply .shadow-md; + } + } + + & > div > .server-card { + @apply .flex .flex-col .p-4 .border .border-t-4 .border-neutral-100 .bg-white; + transition: all 100ms ease-in; + + & .identifier-icon { + @apply .select-none .inline-block .rounded-full .text-white .text-center .leading-none .justify-center .w-8 .h-8 .mr-2 .flex .flex-row .items-center; + } + + & a, & a:visited { + @apply .no-underline .text-neutral-800; + } + } + + & > div > .footer { + @apply .border .border-neutral-100 .border-t-0 .bg-neutral-50 .shadow-inner; + } +} + +.pillbox { + @apply .rounded-full .px-2 .py-1 .text-white .font-medium .leading-none .text-xs; +} + +.server-search { + @apply .w-full .my-4; + + & > input[type="text"] { + @apply .w-full .p-4 .rounded .border .border-neutral-200 .text-neutral-500; + transition: border 150ms ease-in; + + &:focus { + @apply .border-primary-500; + } + } +} diff --git a/resources/assets/styles/components/modal.css b/resources/assets/styles/components/modal.css new file mode 100644 index 00000000..0a2fe6e3 --- /dev/null +++ b/resources/assets/styles/components/modal.css @@ -0,0 +1,24 @@ +.modal-mask { + @apply .fixed .pin .z-50 .overflow-auto .flex; + background: rgba(0, 0, 0, 0.7); + transition: opacity 250ms ease; + + & > .modal-container { + @apply .relative .p-8 .bg-white .w-full .max-w-md .m-auto .flex-col .flex .rounded; + transition: all 250ms ease; + margin-top: 15%; + + /** + * On tiny phone screens make sure there is a margin on the sides and also + * center the modal rather than putting it towards the top of the screen. + */ + @screen smx { + margin-top: auto; + width: 90%; + } + } + + & > .modal-container.w-auto { + @apply .w-auto; + } +} diff --git a/resources/assets/styles/components/navigation.css b/resources/assets/styles/components/navigation.css new file mode 100644 index 00000000..9ead877e --- /dev/null +++ b/resources/assets/styles/components/navigation.css @@ -0,0 +1,113 @@ +.nav { + @apply .bg-primary-600 .border-b .border-t .border-primary-700; + height: 56px; + + & .logo { + @apply .mr-8 .font-sans .font-thin .text-3xl .text-white .inline-block; + + & a { + color: inherit; + text-decoration: none; + } + + @screen xsx { + @apply .hidden; + } + } + + & .search-box { + @apply .mr-2; + + & > .search-input { + @apply .text-sm .p-2 .ml-8 .rounded .border .border-primary-600 .bg-white .text-neutral-900 .w-96; + transition: border 150ms ease-in; + + &:focus { + @apply .border-primary-700; + } + + &.has-search-results { + @apply .border-b-0 .rounded-b-none; + } + } + + & .search-results { + @apply .absolute .bg-white .border .border-primary-700 .border-t-0 .rounded .rounded-t-none .p-2 .ml-8 .z-50 .w-96; + + & a { + @apply .block .no-underline .p-2 .rounded; + + &:not(.no-hover):hover { + @apply .bg-neutral-50; + } + } + } + } + + & .menu { + @apply .flex .h-full .items-center; + + & > a { + transition: background-color 150ms linear; + @apply .block .flex .self-stretch .items-center .no-underline .text-white .font-light .text-sm .px-5; + + &:hover { + @apply .bg-primary-700; + } + } + } +} + +.sidenav { + ul { + @apply .list-reset; + + & li { + @apply .block; + + & > a { + transition: border-left-color 250ms linear, color 250ms linear; + @apply .block .px-4 .py-3 .border-l-3 .border-neutral-100 .no-underline .text-neutral-400 .font-medium; + + &:hover, &.router-link-exact-active, &.router-link-active { + @apply .text-neutral-800; + } + + &.router-link-exact-active, &.router-link-active { + @apply .border-primary-500 .cursor-default; + } + } + + /** + * Because of how the router works the first sidebar link is always active + * since that is the container for all of the server things. Override the + * style for active links if its the first one and not an exact route match. + */ + &:first-of-type > a { + &.router-link-active:not(.router-link-exact-active) { + @apply .border-neutral-100 .text-neutral-400 .cursor-pointer; + } + } + } + } +} +/* +.sidenav { + @apply .py-2; + + a { + @apply .block .py-3 .px-6 .text-neutral-900 .no-underline .border .border-transparent; + + &:hover, &.router-link-exact-active { + @apply .border-neutral-400 .bg-neutral-50; + + border-left: 1px solid transparent; + border-right: 1px solid transparent; + } + + &.router-link-exact-active + a:hover { + border-top: 1px solid transparent; + } + } +} +*/ diff --git a/resources/assets/styles/components/notifications.css b/resources/assets/styles/components/notifications.css new file mode 100644 index 00000000..85d31ee6 --- /dev/null +++ b/resources/assets/styles/components/notifications.css @@ -0,0 +1,46 @@ +/** + * Styling to control alert boxes. + */ +.alert { + @apply .p-2 .border .items-center .leading-normal .rounded .flex .w-full .text-sm; + + & > .title { + @apply .flex .rounded-full .uppercase .px-2 .py-1 .text-xs .font-bold .mr-3 .leading-none; + } + + & > .message { + @apply .mr-2 .text-left .flex-auto; + } + + &.error { + @apply .bg-red-600 .border-red-800 .text-red-50; + + & > .title { + @apply .bg-red-500; + } + } + + &.info { + @apply .bg-primary-600 .border-primary-800 .text-primary-50; + + & > .title { + @apply .bg-primary-500; + } + } + + &.success { + @apply .bg-green-600 .border-green-800 .text-green-50; + + & > .title { + @apply .bg-green-500; + } + } + + &.warning { + @apply .bg-yellow-600 .border-yellow-800 .text-yellow-50; + + & > .title { + @apply .bg-yellow-500; + } + } +} diff --git a/resources/assets/styles/components/spinners.css b/resources/assets/styles/components/spinners.css new file mode 100644 index 00000000..f5591f28 --- /dev/null +++ b/resources/assets/styles/components/spinners.css @@ -0,0 +1,58 @@ +.spinner { + @apply .h-4 .relative .bg-transparent; + pointer-events: none; + + &.spinner-xl { + @apply .h-16; + } + + &:after { + @apply .border-2 .border-neutral-400 .absolute .block .h-4 .w-4 .rounded-full; + animation: spinners--spin 500ms infinite linear; + border-top-color: transparent !important; + border-right-color: transparent !important; + content: ''; + left: calc(50% - (1em / 2)); + } + + &.spinner-relative:after { + @apply .relative; + } + + &.spinner-xl:after { + @apply .h-16 .w-16; + left: calc(50% - (4rem / 2)); + } + + /** + * Speeds + */ + &.spin-slow:after { + animation: spinners--spin 1200ms infinite linear; + } + + /** + * Spinner Colors + */ + &.blue:after, &.text-blue:after { + @apply .border-primary-500; + } + + &.white:after, &.text-white:after { + @apply .border-white; + } + + &.spinner-thick:after { + @apply .border-4; + } +} + +@keyframes spinners--spin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} diff --git a/resources/assets/styles/main.css b/resources/assets/styles/main.css new file mode 100644 index 00000000..01a28e8d --- /dev/null +++ b/resources/assets/styles/main.css @@ -0,0 +1,32 @@ +/** + * Tailwind Preflight Classes + */ +@import "tailwindcss/preflight"; +@import "tailwindcss/components"; + +@import "xterm/src/xterm.css"; + +/** + * Pterodactyl Specific CSS + */ +@import "components/animations.css"; +@import "components/authentication.css"; +@import "components/forms.css"; +@import "components/miscellaneous.css"; +@import "components/modal.css"; +@import "components/navigation.css"; +@import "components/notifications.css"; +@import "components/spinners.css"; +@import "components/filemanager.css"; + +/** + * Tailwind Utilities + */ +@import "tailwindcss/utilities"; + +/** + * Assorted Other CSS + */ +body { + @apply .font-sans; +} diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php index 176de8f6..2a3a4526 100644 --- a/resources/lang/en/auth.php +++ b/resources/lang/en/auth.php @@ -1,22 +1,27 @@ 'You are not authorized to perform this action.', - 'auth_error' => 'There was an error while attempting to login.', - 'authentication_required' => 'Authentication is required to continue.', - 'remember_me' => 'Remember Me', 'sign_in' => 'Sign In', - 'forgot_password' => 'I\'ve forgotten my password!', - 'request_reset_text' => 'Forgotten your account password? It is not the end of the world, just provide your email below.', - 'reset_password_text' => 'Reset your account password.', - 'reset_password' => 'Reset Account Password', - 'email_sent' => 'An email has been sent to you with further instructions for resetting your password.', - 'failed' => 'The credentials provided do not match those we have on record, or the 2FA token provided was invalid.', + 'go_to_login' => 'Go to Login', + 'failed' => 'No account matching those credentials could be found.', + + 'forgot_password' => [ + 'label' => 'Forgot Password?', + 'label_help' => 'Enter your account email address to receive instructions on resetting your password.', + 'button' => 'Recover Account', + ], + + 'reset_password' => [ + 'button' => 'Reset and Sign In', + ], + + 'two_factor' => [ + 'label' => '2-Factor Token', + 'label_help' => 'This account requires a second layer of authentication in order to continue. Please enter the code generated by your device to complete this login.', + 'checkpoint_failed' => 'The two-factor authentication token was invalid.', + ], + 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', - 'password_requirements' => 'Passwords must contain at least one uppercase, lowercase, and numeric character and must be at least 8 characters in length.', - 'request_reset' => 'Locate Account', - '2fa_required' => '2-Factor Authentication', - '2fa_failed' => 'The 2FA token provided was invalid.', - 'totp_failed' => 'There was an error while attempting to validate TOTP.', + 'password_requirements' => 'Password must be at least 8 characters in length and should be unique to this site.', '2fa_must_be_enabled' => 'The administrator has required that 2-Factor Authentication be enabled for your account in order to use the Panel.', ]; diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index e2c66106..2646dc4f 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -54,36 +54,4 @@ return [ ], ], ], - 'account' => [ - 'details_updated' => 'Your account details have been successfully updated.', - 'invalid_password' => 'The password provided for your account was not valid.', - 'header' => 'Your Account', - 'header_sub' => 'Manage your account details.', - 'update_pass' => 'Update Password', - 'update_email' => 'Update Email Address', - 'current_password' => 'Current Password', - 'new_password' => 'New Password', - 'new_password_again' => 'Repeat New Password', - 'new_email' => 'New Email Address', - 'first_name' => 'First Name', - 'last_name' => 'Last Name', - 'update_identity' => 'Update Identity', - 'username_help' => 'Your username must be unique to your account, and may only contain the following characters: :requirements.', - 'language' => 'Language', - ], - 'security' => [ - 'session_mgmt_disabled' => 'Your host has not enabled the ability to manage account sessions via this interface.', - 'header' => 'Account Security', - 'header_sub' => 'Control active sessions and 2-Factor Authentication.', - 'sessions' => 'Active Sessions', - '2fa_header' => '2-Factor Authentication', - '2fa_token_help' => 'Enter the 2FA Token generated by your app (Google Authenticator, Authy, etc.).', - 'disable_2fa' => 'Disable 2-Factor Authentication', - '2fa_enabled' => '2-Factor Authentication is enabled on this account and will be required in order to login to the panel. If you would like to disable 2FA, simply enter a valid token below and submit the form.', - '2fa_disabled' => '2-Factor Authentication is disabled on your account! You should enable 2FA in order to add an extra level of protection on your account.', - 'enable_2fa' => 'Enable 2-Factor Authentication', - '2fa_qr' => 'Configure 2FA on Your Device', - '2fa_checkpoint_help' => 'Use the 2FA application on your phone to take a picture of the QR code to the left, or manually enter the code under it. Once you have done so, generate a token and enter it below.', - '2fa_disable_error' => 'The 2FA token provided was not valid. Protection has not been disabled for this account.', - ], ]; diff --git a/resources/lang/en/dashboard/account.php b/resources/lang/en/dashboard/account.php new file mode 100644 index 00000000..85411ef6 --- /dev/null +++ b/resources/lang/en/dashboard/account.php @@ -0,0 +1,28 @@ + [ + 'title' => 'Update your email', + 'updated' => 'Your email address has been updated.', + ], + 'password' => [ + 'title' => 'Change your password', + 'requirements' => 'Your new password should be at least 8 characters in length.', + 'updated' => 'Your password has been updated.', + ], + 'two_factor' => [ + 'button' => 'Configure 2-Factor Authentication', + 'disabled' => 'Two-factor authentication has been disabled on your account. You will no longer be prompted to provide a token when logging in.', + 'enabled' => 'Two-factor authentication has been enabled on your account! From now on, when logging in, you will be required to provide the code generated by your device.', + 'invalid' => 'The token provided was invalid.', + 'setup' => [ + 'title' => 'Setup two-factor authentication', + 'help' => 'Can\'t scan the code? Enter the code below into your application:', + 'field' => 'Enter token', + ], + 'disable' => [ + 'title' => 'Disable two-factor authentication', + 'field' => 'Enter token', + ], + ], +]; diff --git a/resources/lang/en/dashboard/index.php b/resources/lang/en/dashboard/index.php new file mode 100644 index 00000000..8ab11e99 --- /dev/null +++ b/resources/lang/en/dashboard/index.php @@ -0,0 +1,8 @@ + 'Search for servers...', + 'no_matches' => 'There were no servers found matching the search criteria provided.', + 'cpu_title' => 'CPU', + 'memory_title' => 'Memory', +]; diff --git a/resources/lang/en/strings.php b/resources/lang/en/strings.php index c0bf3f41..c9fbb634 100644 --- a/resources/lang/en/strings.php +++ b/resources/lang/en/strings.php @@ -2,9 +2,11 @@ return [ 'email' => 'Email', + 'email_address' => 'Email address', 'user_identifier' => 'Username or Email', 'password' => 'Password', - 'confirm_password' => 'Confirm Password', + 'new_password' => 'New password', + 'confirm_password' => 'Confirm new password', 'login' => 'Login', 'home' => 'Home', 'servers' => 'Servers', @@ -85,4 +87,8 @@ return [ 'sat' => 'Saturday', ], 'last_used' => 'Last Used', + 'enable' => 'Enable', + 'disable' => 'Disable', + 'save' => 'Save', + 'copyright' => '© 2015 - :year Pterodactyl Software', ]; diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 201880ec..a82aaa1b 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -101,5 +101,6 @@ return [ // Internal validation logic for Pterodactyl 'internal' => [ 'variable_value' => ':env variable', + 'invalid_password' => 'The password provided was invalid for this account.', ], ]; diff --git a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php index 71eb346d..ac9e2953 100644 --- a/resources/themes/pterodactyl/admin/nodes/view/index.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/view/index.blade.php @@ -98,7 +98,7 @@
@if($node->maintenance_mode)
-
+
This node is under @@ -169,4 +169,4 @@ }); })(); -@endsection \ No newline at end of file +@endsection diff --git a/resources/themes/pterodactyl/admin/users/index.blade.php b/resources/themes/pterodactyl/admin/users/index.blade.php index 2de490d5..b327ad5f 100644 --- a/resources/themes/pterodactyl/admin/users/index.blade.php +++ b/resources/themes/pterodactyl/admin/users/index.blade.php @@ -58,7 +58,7 @@ {{ $user->username }} @if($user->use_totp) - + @else @endif diff --git a/resources/themes/pterodactyl/auth/login.blade.php b/resources/themes/pterodactyl/auth/login.blade.php deleted file mode 100644 index e81af8d3..00000000 --- a/resources/themes/pterodactyl/auth/login.blade.php +++ /dev/null @@ -1,75 +0,0 @@ -{{-- Pterodactyl - Panel --}} -{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} - -{{-- This software is licensed under the terms of the MIT license. --}} -{{-- https://opensource.org/licenses/MIT --}} -@extends('layouts.auth') - -@section('title') - Login -@endsection - -@section('content') -
-
- @if (count($errors) > 0) -
- - @lang('auth.auth_error')

-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach -
-
-
- -
-@endsection - -@section('scripts') - @parent - @if(config('recaptcha.enabled')) - - - @endif -@endsection diff --git a/resources/themes/pterodactyl/auth/passwords/email.blade.php b/resources/themes/pterodactyl/auth/passwords/email.blade.php deleted file mode 100644 index d90d36c5..00000000 --- a/resources/themes/pterodactyl/auth/passwords/email.blade.php +++ /dev/null @@ -1,71 +0,0 @@ -{{-- Pterodactyl - Panel --}} -{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} - -{{-- This software is licensed under the terms of the MIT license. --}} -{{-- https://opensource.org/licenses/MIT --}} -@extends('layouts.auth') - -@section('title') - Forgot Password -@endsection - -@section('content') -
-
- @if (count($errors) > 0) -
- - @lang('auth.auth_error')

-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif - @if (session('status')) -
- @lang('auth.email_sent') -
- @endif -
-
-
- -
-@endsection - -@section('scripts') - @parent - @if(config('recaptcha.enabled')) - - - @endif -@endsection diff --git a/resources/themes/pterodactyl/auth/passwords/reset.blade.php b/resources/themes/pterodactyl/auth/passwords/reset.blade.php deleted file mode 100644 index d79b9a6a..00000000 --- a/resources/themes/pterodactyl/auth/passwords/reset.blade.php +++ /dev/null @@ -1,90 +0,0 @@ -{{-- Pterodactyl - Panel --}} -{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} - -{{-- This software is licensed under the terms of the MIT license. --}} -{{-- https://opensource.org/licenses/MIT --}} -@extends('layouts.auth') - -@section('title') - Reset Password -@endsection - -@section('content') -
-
- @if (count($errors) > 0) -
- - @lang('auth.auth_error')

-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif -
-
-
- -
-@endsection - -@section('scripts') - @parent - @if(config('recaptcha.enabled')) - - - @endif -@endsection diff --git a/resources/themes/pterodactyl/auth/totp.blade.php b/resources/themes/pterodactyl/auth/totp.blade.php deleted file mode 100644 index 3c1ee253..00000000 --- a/resources/themes/pterodactyl/auth/totp.blade.php +++ /dev/null @@ -1,42 +0,0 @@ -{{-- Pterodactyl - Panel --}} -{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} - -{{-- This software is licensed under the terms of the MIT license. --}} -{{-- https://opensource.org/licenses/MIT --}} -@extends('layouts.auth') - -@section('title') - 2FA Checkpoint -@endsection - -@section('scripts') - @parent - -@endsection - -@section('content') -
- -
-@endsection diff --git a/resources/themes/pterodactyl/server/users/index.blade.php b/resources/themes/pterodactyl/server/users/index.blade.php index 3d08e590..632e79f8 100644 --- a/resources/themes/pterodactyl/server/users/index.blade.php +++ b/resources/themes/pterodactyl/server/users/index.blade.php @@ -49,7 +49,7 @@ {{ $subuser->user->email }} @if($subuser->user->use_totp) - + @else @endif diff --git a/resources/themes/pterodactyl/templates/auth/core.blade.php b/resources/themes/pterodactyl/templates/auth/core.blade.php new file mode 100644 index 00000000..988509c3 --- /dev/null +++ b/resources/themes/pterodactyl/templates/auth/core.blade.php @@ -0,0 +1,15 @@ +@extends('templates/wrapper', [ + 'css' => ['body' => 'bg-neutral-900'] +]) + +@section('container') +
+ + +

+ {!! trans('strings.copyright', ['year' => date('Y')]) !!} +

+
+@endsection diff --git a/resources/themes/pterodactyl/templates/base/core.blade.php b/resources/themes/pterodactyl/templates/base/core.blade.php new file mode 100644 index 00000000..bf3b37c1 --- /dev/null +++ b/resources/themes/pterodactyl/templates/base/core.blade.php @@ -0,0 +1,14 @@ +@extends('templates/wrapper') + +@section('container') + +@endsection + +@section('below-container') +
+
+

+ {!! trans('strings.copyright', ['year' => date('Y')]) !!} +

+
+@endsection diff --git a/resources/themes/pterodactyl/templates/wrapper.blade.php b/resources/themes/pterodactyl/templates/wrapper.blade.php new file mode 100644 index 00000000..35930d63 --- /dev/null +++ b/resources/themes/pterodactyl/templates/wrapper.blade.php @@ -0,0 +1,49 @@ + + + {{ config('app.name', 'Pterodactyl') }} + + @section('meta') + + + + + + + + + + + + + + @show + + @section('user-data') + @if(!is_null(Auth::user())) + + @endif + @show + + @section('assets') + {!! $asset->css('main.css') !!} + @show + + @include('layouts.scripts') + + + @section('content') + @yield('above-container') +
+ @yield('container') +
+ @yield('below-container') + @show + @section('scripts') + {!! $asset->js('main.js') !!} + {!! $asset->js('vendor.js') !!} + {!! $asset->js('locales.js') !!} + @show + + diff --git a/routes/api-client.php b/routes/api-client.php index 23c79fd4..02ece8b3 100644 --- a/routes/api-client.php +++ b/routes/api-client.php @@ -1,6 +1,6 @@ name('api.client.index'); +Route::group(['prefix' => '/account'], function () { + Route::get('/', 'AccountController@index')->name('api.client.account'); + + Route::put('/email', 'AccountController@updateEmail')->name('api.client.account.update-email'); + Route::put('/password', 'AccountController@updatePassword')->name('api.client.account.update-password'); +}); + /* |-------------------------------------------------------------------------- | Client Control API @@ -20,12 +27,29 @@ Route::get('/', 'ClientController@index')->name('api.client.index'); | Endpoint: /api/client/servers/{server} | */ -Route::group(['prefix' => '/servers/{server}', 'middleware' => [AuthenticateClientAccess::class]], function () { +Route::group(['prefix' => '/servers/{server}', 'middleware' => [AuthenticateServerAccess::class]], function () { Route::get('/', 'Servers\ServerController@index')->name('api.client.servers.view'); Route::get('/utilization', 'Servers\ResourceUtilizationController@index') - ->middleware(['throttle:15,1']) ->name('api.client.servers.resources'); Route::post('/command', 'Servers\CommandController@index')->name('api.client.servers.command'); Route::post('/power', 'Servers\PowerController@index')->name('api.client.servers.power'); + + Route::group(['prefix' => '/databases'], function () { + Route::get('/', 'Servers\DatabaseController@index')->name('api.client.servers.databases'); + Route::post('/', 'Servers\DatabaseController@store'); + Route::delete('/{database}', 'Servers\DatabaseController@delete')->name('api.client.servers.databases.delete'); + }); + + Route::group(['prefix' => '/files'], function () { + Route::get('/list', 'Servers\FileController@listDirectory')->name('api.client.servers.files.list'); + + Route::post('/download/{file}', 'Servers\FileController@download') + ->where('file', '.*') + ->name('api.client.servers.files.download'); + }); + + Route::group(['prefix' => '/network'], function () { + Route::get('/', 'Servers\NetworkController@index')->name('api.client.servers.network'); + }); }); diff --git a/routes/auth.php b/routes/auth.php index 071ddabf..a6038447 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -9,16 +9,27 @@ | */ Route::group(['middleware' => 'guest'], function () { - Route::get('/login', 'LoginController@showLoginForm')->name('auth.login'); - Route::get('/login/totp', 'LoginController@totp')->name('auth.totp'); - Route::get('/password', 'ForgotPasswordController@showLinkRequestForm')->name('auth.password'); - Route::get('/password/reset/{token}', 'ResetPasswordController@showResetForm')->name('auth.reset'); + // These routes are defined so that we can continue to reference them programatically. + // They all route to the same controller function which passes off to Vuejs. + Route::get('/login', 'LoginController@index')->name('auth.login'); + Route::get('/password', 'LoginController@index')->name('auth.forgot-password'); + Route::get('/password/reset/{token}', 'LoginController@index')->name('auth.reset'); + // Login endpoints. Route::post('/login', 'LoginController@login')->middleware('recaptcha'); - Route::post('/login/totp', 'LoginController@loginUsingTotp'); + Route::post('/login/checkpoint', 'LoginCheckpointController')->name('auth.login-checkpoint'); + + // Forgot password route. A post to this endpoint will trigger an + // email to be sent containing a reset token. Route::post('/password', 'ForgotPasswordController@sendResetLinkEmail')->middleware('recaptcha'); - Route::post('/password/reset', 'ResetPasswordController@reset')->name('auth.reset.post')->middleware('recaptcha'); - Route::post('/password/reset/{token}', 'ForgotPasswordController@sendResetLinkEmail')->middleware('recaptcha'); + + // Password reset routes. This endpoint is hit after going through + // the forgot password routes to acquire a token (or after an account + // is created). + Route::post('/password/reset', 'ResetPasswordController')->name('auth.reset-password')->middleware('recaptcha'); + + // Catch any other combinations of routes and pass them off to the Vuejs component. + Route::fallback('LoginController@index'); }); /* diff --git a/routes/base.php b/routes/base.php index 4955afd4..dbdad971 100644 --- a/routes/base.php +++ b/routes/base.php @@ -1,27 +1,7 @@ . - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ -Route::get('/', 'IndexController@getIndex')->name('index'); -Route::get('/status/{server}', 'IndexController@status')->name('index.status'); -/* -|-------------------------------------------------------------------------- -| Account Controller Routes -|-------------------------------------------------------------------------- -| -| Endpoint: /account -| -*/ -Route::group(['prefix' => 'account'], function () { - Route::get('/', 'AccountController@index')->name('account'); - - Route::post('/', 'AccountController@update'); -}); +Route::get('/', 'IndexController@index')->name('index')->fallback(); +Route::get('/account', 'IndexController@index')->name('account'); /* |-------------------------------------------------------------------------- @@ -34,9 +14,7 @@ Route::group(['prefix' => 'account'], function () { Route::group(['prefix' => 'account/api'], function () { Route::get('/', 'ClientApiController@index')->name('account.api'); Route::get('/new', 'ClientApiController@create')->name('account.api.new'); - Route::post('/new', 'ClientApiController@store'); - Route::delete('/revoke/{identifier}', 'ClientApiController@delete')->name('account.api.revoke'); }); @@ -48,13 +26,11 @@ Route::group(['prefix' => 'account/api'], function () { | Endpoint: /account/security | */ -Route::group(['prefix' => 'account/security'], function () { - Route::get('/', 'SecurityController@index')->name('account.security'); - Route::get('/revoke/{id}', 'SecurityController@revoke')->name('account.security.revoke'); - - Route::put('/totp', 'SecurityController@generateTotp')->name('account.security.totp'); - - Route::post('/totp', 'SecurityController@setTotp')->name('account.security.totp.set'); - - Route::delete('/totp', 'SecurityController@disableTotp')->name('account.security.totp.disable'); +Route::group(['prefix' => 'account/two_factor'], function () { + Route::get('/', 'SecurityController@index')->name('account.two_factor'); + Route::post('/totp', 'SecurityController@store')->name('account.two_factor.enable'); + Route::post('/totp/disable', 'SecurityController@delete')->name('account.two_factor.disable'); }); + +Route::get('/{vue}', 'IndexController@index') + ->where('vue', '^(?!(\/)?(api|admin|daemon)).+'); diff --git a/routes/server.php b/routes/server.php index f5d06b7e..4bcc2d83 100644 --- a/routes/server.php +++ b/routes/server.php @@ -6,104 +6,13 @@ * This software is licensed under the terms of the MIT license. * https://opensource.org/licenses/MIT */ -Route::get('/', 'ConsoleController@index')->name('server.index'); -Route::get('/console', 'ConsoleController@console')->name('server.console'); +Route::get('/credentials', 'CredentialsController@index')->name('server.credentials'); -/* -|-------------------------------------------------------------------------- -| Server Settings Controller Routes -|-------------------------------------------------------------------------- -| -| Endpoint: /server/{server}/settings -| -*/ -Route::group(['prefix' => 'settings'], function () { - Route::get('/allocation', 'Settings\AllocationController@index')->name('server.settings.allocation'); - Route::get('/name', 'Settings\NameController@index')->name('server.settings.name'); - Route::get('/sftp', 'Settings\SftpController@index')->name('server.settings.sftp'); - Route::get('/startup', 'Settings\StartupController@index')->name('server.settings.startup'); - - Route::patch('/allocation', 'Settings\AllocationController@update'); - Route::patch('/name', 'Settings\NameController@update'); - Route::patch('/startup', 'Settings\StartupController@update'); +Route::group(['prefix' => '/files'], function () { + Route::get('/{directory?}', 'FileController@index') + ->name('server.files') + ->where('directory', '.*'); }); -/* -|-------------------------------------------------------------------------- -| Server Database Controller Routes -|-------------------------------------------------------------------------- -| -| Endpoint: /server/{server}/databases -| -*/ -Route::group(['prefix' => 'databases'], function () { - Route::get('/', 'DatabaseController@index')->name('server.databases.index'); - - Route::post('/new', 'DatabaseController@store')->name('server.databases.new'); - - Route::patch('/password', 'DatabaseController@update')->middleware('server..database')->name('server.databases.password'); - - Route::delete('/delete/{database}', 'DatabaseController@delete')->middleware('server..database')->name('server.databases.delete'); -}); - -/* -|-------------------------------------------------------------------------- -| Server File Manager Controller Routes -|-------------------------------------------------------------------------- -| -| Endpoint: /server/{server}/files -| -*/ -Route::group(['prefix' => 'files'], function () { - Route::get('/', 'Files\FileActionsController@index')->name('server.files.index'); - Route::get('/add', 'Files\FileActionsController@create')->name('server.files.add'); - Route::get('/edit/{file}', 'Files\FileActionsController@view')->name('server.files.edit')->where('file', '.*'); - Route::get('/download/{file}', 'Files\DownloadController@index')->name('server.files.edit')->where('file', '.*'); - - Route::post('/directory-list', 'Files\RemoteRequestController@directory')->name('server.files.directory-list'); - Route::post('/save', 'Files\RemoteRequestController@store')->name('server.files.save'); -}); - -/* -|-------------------------------------------------------------------------- -| Server Subuser Controller Routes -|-------------------------------------------------------------------------- -| -| Endpoint: /server/{server}/users -| -*/ -Route::group(['prefix' => 'users'], function () { - Route::get('/', 'SubuserController@index')->name('server.subusers'); - Route::get('/new', 'SubuserController@create')->name('server.subusers.new'); - Route::post('/new', 'SubuserController@store'); - - Route::group(['middleware' => 'server..subuser'], function () { - Route::get('/view/{subuser}', 'SubuserController@view')->name('server.subusers.view'); - Route::patch('/view/{subuser}', 'SubuserController@update'); - Route::delete('/view/{subuser}', 'SubuserController@delete'); - }); -}); - -/* -|-------------------------------------------------------------------------- -| Server Task Controller Routes -|-------------------------------------------------------------------------- -| -| Endpoint: /server/{server}/tasks -| -*/ -Route::group(['prefix' => 'schedules'], function () { - Route::get('/', 'Tasks\TaskManagementController@index')->name('server.schedules'); - Route::get('/new', 'Tasks\TaskManagementController@create')->name('server.schedules.new'); - Route::post('/new', 'Tasks\TaskManagementController@store'); - - Route::group(['middleware' => 'server..schedule'], function () { - Route::get('/view/{schedule}', 'Tasks\TaskManagementController@view')->name('server.schedules.view'); - - Route::patch('/view/{schedule}', 'Tasks\TaskManagementController@update'); - Route::post('/view/{schedule}/toggle', 'Tasks\ActionController@toggle')->name('server.schedules.toggle'); - Route::post('/view/{schedule}/trigger', 'Tasks\ActionController@trigger')->name('server.schedules.trigger'); - - Route::delete('/view/{schedule}', 'Tasks\TaskManagementController@delete'); - }); -}); +Route::get('/')->name('server.index'); +Route::get('/console')->name('server.console'); diff --git a/tailwind.js b/tailwind.js new file mode 100644 index 00000000..549d371c --- /dev/null +++ b/tailwind.js @@ -0,0 +1,912 @@ +/* + +Tailwind - The Utility-First CSS Framework + +A project by Adam Wathan (@adamwathan), Jonathan Reinink (@reinink), +David Hemphill (@davidhemphill) and Steve Schoger (@steveschoger). + +Welcome to the Tailwind config file. This is where you can customize +Tailwind specifically for your project. Don't be intimidated by the +length of this file. It's really just a big JavaScript object and +we've done our very best to explain each section. + +View the full documentation at https://tailwindcss.com. + + +|------------------------------------------------------------------------------- +| The default config +|------------------------------------------------------------------------------- +| +| This variable contains the default Tailwind config. You don't have +| to use it, but it can sometimes be helpful to have available. For +| example, you may choose to merge your custom configuration +| values with some of the Tailwind defaults. +| +*/ + +// let defaultConfig = require('tailwindcss/defaultConfig')() + +/* +|------------------------------------------------------------------------------- +| Colors https://tailwindcss.com/docs/colors +|------------------------------------------------------------------------------- +| +| Here you can specify the colors used in your project. To get you started, +| we've provided a generous palette of great looking colors that are perfect +| for prototyping, but don't hesitate to change them for your project. You +| own these colors, nothing will break if you change everything about them. +| +| We've used literal color names ("red", "blue", etc.) for the default +| palette, but if you'd rather use functional names like "primary" and +| "secondary", or even a numeric scale like "100" and "200", go for it. +| +*/ + +let colors = { + 'transparent': 'transparent', + + 'black': '#1F2933', + 'white': '#ffffff', + 'basically-white': '#fafafb', + + // The design's primary colors. Splashes of color that should appear the most + // within the UI and determine the overall look of the site. + 'primary-50': 'hsl(202, 100%, 95%)', // lightest + 'primary-100': 'hsl(204, 100%, 86%)', // lighter + 'primary-200': 'hsl(206, 93%, 73%)', + 'primary-300': 'hsl(208, 88%, 62%)', + 'primary-400': 'hsl(210, 83%, 53%)', // light + 'primary-500': 'hsl(212, 92%, 43%)', // base + 'primary-600': 'hsl(214, 95%, 36%)', // dark + 'primary-700': 'hsl(215, 96%, 32%)', + 'primary-800': 'hsl(216, 98%, 25%)', // darker + 'primary-900': 'hsl(218, 100%, 17%)', //darkest + + // Color used the most in the design and make up the majority of the UI. + 'neutral-50': 'hsl(216, 33%, 97%)', + 'neutral-100': 'hsl(214, 15%, 91%)', + 'neutral-200': 'hsl(210, 16%, 82%)', + 'neutral-300': 'hsl(211, 13%, 65%)', + 'neutral-400': 'hsl(211, 10%, 53%)', + 'neutral-500': 'hsl(211, 12%, 43%)', + 'neutral-600': 'hsl(209, 14%, 37%)', + 'neutral-700': 'hsl(209, 18%, 30%)', + 'neutral-800': 'hsl(209, 20%, 25%)', + 'neutral-900': 'hsl(210, 24%, 16%)', + + // Supporting colors used to make an element stand out or re-inforce error + // states or trends. + 'red-50': 'hsl(360, 100%, 95%)', + 'red-100': 'hsl(360, 100%, 87%)', + 'red-200': 'hsl(360, 100%, 80%)', + 'red-300': 'hsl(360, 91%, 69%)', + 'red-400': 'hsl(360, 83%, 62%)', + 'red-500': 'hsl(356, 75%, 53%)', + 'red-600': 'hsl(354, 85%, 44%)', + 'red-700': 'hsl(352, 90%, 35%)', + 'red-800': 'hsl(350, 94%, 28%)', + 'red-900': 'hsl(348, 94%, 20%)', + + 'yellow-50': 'hsl(49, 100%, 96%)', + 'yellow-100': 'hsl(48, 100%, 88%)', + 'yellow-200': 'hsl(48, 95%, 76%)', + 'yellow-300': 'hsl(48, 94%, 68%)', + 'yellow-400': 'hsl(44, 92%, 63%)', + 'yellow-500': 'hsl(42, 87%, 55%)', + 'yellow-600': 'hsl(36, 77%, 49%)', + 'yellow-700': 'hsl(29, 80%, 44%)', + 'yellow-800': 'hsl(22, 82%, 39%)', + 'yellow-900': 'hsl(15, 86%, 30%)', + + 'cyan-50': 'hsl(171, 82%, 94%)', + 'cyan-100': 'hsl(172, 97%, 88%)', + 'cyan-200': 'hsl(174, 96%, 78%)', + 'cyan-300': 'hsl(176, 87%, 67%)', + 'cyan-400': 'hsl(178, 78%, 57%)', + 'cyan-500': 'hsl(180, 77%, 47%)', + 'cyan-600': 'hsl(182, 85%, 39%)', + 'cyan-700': 'hsl(184, 90%, 34%)', + 'cyan-800': 'hsl(186, 91%, 29%)', + 'cyan-900': 'hsl(188, 91%, 23%)', + + 'green-50': 'hsl(125, 65%, 93%)', + 'green-100': 'hsl(127, 65%, 85%)', + 'green-200': 'hsl(124, 63%, 74%)', + 'green-300': 'hsl(123, 53%, 55%)', + 'green-400': 'hsl(123, 57%, 45%)', + 'green-500': 'hsl(122, 73%, 35%)', + 'green-600': 'hsl(122, 80%, 29%)', + 'green-700': 'hsl(125, 79%, 26%)', + 'green-800': 'hsl(125, 86%, 20%)', + 'green-900': 'hsl(125, 97%, 14%)', +}; + +module.exports = { + + /* + |----------------------------------------------------------------------------- + | Colors https://tailwindcss.com/docs/colors + |----------------------------------------------------------------------------- + | + | The color palette defined above is also assigned to the "colors" key of + | your Tailwind config. This makes it easy to access them in your CSS + | using Tailwind's config helper. For example: + | + | .error { color: config('colors.red') } + | + */ + + colors: colors, + + /* + |----------------------------------------------------------------------------- + | Screens https://tailwindcss.com/docs/responsive-design + |----------------------------------------------------------------------------- + | + | Screens in Tailwind are translated to CSS media queries. They define the + | responsive breakpoints for your project. By default Tailwind takes a + | "mobile first" approach, where each screen size represents a minimum + | viewport width. Feel free to have as few or as many screens as you + | want, naming them in whatever way you'd prefer for your project. + | + | Tailwind also allows for more complex screen definitions, which can be + | useful in certain situations. Be sure to see the full responsive + | documentation for a complete list of options. + | + | Class name: .{screen}:{utility} + | + */ + + screens: { + 'sm': '576px', + 'md': '768px', + 'lg': '992px', + 'xl': '1200px', + + 'xsx': {'max': '575px'}, + 'smx': {'max': '767px'}, + 'mdx': {'max': '991px'}, + 'lgx': {'max': '1999px'}, + }, + + /* + |----------------------------------------------------------------------------- + | Fonts https://tailwindcss.com/docs/fonts + |----------------------------------------------------------------------------- + | + | Here is where you define your project's font stack, or font families. + | Keep in mind that Tailwind doesn't actually load any fonts for you. + | If you're using custom fonts you'll need to import them prior to + | defining them here. + | + | By default we provide a native font stack that works remarkably well on + | any device or OS you're using, since it just uses the default fonts + | provided by the platform. + | + | Class name: .font-{name} + | + */ + + fonts: { + 'sans': [ + '-apple-system', + 'BlinkMacSystemFont', + '"Helvetica Neue"', + '"Roboto"', + 'system-ui', + 'sans-serif', + ], + 'serif': [ + 'Constantia', + '"Lucida Bright"', + 'Lucidabright', + '"Lucida Serif"', + 'Lucida', + 'serif', + ], + 'mono': [ + 'Menlo', + 'Monaco', + 'Consolas', + 'monospace', + ] + }, + + /* + |----------------------------------------------------------------------------- + | Text sizes https://tailwindcss.com/docs/text-sizing + |----------------------------------------------------------------------------- + | + | Here is where you define your text sizes. Name these in whatever way + | makes the most sense to you. We use size names by default, but + | you're welcome to use a numeric scale or even something else + | entirely. + | + | By default Tailwind uses the "rem" unit type for most measurements. + | This allows you to set a root font size which all other sizes are + | then based on. That said, you are free to use whatever units you + | prefer, be it rems, ems, pixels or other. + | + | Class name: .text-{size} + | + */ + + textSizes: { + 'xs': '.75rem', // 12px + 'sm': '.875rem', // 14px + 'base': '1rem', // 16px + 'lg': '1.125rem', // 18px + 'xl': '1.25rem', // 20px + '2xl': '1.5rem', // 24px + '3xl': '1.875rem', // 30px + '4xl': '2.25rem', // 36px + '5xl': '3rem', // 48px + }, + + /* + |----------------------------------------------------------------------------- + | Font weights https://tailwindcss.com/docs/font-weight + |----------------------------------------------------------------------------- + | + | Here is where you define your font weights. We've provided a list of + | common font weight names with their respective numeric scale values + | to get you started. It's unlikely that your project will require + | all of these, so we recommend removing those you don't need. + | + | Class name: .font-{weight} + | + */ + + fontWeights: { + 'hairline': 100, + 'thin': 200, + 'light': 300, + 'normal': 400, + 'medium': 500, + 'semibold': 600, + 'bold': 700, + 'extrabold': 800, + 'black': 900, + }, + + /* + |----------------------------------------------------------------------------- + | Leading (line height) https://tailwindcss.com/docs/line-height + |----------------------------------------------------------------------------- + | + | Here is where you define your line height values, or as we call + | them in Tailwind, leadings. + | + | Class name: .leading-{size} + | + */ + + leading: { + 'none': 1, + 'tight': 1.25, + 'normal': 1.5, + 'loose': 2, + }, + + /* + |----------------------------------------------------------------------------- + | Tracking (letter spacing) https://tailwindcss.com/docs/letter-spacing + |----------------------------------------------------------------------------- + | + | Here is where you define your letter spacing values, or as we call + | them in Tailwind, tracking. + | + | Class name: .tracking-{size} + | + */ + + tracking: { + 'tight': '-0.05em', + 'normal': '0', + 'wide': '0.05em', + }, + + /* + |----------------------------------------------------------------------------- + | Text colors https://tailwindcss.com/docs/text-color + |----------------------------------------------------------------------------- + | + | Here is where you define your text colors. By default these use the + | color palette we defined above, however you're welcome to set these + | independently if that makes sense for your project. + | + | Class name: .text-{color} + | + */ + + textColors: colors, + + /* + |----------------------------------------------------------------------------- + | Background colors https://tailwindcss.com/docs/background-color + |----------------------------------------------------------------------------- + | + | Here is where you define your background colors. By default these use + | the color palette we defined above, however you're welcome to set + | these independently if that makes sense for your project. + | + | Class name: .bg-{color} + | + */ + + backgroundColors: colors, + + /* + |----------------------------------------------------------------------------- + | Background sizes https://tailwindcss.com/docs/background-size + |----------------------------------------------------------------------------- + | + | Here is where you define your background sizes. We provide some common + | values that are useful in most projects, but feel free to add other sizes + | that are specific to your project here as well. + | + | Class name: .bg-{size} + | + */ + + backgroundSize: { + 'auto': 'auto', + 'cover': 'cover', + 'contain': 'contain', + }, + + /* + |----------------------------------------------------------------------------- + | Border widths https://tailwindcss.com/docs/border-width + |----------------------------------------------------------------------------- + | + | Here is where you define your border widths. Take note that border + | widths require a special "default" value set as well. This is the + | width that will be used when you do not specify a border width. + | + | Class name: .border{-side?}{-width?} + | + */ + + borderWidths: { + default: '1px', + '0': '0', + '2': '2px', + '3': '3px', + '4': '4px', + '8': '8px', + }, + + /* + |----------------------------------------------------------------------------- + | Border colors https://tailwindcss.com/docs/border-color + |----------------------------------------------------------------------------- + | + | Here is where you define your border colors. By default these use the + | color palette we defined above, however you're welcome to set these + | independently if that makes sense for your project. + | + | Take note that border colors require a special "default" value set + | as well. This is the color that will be used when you do not + | specify a border color. + | + | Class name: .border-{color} + | + */ + + borderColors: global.Object.assign({default: colors['neutral-400']}, colors), + + /* + |----------------------------------------------------------------------------- + | Border radius https://tailwindcss.com/docs/border-radius + |----------------------------------------------------------------------------- + | + | Here is where you define your border radius values. If a `default` radius + | is provided, it will be made available as the non-suffixed `.rounded` + | utility. + | + | If your scale includes a `0` value to reset already rounded corners, it's + | a good idea to put it first so other values are able to override it. + | + | Class name: .rounded{-side?}{-size?} + | + */ + + borderRadius: { + 'none': '0', + 'sm': '.125rem', + default: '.25rem', + 'lg': '.5rem', + 'full': '9999px', + }, + + /* + |----------------------------------------------------------------------------- + | Width https://tailwindcss.com/docs/width + |----------------------------------------------------------------------------- + | + | Here is where you define your width utility sizes. These can be + | percentage based, pixels, rems, or any other units. By default + | we provide a sensible rem based numeric scale, a percentage + | based fraction scale, plus some other common use-cases. You + | can, of course, modify these values as needed. + | + | + | It's also worth mentioning that Tailwind automatically escapes + | invalid CSS class name characters, which allows you to have + | awesome classes like .w-2/3. + | + | Class name: .w-{size} + | + */ + + width: { + 'auto': 'auto', + 'px': '1px', + '1': '0.25rem', + '2': '0.5rem', + '3': '0.75rem', + '4': '1rem', + '6': '1.5rem', + '8': '2rem', + '10': '2.5rem', + '12': '3rem', + '16': '4rem', + '24': '6rem', + '32': '8rem', + '48': '12rem', + '64': '16rem', + '96': '24rem', + '1/2': '50%', + '1/3': '33.33333%', + '2/3': '66.66667%', + '1/4': '25%', + '3/4': '75%', + '1/5': '20%', + '2/5': '40%', + '3/5': '60%', + '4/5': '80%', + '1/6': '16.66667%', + '5/6': '83.33333%', + 'full': '100%', + 'screen': '100vw' + }, + + /* + |----------------------------------------------------------------------------- + | Height https://tailwindcss.com/docs/height + |----------------------------------------------------------------------------- + | + | Here is where you define your height utility sizes. These can be + | percentage based, pixels, rems, or any other units. By default + | we provide a sensible rem based numeric scale plus some other + | common use-cases. You can, of course, modify these values as + | needed. + | + | Class name: .h-{size} + | + */ + + height: { + 'auto': 'auto', + 'px': '1px', + '1': '0.25rem', + '2': '0.5rem', + '3': '0.75rem', + '4': '1rem', + '6': '1.5rem', + '8': '2rem', + '10': '2.5rem', + '12': '3rem', + '16': '4rem', + '24': '6rem', + '32': '8rem', + '48': '12rem', + '64': '16rem', + 'full': '100%', + 'screen': '100vh' + }, + + /* + |----------------------------------------------------------------------------- + | Minimum width https://tailwindcss.com/docs/min-width + |----------------------------------------------------------------------------- + | + | Here is where you define your minimum width utility sizes. These can + | be percentage based, pixels, rems, or any other units. We provide a + | couple common use-cases by default. You can, of course, modify + | these values as needed. + | + | Class name: .min-w-{size} + | + */ + + minWidth: { + '0': '0', + 'full': '100%', + }, + + /* + |----------------------------------------------------------------------------- + | Minimum height https://tailwindcss.com/docs/min-height + |----------------------------------------------------------------------------- + | + | Here is where you define your minimum height utility sizes. These can + | be percentage based, pixels, rems, or any other units. We provide a + | few common use-cases by default. You can, of course, modify these + | values as needed. + | + | Class name: .min-h-{size} + | + */ + + minHeight: { + '0': '0', + 'full': '100%', + 'screen': '100vh' + }, + + /* + |----------------------------------------------------------------------------- + | Maximum width https://tailwindcss.com/docs/max-width + |----------------------------------------------------------------------------- + | + | Here is where you define your maximum width utility sizes. These can + | be percentage based, pixels, rems, or any other units. By default + | we provide a sensible rem based scale and a "full width" size, + | which is basically a reset utility. You can, of course, + | modify these values as needed. + | + | Class name: .max-w-{size} + | + */ + + maxWidth: { + 'xxs': '10rem', + 'xs': '20rem', + 'sm': '30rem', + 'md': '40rem', + 'lg': '50rem', + 'xl': '60rem', + '2xl': '70rem', + '3xl': '80rem', + '4xl': '90rem', + '5xl': '100rem', + 'full': '100%', + }, + + /* + |----------------------------------------------------------------------------- + | Maximum height https://tailwindcss.com/docs/max-height + |----------------------------------------------------------------------------- + | + | Here is where you define your maximum height utility sizes. These can + | be percentage based, pixels, rems, or any other units. We provide a + | couple common use-cases by default. You can, of course, modify + | these values as needed. + | + | Class name: .max-h-{size} + | + */ + + maxHeight: { + 'full': '100%', + 'screen': '100vh', + }, + + /* + |----------------------------------------------------------------------------- + | Padding https://tailwindcss.com/docs/padding + |----------------------------------------------------------------------------- + | + | Here is where you define your padding utility sizes. These can be + | percentage based, pixels, rems, or any other units. By default we + | provide a sensible rem based numeric scale plus a couple other + | common use-cases like "1px". You can, of course, modify these + | values as needed. + | + | Class name: .p{side?}-{size} + | + */ + + padding: { + 'px': '1px', + '0': '0', + '1': '0.25rem', + '2': '0.5rem', + '3': '0.75rem', + '4': '1rem', + '5': '1.25rem', + '6': '1.5rem', + '8': '2rem', + '10': '2.5rem', + '12': '3rem', + '16': '4rem', + '20': '5rem', + '24': '6rem', + '32': '8rem', + }, + + /* + |----------------------------------------------------------------------------- + | Margin https://tailwindcss.com/docs/margin + |----------------------------------------------------------------------------- + | + | Here is where you define your margin utility sizes. These can be + | percentage based, pixels, rems, or any other units. By default we + | provide a sensible rem based numeric scale plus a couple other + | common use-cases like "1px". You can, of course, modify these + | values as needed. + | + | Class name: .m{side?}-{size} + | + */ + + margin: { + 'auto': 'auto', + 'px': '1px', + '0': '0', + '1': '0.25rem', + '2': '0.5rem', + '3': '0.75rem', + '4': '1rem', + '5': '1.25rem', + '6': '1.5rem', + '8': '2rem', + '10': '2.5rem', + '12': '3rem', + '16': '4rem', + '20': '5rem', + '24': '6rem', + '32': '8rem', + }, + + /* + |----------------------------------------------------------------------------- + | Negative margin https://tailwindcss.com/docs/negative-margin + |----------------------------------------------------------------------------- + | + | Here is where you define your negative margin utility sizes. These can + | be percentage based, pixels, rems, or any other units. By default we + | provide matching values to the padding scale since these utilities + | generally get used together. You can, of course, modify these + | values as needed. + | + | Class name: .-m{side?}-{size} + | + */ + + negativeMargin: { + 'px': '1px', + '0': '0', + '1': '0.25rem', + '2': '0.5rem', + '3': '0.75rem', + '4': '1rem', + '5': '1.25rem', + '6': '1.5rem', + '8': '2rem', + '10': '2.5rem', + '12': '3rem', + '16': '4rem', + '20': '5rem', + '24': '6rem', + '32': '8rem', + }, + + /* + |----------------------------------------------------------------------------- + | Shadows https://tailwindcss.com/docs/shadows + |----------------------------------------------------------------------------- + | + | Here is where you define your shadow utilities. As you can see from + | the defaults we provide, it's possible to apply multiple shadows + | per utility using comma separation. + | + | If a `default` shadow is provided, it will be made available as the non- + | suffixed `.shadow` utility. + | + | Class name: .shadow-{size?} + | + */ + + shadows: { + default: '0 2px 4px 0 rgba(0,0,0,0.10)', + 'md': '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08)', + 'lg': '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)', + 'inner': 'inset 0 2px 4px 0 rgba(0,0,0,0.06)', + 'outline': '0 0 0 3px rgba(52,144,220,0.5)', + 'none': 'none', + }, + + /* + |----------------------------------------------------------------------------- + | Z-index https://tailwindcss.com/docs/z-index + |----------------------------------------------------------------------------- + | + | Here is where you define your z-index utility values. By default we + | provide a sensible numeric scale. You can, of course, modify these + | values as needed. + | + | Class name: .z-{index} + | + */ + + zIndex: { + 'auto': 'auto', + '0': 0, + '10': 10, + '20': 20, + '30': 30, + '40': 40, + '50': 50, + }, + + /* + |----------------------------------------------------------------------------- + | Opacity https://tailwindcss.com/docs/opacity + |----------------------------------------------------------------------------- + | + | Here is where you define your opacity utility values. By default we + | provide a sensible numeric scale. You can, of course, modify these + | values as needed. + | + | Class name: .opacity-{name} + | + */ + + opacity: { + '0': '0', + '25': '.25', + '50': '.5', + '75': '.75', + '100': '1', + }, + + /* + |----------------------------------------------------------------------------- + | SVG fill https://tailwindcss.com/docs/svg + |----------------------------------------------------------------------------- + | + | Here is where you define your SVG fill colors. By default we just provide + | `fill-current` which sets the fill to the current text color. This lets you + | specify a fill color using existing text color utilities and helps keep the + | generated CSS file size down. + | + | Class name: .fill-{name} + | + */ + + svgFill: { + 'current': 'currentColor', + }, + + /* + |----------------------------------------------------------------------------- + | SVG stroke https://tailwindcss.com/docs/svg + |----------------------------------------------------------------------------- + | + | Here is where you define your SVG stroke colors. By default we just provide + | `stroke-current` which sets the stroke to the current text color. This lets + | you specify a stroke color using existing text color utilities and helps + | keep the generated CSS file size down. + | + | Class name: .stroke-{name} + | + */ + + svgStroke: { + 'current': 'currentColor', + }, + + /* + |----------------------------------------------------------------------------- + | Modules https://tailwindcss.com/docs/configuration#modules + |----------------------------------------------------------------------------- + | + | Here is where you control which modules are generated and what variants are + | generated for each of those modules. + | + | Currently supported variants: + | - responsive + | - hover + | - focus + | - active + | - group-hover + | + | To disable a module completely, use `false` instead of an array. + | + */ + + modules: { + appearance: ['responsive'], + backgroundAttachment: ['responsive'], + backgroundColors: ['responsive', 'hover', 'focus'], + backgroundPosition: ['responsive'], + backgroundRepeat: ['responsive'], + backgroundSize: ['responsive'], + borderCollapse: [], + borderColors: ['responsive', 'hover', 'focus'], + borderRadius: ['responsive'], + borderStyle: ['responsive'], + borderWidths: ['responsive'], + cursor: ['responsive'], + display: ['responsive'], + flexbox: ['responsive'], + float: ['responsive'], + fonts: ['responsive'], + fontWeights: ['responsive', 'hover', 'focus'], + height: ['responsive'], + leading: ['responsive'], + lists: ['responsive'], + margin: ['responsive'], + maxHeight: ['responsive'], + maxWidth: ['responsive'], + minHeight: ['responsive'], + minWidth: ['responsive'], + negativeMargin: ['responsive'], + opacity: ['responsive'], + outline: ['focus'], + overflow: ['responsive'], + padding: ['responsive'], + pointerEvents: ['responsive'], + position: ['responsive'], + resize: ['responsive'], + shadows: ['responsive', 'hover', 'focus'], + svgFill: [], + svgStroke: [], + tableLayout: ['responsive'], + textAlign: ['responsive'], + textColors: ['responsive', 'hover', 'focus'], + textSizes: ['responsive'], + textStyle: ['responsive', 'hover', 'focus'], + tracking: ['responsive'], + userSelect: ['responsive'], + verticalAlign: ['responsive'], + visibility: ['responsive'], + whitespace: ['responsive'], + width: ['responsive'], + zIndex: ['responsive'], + }, + + /* + |----------------------------------------------------------------------------- + | Plugins https://tailwindcss.com/docs/plugins + |----------------------------------------------------------------------------- + | + | Here is where you can register any plugins you'd like to use in your + | project. Tailwind's built-in `container` plugin is enabled by default to + | give you a Bootstrap-style responsive container component out of the box. + | + | Be sure to view the complete plugin documentation to learn more about how + | the plugin system works. + | + */ + + plugins: [ + require('tailwindcss/plugins/container')({ + center: true, + }), + ], + + /* + |----------------------------------------------------------------------------- + | Advanced Options https://tailwindcss.com/docs/configuration#options + |----------------------------------------------------------------------------- + | + | Here is where you can tweak advanced configuration options. We recommend + | leaving these options alone unless you absolutely need to change them. + | + */ + + options: { + prefix: '', + important: false, + separator: ':', + }, + + experiments: { + shadowLookup: true, + }, + +}; diff --git a/tests/Browser/BrowserTestCase.php b/tests/Browser/BrowserTestCase.php new file mode 100644 index 00000000..825978d3 --- /dev/null +++ b/tests/Browser/BrowserTestCase.php @@ -0,0 +1,122 @@ +make(Kernel::class); + + $kernel->bootstrap(); + $kernel->call('migrate:fresh'); + } + + /** + * Setup tests. + */ + protected function setUp() + { + // Don't accidentally run the migrations aganist the non-testing database. Ask me + // how many times I've accidentally dropped my database... + if (env('DB_CONNECTION') !== 'testing') { + throw new BadMethodCallException('Cannot call browser tests using the non-testing database connection.'); + } + + parent::setUp(); + + // Gotta unset this to continue avoiding issues with the validation. + Model::unsetEventDispatcher(); + } + + /** + * Create the RemoteWebDriver instance. + * + * @return \Facebook\WebDriver\Remote\RemoteWebDriver + */ + protected function driver() + { + $options = (new ChromeOptions)->addArguments([ + '--disable-gpu', + '--disable-infobars', + ]); + + return RemoteWebDriver::create( + 'http://host.pterodactyl.local:4444/wd/hub', DesiredCapabilities::chrome()->setCapability( + ChromeOptions::CAPABILITY, $options + ) + ); + } + + /** + * Return an instance of the browser to be used for tests. + * + * @param \Facebook\WebDriver\Remote\RemoteWebDriver $driver + * @return \Pterodactyl\Tests\Browser\PterodactylBrowser + */ + protected function newBrowser($driver): PterodactylBrowser + { + return new PterodactylBrowser($driver); + } + + /** + * Tear down the test and delete all cookies from the browser instance to address + * instances where the test would be kicked over to the login page. + */ + protected function tearDown() + { + /** @var \Pterodactyl\Tests\Browser\PterodactylBrowser $browser */ + foreach (static::$browsers as $browser) { + $browser->driver->manage()->deleteAllCookies(); + } + + parent::tearDown(); + } + + /** + * Return a user model to authenticate aganist and use in the tests. + * + * @param array $attributes + * @return \Pterodactyl\Models\User + */ + protected function user(array $attributes = []): User + { + return factory(User::class)->create(array_merge([ + 'password' => Hash::make(static::$userPassword), + ], $attributes)); + } +} diff --git a/tests/Browser/Pages/BasePage.php b/tests/Browser/Pages/BasePage.php new file mode 100644 index 00000000..c2e451a3 --- /dev/null +++ b/tests/Browser/Pages/BasePage.php @@ -0,0 +1,19 @@ + '.alert.success[role="alert"]', + '@@error' => '.alert.error[role="alert"]', + ]; + } +} diff --git a/tests/Browser/Pages/Dashboard/AccountPage.php b/tests/Browser/Pages/Dashboard/AccountPage.php new file mode 100644 index 00000000..e1aef4c2 --- /dev/null +++ b/tests/Browser/Pages/Dashboard/AccountPage.php @@ -0,0 +1,41 @@ + '#update-email-container #grid-email', + '@password' => '#update-email-container #grid-password[type="password"]', + '@submit' => '#update-email-container button[type="submit"]', + + '@current_password' => '#change-password-container #grid-password-current[type="password"]', + '@new_password' => '#change-password-container #grid-password-new[type="password"]', + '@confirm_password' => '#change-password-container #grid-password-new-confirm[type="password"]', + '@submit_password' => '#change-password-container button[type="submit"]', + + '@2fa_button' => '#grid-open-two-factor-modal', + '@2fa_modal' => '.modal-mask #configure-two-factor', + '@2fa_token' => '#configure-two-factor #container-enable-two-factor #grid-two-factor-token[type="number"]', + '@2fa_token_disable' => '#configure-two-factor #container-disable-two-factor #grid-two-factor-token-disable', + '@2fa_enable' => '#configure-two-factor #container-enable-two-factor button[type="submit"]', + '@2fa_disable' => '#configure-two-factor #container-disable-two-factor button.btn-red[type="submit"]', + '@2fa_cancel' => '#configure-two-factor #container-disable-two-factor button.btn-secondary', + ]); + } +} diff --git a/tests/Browser/Pages/LoginPage.php b/tests/Browser/Pages/LoginPage.php new file mode 100644 index 00000000..5fd42cbf --- /dev/null +++ b/tests/Browser/Pages/LoginPage.php @@ -0,0 +1,29 @@ + '#grid-email', + '@username' => '#grid-username', + '@password' => '#grid-password', + '@loginButton' => '#grid-login-button', + '@submitButton' => 'button.btn.btn-jumbo[type="submit"]', + '@forgotPassword' => 'a[href="/auth/password"][aria-label="Forgot password"]', + '@goToLogin' => 'a[href="/auth/login"][aria-label="Go to login"]', + '@alertSuccess' => 'div[role="alert"].success > span.message', + '@alertDanger' => 'div[role="alert"].danger > span.message', + ]; + } +} diff --git a/tests/Browser/Processes/Authentication/ForgotPasswordProcessTest.php b/tests/Browser/Processes/Authentication/ForgotPasswordProcessTest.php new file mode 100644 index 00000000..ab8c9bc8 --- /dev/null +++ b/tests/Browser/Processes/Authentication/ForgotPasswordProcessTest.php @@ -0,0 +1,50 @@ +browse(function (PterodactylBrowser $browser) { + $browser->visit(new LoginPage) + ->assertSee(trans('auth.forgot_password.label')) + ->click('@forgotPassword') + ->waitForLocation('/auth/password') + ->assertFocused('@email') + ->assertSeeIn('.input-open > p.text-xs', trans('auth.forgot_password.label_help')) + ->assertSeeIn('@submitButton', trans('auth.forgot_password.button')) + ->type('@email', 'unassociated@example.com') + ->assertSeeIn('@goToLogin', trans('auth.go_to_login')) + ->press('@submitButton') + ->waitForLocation('/auth/login') + ->assertSeeIn('div[role="alert"].success > span.message', 'We have e-mailed your password reset link!') + ->assertFocused('@username') + ->assertValue('@username', 'unassociated@example.com'); + }); + } + + /** + * Test that you can type in your email address and then click forgot password and have + * the email maintained on the new page. + */ + public function testEmailCarryover() + { + $this->browse(function (PterodactylBrowser $browser) { + $browser->visit(new LoginPage) + ->type('@username', 'dane@example.com') + ->click('@forgotPassword') + ->waitForLocation('/auth/password') + ->assertFocused('@email') + ->assertValue('@email', 'dane@example.com'); + }); + } +} diff --git a/tests/Browser/Processes/Authentication/LoginProcessTest.php b/tests/Browser/Processes/Authentication/LoginProcessTest.php new file mode 100644 index 00000000..c6e58dd7 --- /dev/null +++ b/tests/Browser/Processes/Authentication/LoginProcessTest.php @@ -0,0 +1,83 @@ +user = $this->user(); + } + + /** + * Test that a user can login successfully using their email address. + */ + public function testLoginUsingEmail() + { + $this->browse(function (PterodactylBrowser $browser) { + $browser->visit(new LoginPage) + ->waitFor('@username') + ->type('@username', $this->user->email) + ->type('@password', self::$userPassword) + ->click('@loginButton') + ->waitForReload() + ->assertPathIs('/') + ->assertAuthenticatedAs($this->user); + }); + } + + /** + * Test that a user can login successfully using their username. + */ + public function testLoginUsingUsername() + { + $this->browse(function (PterodactylBrowser $browser) { + $browser->visit(new LoginPage) + ->waitFor('@username') + ->type('@username', $this->user->username) + ->type('@password', self::$userPassword) + ->click('@loginButton') + ->waitForReload() + ->assertPathIs('/') + ->assertAuthenticatedAs($this->user); + }); + } + + /** + * Test that entering the wrong password shows the expected error and then allows + * us to login without clearing the username field. + */ + public function testLoginWithErrors() + { + $this->browse(function (PterodactylBrowser $browser) { + $browser->logout() + ->visit(new LoginPage()) + ->waitFor('@username') + ->type('@username', $this->user->email) + ->type('@password', 'invalid') + ->click('@loginButton') + ->waitFor('.alert.error') + ->assertSeeIn('.alert.error', trans('auth.failed')) + ->assertValue('@username', $this->user->email) + ->assertValue('@password', '') + ->assertFocused('@password') + ->type('@password', self::$userPassword) + ->keys('@password', [WebDriverKeys::ENTER]) + ->waitForReload() + ->assertPathIs('/') + ->assertAuthenticatedAs($this->user); + }); + } +} diff --git a/tests/Browser/Processes/Dashboard/AccountEmailProcessTest.php b/tests/Browser/Processes/Dashboard/AccountEmailProcessTest.php new file mode 100644 index 00000000..311312b2 --- /dev/null +++ b/tests/Browser/Processes/Dashboard/AccountEmailProcessTest.php @@ -0,0 +1,67 @@ +browse(function (PterodactylBrowser $browser) { + $browser->loginAs($this->user) + ->visit(new AccountPage) + ->assertValue('@email', $this->user->email) + ->type('@email', 'new.email@example.com') + ->type('@password', 'Password123') + ->click('@submit') + ->waitFor('@@success') + ->assertSeeIn('@@success', trans('dashboard/account.email.updated')) + ->assertValue('@email', 'new.email@example.com'); + + $this->assertDatabaseHas('users', ['id' => $this->user->id, 'email' => 'new.email@example.com']); + }); + } + + /** + * Test that the validation error message shows up when an invalid email is entered. + */ + public function testInvalidEmailShowsErrors() + { + $this->browse(function (PterodactylBrowser $browser) { + $browser->loginAs($this->user) + ->visit(new AccountPage) + ->assertMissing('@email ~ .input-help.error') + ->type('@email', 'admin') + ->assertVisible('@email ~ .input-help.error') + ->assertSeeIn('@email ~ .input-help.error', 'The email field must be a valid email.') + ->type('@email', 'admin@example.com') + ->assertMissing('@email ~ .input-help.error'); + }); + } + + /** + * Test that entering the wrong password for an account returns an error. + */ + public function testInvalidPasswordShowsError() + { + $this->browse(function (PterodactylBrowser $browser) { + $browser->loginAs($this->user) + ->visit(new AccountPage) + ->type('@email', 'new.email@example.com') + ->click('@submit') + ->assertFocused('@password') + ->type('@password', 'test1234') + ->click('@submit') + ->waitFor('@@error') + ->assertSeeIn('@@error', trans('validation.internal.invalid_password')) + ->assertValue('@email', 'new.email@example.com'); + + $this->assertDatabaseMissing('users', ['id' => $this->user->id, 'email' => 'new.email@example.com']); + }); + } +} diff --git a/tests/Browser/Processes/Dashboard/AccountPasswordProcessTest.php b/tests/Browser/Processes/Dashboard/AccountPasswordProcessTest.php new file mode 100644 index 00000000..0b5e4878 --- /dev/null +++ b/tests/Browser/Processes/Dashboard/AccountPasswordProcessTest.php @@ -0,0 +1,55 @@ +browse(function (PterodactylBrowser $browser) { + $browser->loginAs($this->user) + ->visit(new AccountPage) + ->type('@current_password', self::$userPassword) + ->assertMissing('@new_password ~ .input-help.error') + ->type('@new_password', 'test') + ->assertSeeIn('@new_password ~ .input-help.error', 'The password field must be at least 8 characters.') + ->type('@new_password', 'Test1234') + ->assertMissing('@new_password ~ .input-help.error') + ->assertMissing('@confirm_password ~ .input-help.error') + ->type('@confirm_password', 'test') + ->assertSeeIn('@confirm_password ~ .input-help.error', 'The password value is not valid.') + ->type('@confirm_password', 'Test1234') + ->assertMissing('@confirm_password ~ .input-help.error') + ->click('@submit_password') + ->waitFor('@@success') + ->assertSeeIn('@@success', 'Your password has been updated.') + ->assertInputValue('@current_password', '') + ->assertInputValue('@new_password', '') + ->assertInputValue('@confirm_password', ''); + }); + } + + /** + * Test that invalid passwords result in the expected error message. + */ + public function testInvalidPassword() + { + $this->browse(function (PterodactylBrowser $browser) { + $browser->loginAs($this->user) + ->visit(new AccountPage) + ->type('@current_password', 'badpassword') + ->type('@new_password', 'testtest') + ->type('@confirm_password', 'testtest') + ->click('@submit_password') + ->waitFor('@@error') + ->assertSeeIn('@@error', trans('validation.internal.invalid_password')) + ->assertInputValue('@current_password', ''); + }); + } +} diff --git a/tests/Browser/Processes/Dashboard/DashboardTestCase.php b/tests/Browser/Processes/Dashboard/DashboardTestCase.php new file mode 100644 index 00000000..b9641634 --- /dev/null +++ b/tests/Browser/Processes/Dashboard/DashboardTestCase.php @@ -0,0 +1,23 @@ +user = $this->user(); + } +} diff --git a/tests/Browser/Processes/Dashboard/TwoFactorAuthenticationProcessTest.php b/tests/Browser/Processes/Dashboard/TwoFactorAuthenticationProcessTest.php new file mode 100644 index 00000000..26a13048 --- /dev/null +++ b/tests/Browser/Processes/Dashboard/TwoFactorAuthenticationProcessTest.php @@ -0,0 +1,111 @@ +browse(function (PterodactylBrowser $browser) { + $browser->loginAs($this->user) + ->visit(new AccountPage) + ->assertMissing('.modal-mask') + ->click('@2fa_button') + ->waitFor('@2fa_modal') + ->pause(500)// seems to fix fragile test + ->clickPosition(100, 100) + ->waitUntilMissing('@2fa_modal') + ->click('@2fa_button') + ->waitFor('@2fa_modal') + ->click('svg[role="button"][aria-label="Close modal"]') + ->waitUntilMissing('@2fa_modal') + ->click('@2fa_button') + ->waitFor('@2fa_modal') + ->keys('', [WebDriverKeys::ESCAPE]) + ->waitUntilMissing('@2fa_modal'); + }); + } + + /** + * Test that a user that does not have two-factor enabled can enable it on their account. + */ + public function testTwoFactorCanBeEnabled() + { + $this->browse(function (PterodactylBrowser $browser) { + $browser->loginAs($this->user) + ->visit(new AccountPage) + ->click('@2fa_button') + ->waitForText(trans('dashboard/account.two_factor.setup.title')) + ->assertFocused('@2fa_token') + ->waitFor('#grid-qr-code') + ->assertSee(trans('dashboard/account.two_factor.setup.help')); + + // Grab information from the database so we can ensure the correct things are showing up. + // Also because we need to generate a code to send through and activate it with. + $updated = $this->user->fresh(); + + $secret = Crypt::decrypt($updated->totp_secret); + $code = (new Google2FA())->getCurrentOtp($secret); + + $browser->assertSeeIn('code', $secret) + ->assertVisible('@2fa_enable[disabled="disabled"]') + ->assertMissing('@2fa_token ~ .input-help.error') + ->type('@2fa_token', '12') + ->assertSeeIn('@2fa_token ~ .input-help.error', 'The token length must be 6.') + ->type('@2fa_token', $code) + ->assertMissing('@2fa_token ~ .input-help.error') + ->click('@2fa_enable') + ->waitUntilMissing('@2fa_modal') + ->assertSeeIn('@@success', trans('dashboard/account.two_factor.enabled')); + + $this->assertDatabaseHas('users', ['id' => $this->user->id, 'use_totp' => 1]); + }); + } + + /** + * Test that a user can disable two-factor authentication on thier account. + */ + public function testTwoFactorCanBeDisabled() + { + $secret = (new Google2FA)->generateSecretKey(16); + + $this->user->update([ + 'use_totp' => true, + 'totp_secret' => Crypt::encrypt($secret), + ]); + + $this->browse(function (PterodactylBrowser $browser) use ($secret) { + $browser->loginAs($this->user) + ->visit(new AccountPage) + ->click('@2fa_button') + ->waitForText(trans('dashboard/account.two_factor.disable.title')) + ->click('@2fa_cancel') + ->waitUntilMissing('@2fa_modal') + ->click('@2fa_button') + ->waitForText(trans('dashboard/account.two_factor.disable.title')) + ->assertVisible('@2fa_disable[disabled="disabled"]') + ->assertVisible('@2fa_cancel') + ->assertFocused('@2fa_token_disable') + ->assertMissing('@2fa_token_disable ~ .input-help.error') + ->type('@2fa_token_disable', '12') + ->assertSeeIn('@2fa_token_disable ~ .input-help.error', 'The token length must be 6.'); + + $token = (new Google2FA())->getCurrentOtp($secret); + + $browser->type('@2fa_token_disable', $token) + ->assertMissing('@2fa_token_disable ~ .input-help.error') + ->click('@2fa_disable') + ->waitUntilMissing('@2fa_modal') + ->assertSeeIn('@@success', trans('dashboard/account.two_factor.disabled')); + }); + } +} diff --git a/tests/Browser/PterodactylBrowser.php b/tests/Browser/PterodactylBrowser.php new file mode 100644 index 00000000..c7465ff3 --- /dev/null +++ b/tests/Browser/PterodactylBrowser.php @@ -0,0 +1,55 @@ +driver->getMouse()->mouseMove(null, $x, $y)->click(); + + return $this; + } + + /** + * Perform a case insensitive search for a string in the body. + * + * @param string $text + * @return \Pterodactyl\Tests\Browser\PterodactylBrowser + */ + public function assertSee($text) + { + return $this->assertSeeIn('', $text); + } + + /** + * Perform a case insensitive search for a string in a given selector. + * + * @param string $selector + * @param string $text + * @return \Pterodactyl\Tests\Browser\PterodactylBrowser + */ + public function assertSeeIn($selector, $text) + { + $fullSelector = $this->resolver->format($selector); + $element = $this->resolver->findOrFail($selector); + + PHPUnit::assertTrue( + Str::contains(mb_strtolower($element->getText()), mb_strtolower($text)), + "Did not see expected text [{$text}] within element [{$fullSelector}] using case-insensitive search." + ); + + return $this; + } +} diff --git a/tests/Browser/console/.gitignore b/tests/Browser/console/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/tests/Browser/console/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/Browser/screenshots/.gitignore b/tests/Browser/screenshots/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/tests/Browser/screenshots/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/Unit/Http/Controllers/Base/AccountControllerTest.php b/tests/Unit/Http/Controllers/Base/AccountControllerTest.php index dc6d69a5..e69de29b 100644 --- a/tests/Unit/Http/Controllers/Base/AccountControllerTest.php +++ b/tests/Unit/Http/Controllers/Base/AccountControllerTest.php @@ -1,132 +0,0 @@ -alert = m::mock(AlertsMessageBag::class); - $this->updateService = m::mock(UserUpdateService::class); - $this->authManager = m::mock(AuthManager::class); - $this->sessionGuard = m::mock(SessionGuard::class); - - $this->authManager->shouldReceive('guard')->once()->andReturn($this->sessionGuard); - } - - /** - * Test the index controller. - */ - public function testIndexController() - { - $response = $this->getController()->index(); - - $this->assertIsViewResponse($response); - $this->assertViewNameEquals('base.account', $response); - } - - /** - * Test controller when password is being updated. - */ - public function testUpdateControllerForPassword() - { - $this->setRequestMockClass(AccountDataFormRequest::class); - - $this->request->shouldReceive('input')->with('do_action')->andReturn('password'); - $this->request->shouldReceive('input')->with('new_password')->once()->andReturn('test-password'); - $this->sessionGuard->shouldReceive('logoutOtherDevices')->once()->with('test-password')->andReturnSelf(); - - $this->alert->shouldReceive('success->flash')->once()->andReturnNull(); - - $response = $this->getController()->update($this->request); - $this->assertIsRedirectResponse($response); - $this->assertRedirectRouteEquals('account', $response); - } - - /** - * Test controller when email is being updated. - */ - public function testUpdateControllerForEmail() - { - $this->setRequestMockClass(AccountDataFormRequest::class); - $user = $this->generateRequestUserModel(); - - $this->request->shouldReceive('input')->with('do_action')->andReturn('email'); - $this->request->shouldReceive('input')->with('new_email')->once()->andReturn('test@example.com'); - - $this->updateService->shouldReceive('setUserLevel')->with(User::USER_LEVEL_USER)->once()->andReturnNull(); - $this->updateService->shouldReceive('handle')->with($user, ['email' => 'test@example.com'])->once()->andReturn(collect()); - $this->alert->shouldReceive('success->flash')->once()->andReturnNull(); - - $response = $this->getController()->update($this->request); - $this->assertIsRedirectResponse($response); - $this->assertRedirectRouteEquals('account', $response); - } - - /** - * Test controller when identity is being updated. - */ - public function testUpdateControllerForIdentity() - { - $this->setRequestMockClass(AccountDataFormRequest::class); - $user = $this->generateRequestUserModel(); - - $this->request->shouldReceive('input')->with('do_action')->andReturn('identity'); - $this->request->shouldReceive('only')->with(['name_first', 'name_last', 'username', 'language'])->once()->andReturn([ - 'test_data' => 'value', - ]); - - $this->updateService->shouldReceive('setUserLevel')->with(User::USER_LEVEL_USER)->once()->andReturnNull(); - $this->updateService->shouldReceive('handle')->with($user, ['test_data' => 'value'])->once()->andReturn(collect()); - $this->alert->shouldReceive('success->flash')->once()->andReturnNull(); - - $response = $this->getController()->update($this->request); - $this->assertIsRedirectResponse($response); - $this->assertRedirectRouteEquals('account', $response); - } - - /** - * Return an instance of the controller for testing. - * - * @return \Pterodactyl\Http\Controllers\Base\AccountController - */ - private function getController(): AccountController - { - return new AccountController($this->alert, $this->authManager, $this->updateService); - } -} diff --git a/tests/Unit/Http/Controllers/Base/IndexControllerTest.php b/tests/Unit/Http/Controllers/Base/IndexControllerTest.php index ebcb565e..2cc4a270 100644 --- a/tests/Unit/Http/Controllers/Base/IndexControllerTest.php +++ b/tests/Unit/Http/Controllers/Base/IndexControllerTest.php @@ -76,9 +76,9 @@ class IndexControllerTest extends ControllerTestCase ->shouldReceive('filterUserAccessServers')->with($model, User::FILTER_LEVEL_ALL, config('pterodactyl.paginate.frontend.servers')) ->once()->andReturn($paginator); - $response = $this->controller->getIndex($this->request); + $response = $this->controller->index($this->request); $this->assertIsViewResponse($response); - $this->assertViewNameEquals('base.index', $response); + $this->assertViewNameEquals('templates.base.core', $response); $this->assertViewHasKey('servers', $response); $this->assertViewKeyEquals('servers', $paginator, $response); } diff --git a/tests/Unit/Http/Controllers/Base/SecurityControllerTest.php b/tests/Unit/Http/Controllers/Base/SecurityControllerTest.php index 363a5980..5423f093 100644 --- a/tests/Unit/Http/Controllers/Base/SecurityControllerTest.php +++ b/tests/Unit/Http/Controllers/Base/SecurityControllerTest.php @@ -3,6 +3,8 @@ namespace Tests\Unit\Http\Controllers\Base; use Mockery as m; +use Illuminate\Http\Response; +use Illuminate\Support\Collection; use Prologue\Alerts\AlertsMessageBag; use Illuminate\Contracts\Config\Repository; use Tests\Unit\Http\Controllers\ControllerTestCase; @@ -53,125 +55,86 @@ class SecurityControllerTest extends ControllerTestCase $this->twoFactorSetupService = m::mock(TwoFactorSetupService::class); } - /** - * Test the index controller when using a database driver. - */ - public function testIndexControllerWithDatabaseDriver() - { - $model = $this->generateRequestUserModel(); - - $this->config->shouldReceive('get')->with('session.driver')->once()->andReturn('database'); - $this->repository->shouldReceive('getUserSessions')->with($model->id)->once()->andReturn(collect(['sessions'])); - - $response = $this->getController()->index($this->request); - $this->assertIsViewResponse($response); - $this->assertViewNameEquals('base.security', $response); - $this->assertViewHasKey('sessions', $response); - $this->assertViewKeyEquals('sessions', collect(['sessions']), $response); - } - - /** - * Test the index controller when not using the database driver. - */ - public function testIndexControllerWithoutDatabaseDriver() - { - $this->config->shouldReceive('get')->with('session.driver')->once()->andReturn('redis'); - - $response = $this->getController()->index($this->request); - $this->assertIsViewResponse($response); - $this->assertViewNameEquals('base.security', $response); - $this->assertViewHasKey('sessions', $response); - $this->assertViewKeyEquals('sessions', null, $response); - } - /** * Test TOTP generation controller. */ - public function testGenerateTotpController() + public function testIndexWithout2FactorEnabled() { - $model = $this->generateRequestUserModel(); + $model = $this->generateRequestUserModel(['use_totp' => 0]); - $this->twoFactorSetupService->shouldReceive('handle')->with($model)->once()->andReturn('qrCodeImage'); + $this->twoFactorSetupService->shouldReceive('handle')->with($model)->once()->andReturn(new Collection([ + 'image' => 'test-image', + 'secret' => 'secret-code', + ])); - $response = $this->getController()->generateTotp($this->request); + $response = $this->getController()->index($this->request); $this->assertIsJsonResponse($response); - $this->assertResponseJsonEquals(['qrImage' => 'qrCodeImage'], $response); + $this->assertResponseCodeEquals(Response::HTTP_OK, $response); + $this->assertResponseJsonEquals(['enabled' => false, 'qr_image' => 'test-image', 'secret' => 'secret-code'], $response); } /** * Test TOTP setting controller when no exception is thrown by the service. */ - public function testSetTotpControllerSuccess() + public function testIndexWith2FactorEnabled() { - $model = $this->generateRequestUserModel(); + $this->generateRequestUserModel(['use_totp' => 1]); - $this->request->shouldReceive('input')->with('token')->once()->andReturn('testToken'); - $this->toggleTwoFactorService->shouldReceive('handle')->with($model, 'testToken')->once(); - - $response = $this->getController()->setTotp($this->request); - $this->assertIsResponse($response); - $this->assertSame('true', $response->getContent()); + $response = $this->getController()->index($this->request); + $this->assertIsJsonResponse($response); + $this->assertResponseCodeEquals(Response::HTTP_OK, $response); + $this->assertResponseJsonEquals(['enabled' => true], $response); } /** - * Test TOTP setting controller when an exception is thrown by the service. + * Test that a 2FA token can be stored or deleted. + * + * @param string $func + * @dataProvider functionCallDataProvider */ - public function testSetTotpControllerWhenExceptionIsThrown() + public function testStore(string $func) { $model = $this->generateRequestUserModel(); - $this->request->shouldReceive('input')->with('token')->once()->andReturn('testToken'); - $this->toggleTwoFactorService->shouldReceive('handle')->with($model, 'testToken')->once()->andThrow(new TwoFactorAuthenticationTokenInvalid()); + $this->mockRequestInput('token', 'some-token'); - $response = $this->getController()->setTotp($this->request); - $this->assertIsResponse($response); - $this->assertSame('false', $response->getContent()); + if ($func === 'delete') { + $this->toggleTwoFactorService->shouldReceive('handle')->with($model, 'some-token', false); + } else { + $this->toggleTwoFactorService->shouldReceive('handle')->with($model, 'some-token'); + } + + $response = $this->getController()->{$func}($this->request); + $this->assertIsJsonResponse($response); + $this->assertResponseCodeEquals(Response::HTTP_OK, $response); + $this->assertResponseJsonEquals(['success' => true], $response); } /** - * Test the disable totp controller when no exception is thrown by the service. + * Test an invalid token exception is handled. + * + * @param string $func + * @dataProvider functionCallDataProvider */ - public function testDisableTotpControllerSuccess() + public function testStoreWithInvalidTokenException(string $func) { - $model = $this->generateRequestUserModel(); + $this->generateRequestUserModel(); - $this->request->shouldReceive('input')->with('token')->once()->andReturn('testToken'); - $this->toggleTwoFactorService->shouldReceive('handle')->with($model, 'testToken', false)->once()->andReturn(true); + $this->mockRequestInput('token'); + $this->toggleTwoFactorService->shouldReceive('handle')->andThrow(new TwoFactorAuthenticationTokenInvalid); - $response = $this->getController()->disableTotp($this->request); - $this->assertIsRedirectResponse($response); - $this->assertRedirectRouteEquals('account.security', $response); + $response = $this->getController()->{$func}($this->request); + $this->assertIsJsonResponse($response); + $this->assertResponseCodeEquals(Response::HTTP_OK, $response); + $this->assertResponseJsonEquals(['success' => false], $response); } /** - * Test the disable totp controller when an exception is thrown by the service. + * @return array */ - public function testDisableTotpControllerWhenExceptionIsThrown() + public function functionCallDataProvider() { - $model = $this->generateRequestUserModel(); - - $this->request->shouldReceive('input')->with('token')->once()->andReturn('testToken'); - $this->toggleTwoFactorService->shouldReceive('handle')->with($model, 'testToken', false)->once()->andThrow(new TwoFactorAuthenticationTokenInvalid); - $this->alert->shouldReceive('danger')->with(trans('base.security.2fa_disable_error'))->once()->andReturnSelf(); - $this->alert->shouldReceive('flash')->withNoArgs()->once()->andReturnNull(); - - $response = $this->getController()->disableTotp($this->request); - $this->assertIsRedirectResponse($response); - $this->assertRedirectRouteEquals('account.security', $response); - } - - /** - * Test the revoke controller. - */ - public function testRevokeController() - { - $model = $this->generateRequestUserModel(); - - $this->repository->shouldReceive('deleteUserSession')->with($model->id, 123)->once()->andReturnNull(); - - $response = $this->getController()->revoke($this->request, 123); - $this->assertIsRedirectResponse($response); - $this->assertRedirectRouteEquals('account.security', $response); + return [['store'], ['delete']]; } /** diff --git a/tests/Unit/Http/Controllers/ControllerTestCase.php b/tests/Unit/Http/Controllers/ControllerTestCase.php index 6caf9abd..3a6ea5cb 100644 --- a/tests/Unit/Http/Controllers/ControllerTestCase.php +++ b/tests/Unit/Http/Controllers/ControllerTestCase.php @@ -66,6 +66,19 @@ abstract class ControllerTestCase extends TestCase } } + /** + * Mocks a request input call. + * + * @param string $param + * @param mixed $return + */ + protected function mockRequestInput(string $param, $return = null) + { + $this->request->shouldReceive('input')->withArgs(function ($k) use ($param) { + return $k === $param; + })->andReturn($return); + } + /** * Build and return a mocked controller instance to use for testing. * diff --git a/tests/Unit/Http/Middleware/API/AuthenticateKeyTest.php b/tests/Unit/Http/Middleware/API/AuthenticateKeyTest.php index 075124e2..0d68b264 100644 --- a/tests/Unit/Http/Middleware/API/AuthenticateKeyTest.php +++ b/tests/Unit/Http/Middleware/API/AuthenticateKeyTest.php @@ -4,6 +4,7 @@ namespace Tests\Unit\Http\Middleware\API; use Mockery as m; use Cake\Chronos\Chronos; +use Pterodactyl\Models\User; use Pterodactyl\Models\ApiKey; use Illuminate\Auth\AuthManager; use Illuminate\Contracts\Encryption\Encrypter; @@ -48,6 +49,7 @@ class AuthenticateKeyTest extends MiddlewareTestCase */ public function testMissingBearerTokenThrowsException() { + $this->request->shouldReceive('user')->andReturnNull(); $this->request->shouldReceive('bearerToken')->withNoArgs()->once()->andReturnNull(); try { @@ -117,6 +119,25 @@ class AuthenticateKeyTest extends MiddlewareTestCase $this->assertEquals($model, $this->request->attributes->get('api_key')); } + /** + * Test that we can still make it though this middleware if the user is logged in and passing + * through a cookie. + */ + public function testAccessWithoutToken() + { + $user = factory(User::class)->make(['id' => 123]); + + $this->request->shouldReceive('user')->andReturn($user); + $this->request->shouldReceive('bearerToken')->withNoArgs()->twice()->andReturnNull(); + + $this->getMiddleware()->handle($this->request, $this->getClosureAssertions(), ApiKey::TYPE_ACCOUNT); + $model = $this->request->attributes->get('api_key'); + + $this->assertSame(ApiKey::TYPE_ACCOUNT, $model->key_type); + $this->assertSame(123, $model->user_id); + $this->assertNull($model->identifier); + } + /** * Test that a valid token identifier with an invalid token attached to it * triggers an exception. diff --git a/tests/Unit/Http/Middleware/API/SetSessionDriverTest.php b/tests/Unit/Http/Middleware/API/SetSessionDriverTest.php index 36f1bc0b..c65f8a6b 100644 --- a/tests/Unit/Http/Middleware/API/SetSessionDriverTest.php +++ b/tests/Unit/Http/Middleware/API/SetSessionDriverTest.php @@ -3,19 +3,12 @@ namespace Tests\Unit\Http\Middleware\API; use Mockery as m; -use Barryvdh\Debugbar\LaravelDebugbar; use Illuminate\Contracts\Config\Repository; -use Illuminate\Contracts\Foundation\Application; use Tests\Unit\Http\Middleware\MiddlewareTestCase; use Pterodactyl\Http\Middleware\Api\SetSessionDriver; class SetSessionDriverTest extends MiddlewareTestCase { - /** - * @var \Illuminate\Contracts\Foundation\Application|\Mockery\Mock - */ - private $appMock; - /** * @var \Illuminate\Contracts\Config\Repository|\Mockery\Mock */ @@ -28,29 +21,14 @@ class SetSessionDriverTest extends MiddlewareTestCase { parent::setUp(); - $this->appMock = m::mock(Application::class); $this->config = m::mock(Repository::class); } /** * Test that a production environment does not try to disable debug bar. */ - public function testProductionEnvironment() + public function testMiddleware() { - $this->config->shouldReceive('get')->once()->with('app.debug')->andReturn(false); - $this->config->shouldReceive('set')->once()->with('session.driver', 'array')->andReturnNull(); - - $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); - } - - /** - * Test that a local environment does disable debug bar. - */ - public function testLocalEnvironment() - { - $this->config->shouldReceive('get')->once()->with('app.debug')->andReturn(true); - $this->appMock->shouldReceive('make')->once()->with(LaravelDebugbar::class)->andReturnSelf(); - $this->appMock->shouldReceive('disable')->once()->withNoArgs()->andReturnNull(); $this->config->shouldReceive('set')->once()->with('session.driver', 'array')->andReturnNull(); $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); @@ -63,6 +41,6 @@ class SetSessionDriverTest extends MiddlewareTestCase */ private function getMiddleware(): SetSessionDriver { - return new SetSessionDriver($this->appMock, $this->config); + return new SetSessionDriver($this->config); } } diff --git a/tests/Unit/Http/Middleware/RequireTwoFactorAuthenticationTest.php b/tests/Unit/Http/Middleware/RequireTwoFactorAuthenticationTest.php index 19bd4512..562ff75c 100644 --- a/tests/Unit/Http/Middleware/RequireTwoFactorAuthenticationTest.php +++ b/tests/Unit/Http/Middleware/RequireTwoFactorAuthenticationTest.php @@ -88,7 +88,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase $response = $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); $this->assertInstanceOf(RedirectResponse::class, $response); - $this->assertEquals(route('account.security'), $response->getTargetUrl()); + $this->assertEquals(route('account'), $response->getTargetUrl()); } /** @@ -132,7 +132,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase $response = $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); $this->assertInstanceOf(RedirectResponse::class, $response); - $this->assertEquals(route('account.security'), $response->getTargetUrl()); + $this->assertEquals(route('account'), $response->getTargetUrl()); } /** @@ -156,7 +156,8 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase public function ignoredRoutesDataProvider() { return [ - ['account.security'], + ['auth'], + ['account'], ['account.security.revoke'], ['account.security.totp'], ['account.security.totp.set'], diff --git a/tests/Unit/Http/Middleware/Server/AccessingValidServerTest.php b/tests/Unit/Http/Middleware/Server/AccessingValidServerTest.php index bbc410f7..67f61d68 100644 --- a/tests/Unit/Http/Middleware/Server/AccessingValidServerTest.php +++ b/tests/Unit/Http/Middleware/Server/AccessingValidServerTest.php @@ -4,7 +4,6 @@ namespace Tests\Unit\Http\Middleware\Server; use Mockery as m; use Pterodactyl\Models\Server; -use Illuminate\Contracts\Session\Session; use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Routing\ResponseFactory; use Tests\Unit\Http\Middleware\MiddlewareTestCase; @@ -28,11 +27,6 @@ class AccessingValidServerTest extends MiddlewareTestCase */ private $response; - /** - * @var \Illuminate\Contracts\Session\Session|\Mockery\Mock - */ - private $session; - /** * Setup tests. */ @@ -43,7 +37,6 @@ class AccessingValidServerTest extends MiddlewareTestCase $this->config = m::mock(Repository::class); $this->repository = m::mock(ServerRepositoryInterface::class); $this->response = m::mock(ResponseFactory::class); - $this->session = m::mock(Session::class); } /** @@ -114,7 +107,6 @@ class AccessingValidServerTest extends MiddlewareTestCase $this->request->shouldReceive('is')->with(...[])->once()->andReturn(false); $this->repository->shouldReceive('getByUuid')->with('123456')->once()->andReturn($model); - $this->session->shouldReceive('now')->with('server_data.model', $model)->once()->andReturnNull(); $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); $this->assertRequestHasAttribute('server'); @@ -141,10 +133,10 @@ class AccessingValidServerTest extends MiddlewareTestCase /** * Return an instance of the middleware using mocked dependencies. * - * @return \Pterodactyl\Http\Middleware\AccessingValidServer + * @return \Pterodactyl\Http\Middleware\Server\AccessingValidServer */ private function getMiddleware(): AccessingValidServer { - return new AccessingValidServer($this->config, $this->response, $this->repository, $this->session); + return new AccessingValidServer($this->config, $this->response, $this->repository); } } diff --git a/tests/Unit/Services/Users/TwoFactorSetupServiceTest.php b/tests/Unit/Services/Users/TwoFactorSetupServiceTest.php index 09d37b0d..cac7f994 100644 --- a/tests/Unit/Services/Users/TwoFactorSetupServiceTest.php +++ b/tests/Unit/Services/Users/TwoFactorSetupServiceTest.php @@ -5,6 +5,7 @@ namespace Tests\Unit\Services\Users; use Mockery as m; use Tests\TestCase; use Pterodactyl\Models\User; +use Illuminate\Support\Collection; use PragmaRX\Google2FAQRCode\Google2FA; use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Encryption\Encrypter; @@ -53,7 +54,9 @@ class TwoFactorSetupServiceTest extends TestCase { $model = factory(User::class)->make(); - $this->config->shouldReceive('get')->with('pterodactyl.auth.2fa.bytes')->once()->andReturn(32); + config()->set('pterodactyl.auth.2fa.bytes', 32); + config()->set('app.name', 'CompanyName'); + $this->google2FA->shouldReceive('generateSecretKey')->with(32)->once()->andReturn('secretKey'); $this->config->shouldReceive('get')->with('app.name')->once()->andReturn('CompanyName'); $this->google2FA->shouldReceive('getQRCodeInline')->with('CompanyName', $model->email, 'secretKey')->once()->andReturn('http://url.com'); @@ -62,7 +65,9 @@ class TwoFactorSetupServiceTest extends TestCase $response = $this->getService()->handle($model); $this->assertNotEmpty($response); - $this->assertSame('http://url.com', $response); + $this->assertInstanceOf(Collection::class, $response); + $this->assertSame('http://url.com', $response->get('image')); + $this->assertSame('secretKey', $response->get('secret')); } /** @@ -72,6 +77,6 @@ class TwoFactorSetupServiceTest extends TestCase */ private function getService(): TwoFactorSetupService { - return new TwoFactorSetupService($this->config, $this->encrypter, $this->google2FA, $this->repository); + return new TwoFactorSetupService($this->encrypter, $this->google2FA, $this->repository); } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..b15575b7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es6", + "strict": true, + "noImplicitReturns": true, + "moduleResolution": "node", + "lib": [ + "es2016", + "dom" + ], + "baseUrl": ".", + "paths": { + "@/*": [ + "./resources/assets/scripts/*" + ] + } + }, + "include": [ + "./resources/assets/scripts/**/*" + ] +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..c7a8ef03 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,215 @@ +const _ = require('lodash'); +const path = require('path'); +const tailwind = require('tailwindcss'); +const glob = require('glob-all'); + +const AssetsManifestPlugin = require('webpack-assets-manifest'); +const CleanPlugin = require('clean-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const ShellPlugin = require('webpack-shell-plugin'); +const PurgeCssPlugin = require('purgecss-webpack-plugin'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const VueLoaderPlugin = require('vue-loader/lib/plugin'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); + +const isProduction = process.env.NODE_ENV === 'production'; + +let plugins = [ + new CleanPlugin(path.resolve(__dirname, 'public/assets')), + new ShellPlugin({ + onBuildStart: [ + 'php artisan vue-i18n:generate', + 'php artisan ziggy:generate resources/assets/scripts/helpers/ziggy.js', + ], + }), + new MiniCssExtractPlugin({ filename: isProduction ? 'bundle.[chunkhash:8].css' : 'bundle.[hash:8].css' }), + new AssetsManifestPlugin({ + writeToDisk: true, + publicPath: true, + integrity: true, + integrityHashes: ['sha384'], + }), + new VueLoaderPlugin(), + new ForkTsCheckerWebpackPlugin({ + vue: true, + }), +]; + +if (isProduction) { + plugins = plugins.concat([ + new PurgeCssPlugin({ + paths: glob.sync([ + path.join(__dirname, 'resources/assets/scripts/**/*.vue'), + path.join(__dirname, 'resources/assets/scripts/**/*.ts'), + path.join(__dirname, 'resources/themes/pterodactyl/**/*.blade.php'), + ]), + // Don't let PurgeCSS remove classes ending with -enter or -leave-active + // They're used by Vue transitions and are therefore not specifically defined + // in any of the files are are checked by PurgeCSS. + whitelistPatterns: [/^xterm/, /-enter$/, /-leave-active$/], + extractors: [ + { + extractor: class { + static extract (content) { + return content.match(/[A-z0-9-:\/]+/g) || []; + } + }, + extensions: ['html', 'ts', 'js', 'php', 'vue'], + }, + ], + }), + ]); +} + +const typescriptLoaders = [ + { + loader: 'babel-loader', + options: { + cacheDirectory: !isProduction, + presets: ['@babel/preset-env'], + plugins: [ + '@babel/plugin-proposal-class-properties', + ['@babel/plugin-proposal-object-rest-spread', { 'useBuiltIns': true }] + ], + }, + }, + { + loader: 'ts-loader', + options: { + appendTsSuffixTo: [/\.vue$/], + experimentalWatchApi: true, + transpileOnly: true, + } + } +]; + +const cssLoaders = [ + { loader: MiniCssExtractPlugin.loader }, + { + loader: 'css-loader', + options: { + sourceMap: !isProduction, + importLoaders: 1, + } + }, + { loader: 'resolve-url-loader' }, + { + loader: 'postcss-loader', + options: { + ident: 'postcss', + sourceMap: true, + plugins: [ + require('postcss-import'), + tailwind('./tailwind.js'), + require('postcss-preset-env')({ + stage: 2, + }), + require('precss'), + ].concat(isProduction ? require('cssnano') : []), + } + } +]; + +module.exports = { + target: 'web', + mode: process.env.NODE_ENV, + devtool: isProduction ? false : 'eval-source-map', + performance: { + hints: false, + }, + entry: ['./resources/assets/styles/main.css', './resources/assets/scripts/app.ts'], + output: { + path: path.resolve(__dirname, 'public/assets'), + filename: isProduction ? 'bundle.[chunkhash:8].js' : 'bundle.[hash:8].js', + chunkFilename: isProduction ? '[name].[chunkhash:8].js' : '[name].[hash:8].js', + publicPath: _.get(process.env, 'PUBLIC_PATH', '') + '/assets/', + crossOriginLoading: 'anonymous', + }, + module: { + rules: [ + { + test: /\.js$/, + loader: 'babel-loader', + exclude: file => (/node_modules/.test(file) && !/\.vue\.js/.test(file)), + options: { + cacheDirectory: !isProduction, + presets: ['@babel/preset-env'], + plugins: [ + '@babel/plugin-proposal-class-properties', + ['@babel/plugin-proposal-object-rest-spread', { 'useBuiltIns': true }] + ], + }, + }, + { + test: /\.vue$/, + use: 'vue-loader', + }, + { + test: /\.ts$/, + exclude: /node_modules/, + use: typescriptLoaders, + }, + { + test: /\.css$/, + include: [ + path.resolve(__dirname, 'resources'), + ], + use: cssLoaders, + }, + { + test: /\.(png|jpg|gif|svg)$/, + loader: 'file-loader', + options: { + name: '[name].[ext]?[hash:8]', + }, + }, + ], + }, + resolve: { + extensions: ['.ts', '.js', '.vue', '.json'], + alias: { + 'vue$': 'vue/dist/vue.esm.js', + '@': path.join(__dirname, 'resources/assets/scripts'), + }, + symlinks: false, + }, + plugins: plugins, + optimization: { + minimize: true, + minimizer: !isProduction ? [] : [ + new UglifyJsPlugin({ + cache: true, + parallel: true, + uglifyOptions: { + output: { + comments: false, + }, + }, + }), + ], + splitChunks: { + cacheGroups: { + locales: { + test: /locales/, + name: 'locales', + chunks: 'initial', + }, + vendors: { + test: /[\\/]node_modules[\\/]/, + name: 'vendor', + chunks: 'initial', + }, + } + } + }, + devServer: { + contentBase: path.join(__dirname, 'public'), + publicPath: _.get(process.env, 'PUBLIC_PATH', '') + '/assets/', + allowedHosts: [ + '.pterodactyl.test', + ], + headers: { + 'Access-Control-Allow-Origin': '*', + }, + }, +}; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..f4d342c6 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,7616 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/cli@^7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.2.3.tgz#1b262e42a3e959d28ab3d205ba2718e1923cfee6" + dependencies: + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.1.0" + glob "^7.0.0" + lodash "^4.17.10" + mkdirp "^0.5.1" + output-file-sync "^2.0.0" + slash "^2.0.0" + source-map "^0.5.0" + optionalDependencies: + chokidar "^2.0.3" + +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + dependencies: + "@babel/highlight" "7.0.0-beta.44" + +"@babel/code-frame@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/core@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.2.2" + "@babel/helpers" "^7.2.0" + "@babel/parser" "^7.2.2" + "@babel/template" "^7.2.2" + "@babel/traverse" "^7.2.2" + "@babel/types" "^7.2.2" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.10" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + dependencies: + "@babel/types" "7.0.0-beta.44" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/generator@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc" + dependencies: + "@babel/types" "^7.2.2" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-annotate-as-pure@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" + dependencies: + "@babel/helper-explode-assignable-expression" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-call-delegate@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz#6a957f105f37755e8645343d3038a22e1449cc4a" + dependencies: + "@babel/helper-hoist-variables" "^7.0.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-create-class-features-plugin@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.0.tgz#2b01a81b3adc2b1287f9ee193688ef8dc71e718f" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.2.3" + +"@babel/helper-define-map@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/types" "^7.0.0" + lodash "^4.17.10" + +"@babel/helper-explode-assignable-expression@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" + dependencies: + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-hoist-variables@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz#46adc4c5e758645ae7a45deb92bab0918c23bb88" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-member-expression-to-functions@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-imports@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-transforms@^7.1.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz#ab2f8e8d231409f8370c883d20c335190284b963" + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/template" "^7.2.2" + "@babel/types" "^7.2.2" + lodash "^4.17.10" + +"@babel/helper-optimise-call-expression@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + +"@babel/helper-regex@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27" + dependencies: + lodash "^4.17.10" + +"@babel/helper-remap-async-to-generator@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-wrap-function" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-replace-supers@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz#5fc31de522ec0ef0899dc9b3e7cf6a5dd655f362" + dependencies: + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-replace-supers@^7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz#19970020cf22677d62b3a689561dbd9644d8c5e5" + dependencies: + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.2.3" + "@babel/types" "^7.0.0" + +"@babel/helper-simple-access@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" + dependencies: + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-split-export-declaration@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-wrap-function@^7.1.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.2.0" + +"@babel/helpers@^7.2.0": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.3.1.tgz#949eec9ea4b45d3210feb7dc1c22db664c9e44b9" + dependencies: + "@babel/template" "^7.1.2" + "@babel/traverse" "^7.1.5" + "@babel/types" "^7.3.0" + +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/highlight@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.0.tgz#a7cd42cb3c12aec52e24375189a47b39759b783e" + +"@babel/parser@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.2.tgz#37ebdbc88a2e1ebc6c8dd3d35ea9436e3e39e477" + +"@babel/parser@^7.2.3": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.1.tgz#8f4ffd45f779e6132780835ffa7a215fa0b2d181" + +"@babel/plugin-proposal-async-generator-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + +"@babel/plugin-proposal-class-properties@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz#272636bc0fa19a0bc46e601ec78136a173ea36cd" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.3.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-proposal-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + +"@babel/plugin-proposal-object-rest-spread@^7.3.1": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.1.tgz#f69fb6a1ea6a4e1c503994a91d9cf76f3c4b36e8" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz#abe7281fe46c95ddc143a65e5358647792039520" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.2.0" + +"@babel/plugin-syntax-async-generators@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-object-rest-spread@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-arrow-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-async-to-generator@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz#68b8a438663e88519e65b776f8938f3445b1a2ff" + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + +"@babel/plugin-transform-block-scoped-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-block-scoping@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz#f17c49d91eedbcdf5dd50597d16f5f2f770132d4" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.10" + +"@babel/plugin-transform-classes@^7.2.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.2.tgz#6c90542f210ee975aa2aa8c8b5af7fa73a126953" + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-define-map" "^7.1.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-destructuring@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.2.0.tgz#e75269b4b7889ec3a332cd0d0c8cff8fed0dc6f3" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-dotall-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz#f0aabb93d120a8ac61e925ea0ba440812dbe0e49" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.1.3" + +"@babel/plugin-transform-duplicate-keys@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz#d952c4930f312a4dbfff18f0b2914e60c35530b3" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-exponentiation-operator@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-for-of@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz#ab7468befa80f764bb03d3cb5eef8cc998e1cad9" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-function-name@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz#f7930362829ff99a3174c39f0afcc024ef59731a" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-amd@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz#82a9bce45b95441f617a24011dc89d12da7f4ee6" + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-commonjs@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz#c4f1933f5991d5145e9cfad1dfd848ea1727f404" + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + +"@babel/plugin-transform-modules-systemjs@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.2.0.tgz#912bfe9e5ff982924c81d0937c92d24994bb9068" + dependencies: + "@babel/helper-hoist-variables" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-umd@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz#140b52985b2d6ef0cb092ef3b29502b990f9cd50" + dependencies: + regexp-tree "^0.1.0" + +"@babel/plugin-transform-new-target@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-object-super@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + +"@babel/plugin-transform-parameters@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.2.0.tgz#0d5ad15dc805e2ea866df4dd6682bfe76d1408c2" + dependencies: + "@babel/helper-call-delegate" "^7.1.0" + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-regenerator@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz#5b41686b4ed40bef874d7ed6a84bdd849c13e0c1" + dependencies: + regenerator-transform "^0.13.3" + +"@babel/plugin-transform-shorthand-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-spread@^7.2.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-sticky-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + +"@babel/plugin-transform-template-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz#d87ed01b8eaac7a92473f608c97c089de2ba1e5b" + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typeof-symbol@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-unicode-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz#4eb8db16f972f8abb5062c161b8b115546ade08b" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.1.3" + +"@babel/preset-env@^7.3.1": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.1.tgz#389e8ca6b17ae67aaf9a2111665030be923515db" + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.2.0" + "@babel/plugin-proposal-json-strings" "^7.2.0" + "@babel/plugin-proposal-object-rest-spread" "^7.3.1" + "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.2.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.2.0" + "@babel/plugin-transform-block-scoped-functions" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.2.0" + "@babel/plugin-transform-classes" "^7.2.0" + "@babel/plugin-transform-computed-properties" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.2.0" + "@babel/plugin-transform-dotall-regex" "^7.2.0" + "@babel/plugin-transform-duplicate-keys" "^7.2.0" + "@babel/plugin-transform-exponentiation-operator" "^7.2.0" + "@babel/plugin-transform-for-of" "^7.2.0" + "@babel/plugin-transform-function-name" "^7.2.0" + "@babel/plugin-transform-literals" "^7.2.0" + "@babel/plugin-transform-modules-amd" "^7.2.0" + "@babel/plugin-transform-modules-commonjs" "^7.2.0" + "@babel/plugin-transform-modules-systemjs" "^7.2.0" + "@babel/plugin-transform-modules-umd" "^7.2.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0" + "@babel/plugin-transform-new-target" "^7.0.0" + "@babel/plugin-transform-object-super" "^7.2.0" + "@babel/plugin-transform-parameters" "^7.2.0" + "@babel/plugin-transform-regenerator" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.2.0" + "@babel/plugin-transform-spread" "^7.2.0" + "@babel/plugin-transform-sticky-regex" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.2.0" + "@babel/plugin-transform-typeof-symbol" "^7.2.0" + "@babel/plugin-transform-unicode-regex" "^7.2.0" + browserslist "^4.3.4" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.3.0" + +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/template@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.0.tgz#58cc9572e1bfe24fe1537fdf99d839d53e517e22" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/template@^7.1.2", "@babel/template@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.2.2" + "@babel/types" "^7.2.2" + +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/traverse@^7.1.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.2.tgz#961039de1f9bcb946d807efe2dba9c92e859d188" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.2.2" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.2.2" + "@babel/types" "^7.2.2" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.10" + +"@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.2.2" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.2.3" + "@babel/types" "^7.2.2" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.10" + +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + +"@babel/types@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0.tgz#6e191793d3c854d19c6749989e3bc55f0e962118" + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + +"@babel/types@^7.2.0", "@babel/types@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.0.tgz#61dc0b336a93badc02bf5f69c4cd8e1353f2ffc0" + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + +"@babel/types@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e" + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + +"@csstools/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + +"@csstools/postcss-image-set-function@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-image-set-function/-/postcss-image-set-function-1.0.0.tgz#1ef0913d90a9c4440495eb41624c202e53a703f3" + dependencies: + postcss "^6.0.20" + postcss-value-parser "^3.3.0" + +"@csstools/sass-import-resolve@^1": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/sass-import-resolve/-/sass-import-resolve-1.0.0.tgz#32c3cdb2f7af3cd8f0dca357b592e7271f3831b5" + +"@types/feather-icons@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@types/feather-icons/-/feather-icons-4.7.0.tgz#ec66bc046bcd1513835f87541ecef54b50c57ec9" + +"@types/lodash@^4.14.119": + version "4.14.119" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.119.tgz#be847e5f4bc3e35e46d041c394ead8b603ad8b39" + +"@types/node@^10.12.15": + version "10.12.15" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.15.tgz#20e85651b62fd86656e57c9c9bc771ab1570bc59" + +"@types/socket.io-client@^1.4.32": + version "1.4.32" + resolved "https://registry.yarnpkg.com/@types/socket.io-client/-/socket.io-client-1.4.32.tgz#988a65a0386c274b1c22a55377fab6a30789ac14" + +"@types/webpack-env@^1.13.6": + version "1.13.6" + resolved "http://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.13.6.tgz#128d1685a7c34d31ed17010fc87d6a12c1de6976" + +"@vue/component-compiler-utils@^2.5.1": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-2.5.2.tgz#a8d57e773354ab10e4742c7d6a8dd86184d4d7be" + dependencies: + consolidate "^0.15.1" + hash-sum "^1.0.2" + lru-cache "^4.1.2" + merge-source-map "^1.1.0" + postcss "^7.0.14" + postcss-selector-parser "^5.0.0" + prettier "1.16.3" + source-map "~0.6.1" + vue-template-es2015-compiler "^1.8.2" + +"@webassemblyjs/ast@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.9.tgz#b2770182678691ab4949d593105c15d4074fedb6" + dependencies: + "@webassemblyjs/helper-module-context" "1.5.9" + "@webassemblyjs/helper-wasm-bytecode" "1.5.9" + "@webassemblyjs/wast-parser" "1.5.9" + debug "^3.1.0" + mamacro "^0.0.3" + +"@webassemblyjs/ast@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace" + dependencies: + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" + +"@webassemblyjs/floating-point-hex-parser@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.9.tgz#ee56243f6ba30781ff6f92fe7f1c377255219a7c" + +"@webassemblyjs/floating-point-hex-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313" + +"@webassemblyjs/helper-api-error@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.9.tgz#c80e204afe1ae102c23b0357f1ec25aeb61022a2" + +"@webassemblyjs/helper-api-error@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a" + +"@webassemblyjs/helper-buffer@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.9.tgz#90d99afcb0fdc1ee11bc403894f3ae37cd926a81" + dependencies: + debug "^3.1.0" + +"@webassemblyjs/helper-buffer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b" + +"@webassemblyjs/helper-code-frame@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.9.tgz#b56ac06a39c3e1cfefcc421ade1ee471a738a570" + dependencies: + "@webassemblyjs/wast-printer" "1.5.9" + +"@webassemblyjs/helper-code-frame@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b" + dependencies: + "@webassemblyjs/wast-printer" "1.7.11" + +"@webassemblyjs/helper-fsm@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.9.tgz#8f996268eb07ee6728130a9e97fa3aac32772454" + +"@webassemblyjs/helper-fsm@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181" + +"@webassemblyjs/helper-module-context@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.9.tgz#69e2eea310f755a0b750b84f8af59f890f2046ac" + +"@webassemblyjs/helper-module-context@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209" + +"@webassemblyjs/helper-wasm-bytecode@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.9.tgz#467ba0f9e4d0e4a48bf1c5107b9f4abe3ca1171a" + +"@webassemblyjs/helper-wasm-bytecode@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06" + +"@webassemblyjs/helper-wasm-section@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.9.tgz#aec9486ab5d56e3cb5252a7ed88777b6792ac624" + dependencies: + "@webassemblyjs/ast" "1.5.9" + "@webassemblyjs/helper-buffer" "1.5.9" + "@webassemblyjs/helper-wasm-bytecode" "1.5.9" + "@webassemblyjs/wasm-gen" "1.5.9" + debug "^3.1.0" + +"@webassemblyjs/helper-wasm-section@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a" + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + +"@webassemblyjs/ieee754@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.5.9.tgz#846856ece040c7debd5b5645b319c26523613bcf" + dependencies: + ieee754 "^1.1.11" + +"@webassemblyjs/ieee754@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b" + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.5.9.tgz#7249443a0fd7574a7e3c1c39532535c735390bbc" + dependencies: + leb "^0.3.0" + +"@webassemblyjs/leb128@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63" + dependencies: + "@xtuc/long" "4.2.1" + +"@webassemblyjs/utf8@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82" + +"@webassemblyjs/wasm-edit@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.9.tgz#9b8e054b2d305a7e0528088571c95904bd73df48" + dependencies: + "@webassemblyjs/ast" "1.5.9" + "@webassemblyjs/helper-buffer" "1.5.9" + "@webassemblyjs/helper-wasm-bytecode" "1.5.9" + "@webassemblyjs/helper-wasm-section" "1.5.9" + "@webassemblyjs/wasm-gen" "1.5.9" + "@webassemblyjs/wasm-opt" "1.5.9" + "@webassemblyjs/wasm-parser" "1.5.9" + "@webassemblyjs/wast-printer" "1.5.9" + debug "^3.1.0" + +"@webassemblyjs/wasm-edit@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005" + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/helper-wasm-section" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-opt" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + "@webassemblyjs/wast-printer" "1.7.11" + +"@webassemblyjs/wasm-gen@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.9.tgz#85e07c047fab917e06b18dee4d16342a2fd3c59c" + dependencies: + "@webassemblyjs/ast" "1.5.9" + "@webassemblyjs/helper-wasm-bytecode" "1.5.9" + "@webassemblyjs/ieee754" "1.5.9" + "@webassemblyjs/leb128" "1.5.9" + +"@webassemblyjs/wasm-gen@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8" + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" + +"@webassemblyjs/wasm-opt@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.9.tgz#ccac17c41a044c167bc95d3e8645cf889a137ce5" + dependencies: + "@webassemblyjs/ast" "1.5.9" + "@webassemblyjs/helper-buffer" "1.5.9" + "@webassemblyjs/wasm-gen" "1.5.9" + "@webassemblyjs/wasm-parser" "1.5.9" + debug "^3.1.0" + +"@webassemblyjs/wasm-opt@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7" + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + +"@webassemblyjs/wasm-parser@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.9.tgz#ddab84da4957b64aafbc61e4ab706cc667082f32" + dependencies: + "@webassemblyjs/ast" "1.5.9" + "@webassemblyjs/helper-api-error" "1.5.9" + "@webassemblyjs/helper-wasm-bytecode" "1.5.9" + "@webassemblyjs/ieee754" "1.5.9" + "@webassemblyjs/leb128" "1.5.9" + "@webassemblyjs/wasm-parser" "1.5.9" + +"@webassemblyjs/wasm-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a" + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" + +"@webassemblyjs/wast-parser@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.5.9.tgz#193d24ccf4742a5f8f1915936680ab2314011df2" + dependencies: + "@webassemblyjs/ast" "1.5.9" + "@webassemblyjs/floating-point-hex-parser" "1.5.9" + "@webassemblyjs/helper-api-error" "1.5.9" + "@webassemblyjs/helper-code-frame" "1.5.9" + "@webassemblyjs/helper-fsm" "1.5.9" + long "^3.2.0" + mamacro "^0.0.3" + +"@webassemblyjs/wast-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c" + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/floating-point-hex-parser" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-code-frame" "1.7.11" + "@webassemblyjs/helper-fsm" "1.7.11" + "@xtuc/long" "4.2.1" + +"@webassemblyjs/wast-printer@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.5.9.tgz#16605d90a481c01a130b7c4edeb2bce503787eb4" + dependencies: + "@webassemblyjs/ast" "1.5.9" + "@webassemblyjs/wast-parser" "1.5.9" + long "^3.2.0" + +"@webassemblyjs/wast-printer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813" + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" + "@xtuc/long" "4.2.1" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + +"@xtuc/long@4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +accepts@~1.3.4, accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" + dependencies: + acorn "^4.0.3" + +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + dependencies: + acorn "^5.0.0" + +acorn-dynamic-import@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" + +acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + +acorn@^5.0.0: + version "5.6.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.6.1.tgz#c9e50c3e3717cf897f1b071ceadbb543bbc0a8d4" + +acorn@^6.0.5: + version "6.0.6" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.6.tgz#cd75181670d5b99bdb1b1c993941d3a239ab1f56" + +adjust-sourcemap-loader@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-1.2.0.tgz#e33fde95e50db9f2a802e3647e311d2fc5000c69" + dependencies: + assert "^1.3.0" + camelcase "^1.2.1" + loader-utils "^1.1.0" + lodash.assign "^4.0.1" + lodash.defaults "^3.1.2" + object-path "^0.9.2" + regex-parser "^2.2.9" + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + +ajv-keywords@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" + +ajv@^6.1.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.0.tgz#4c8affdf80887d8f132c9c52ab8a2dc4d0b7b24c" + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + uri-js "^4.2.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +ansi-colors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" + dependencies: + ansi-wrap "^0.1.0" + +ansi-colors@^3.0.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + dependencies: + ansi-wrap "0.1.0" + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +ansi-wrap@0.1.0, ansi-wrap@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +arity-n@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +assert@^1.1.1, assert@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.0, async-each@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + +async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.1.2: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + dependencies: + lodash "^4.17.10" + +atob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + +autoprefixer@^9.4.5: + version "9.4.7" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.7.tgz#f997994f9a810eae47b38fa6d8a119772051c4ff" + dependencies: + browserslist "^4.4.1" + caniuse-lite "^1.0.30000932" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.14" + postcss-value-parser "^3.3.1" + +axios@^0.16: + version "0.16.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d" + dependencies: + follow-redirects "^1.2.3" + is-buffer "^1.1.5" + +axios@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" + dependencies: + follow-redirects "^1.3.0" + is-buffer "^1.1.5" + +babel-code-frame@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-eslint@^8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + eslint-scope "~3.7.1" + eslint-visitor-keys "^1.0.0" + +babel-extract-comments@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz#0a2aedf81417ed391b85e18b4614e693a0351a21" + dependencies: + babylon "^6.18.0" + +babel-helper-vue-jsx-merge-props@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6" + +babel-loader@^8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.5.tgz#225322d7509c2157655840bba52e46b6c2f2fe33" + dependencies: + find-cache-dir "^2.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + util.promisify "^1.0.0" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-transform-object-rest-spread@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-runtime@^6.23.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + +balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + 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" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + +bluebird@^3.1.1, bluebird@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + +bluebird@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +body-parser@1.18.3: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + 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" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.1.tgz#3343124db6d7ad53e26a8826318712bdc8450f9c" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + dependencies: + pako "~1.0.5" + +browserslist@^3.2.4: + version "3.2.8" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + +browserslist@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.0.1.tgz#61c05ce2a5843c7d96166408bc23d58b5416e818" + dependencies: + caniuse-lite "^1.0.30000865" + electron-to-chromium "^1.3.52" + node-releases "^1.0.0-alpha.10" + +browserslist@^4.3.4, browserslist@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062" + dependencies: + caniuse-lite "^1.0.30000929" + electron-to-chromium "^1.3.103" + node-releases "^1.1.3" + +buffer-from@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + +bytes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cacache@^11.0.2, cacache@^11.2.0: + version "11.3.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" + dependencies: + bluebird "^3.5.3" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.3" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + 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" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase-css@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + +camelcase@^1.0.2, camelcase@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +camelcase@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000865: + version "1.0.30000865" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" + +caniuse-lite@^1.0.30000823, caniuse-lite@^1.0.30000844: + version "1.0.30000847" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000847.tgz#be77f439be29bbc57ae08004b1e470b653b1ec1d" + +caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000932: + version "1.0.30000933" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000933.tgz#5871ff54b3177675ae1c2a275b2aae7abf2b9222" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + 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" + +chalk@^2.0, chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029" + +chokidar@^2.0.0, chokidar@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chokidar@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.0" + optionalDependencies: + fsevents "^1.1.2" + +chokidar@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.0.tgz#5fcb70d0b28ebe0867eb0f09d5f6a08f29a1efa0" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + 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.0" + optionalDependencies: + fsevents "^1.2.7" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + +chrome-trace-event@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-0.1.3.tgz#d395af2d31c87b90a716c831fe326f69768ec084" + +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + dependencies: + tslib "^1.9.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +classnames@^2.2.5: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + +clean-css@4.1.x: + version "4.1.11" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.11.tgz#2ecdf145aba38f54740f26cefd0ff3e03e125d6a" + dependencies: + source-map "0.5.x" + +clean-webpack-plugin@^0.1.19: + version "0.1.19" + resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-0.1.19.tgz#ceda8bb96b00fe168e9b080272960d20fdcadd6d" + dependencies: + rimraf "^2.6.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-table3@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + dependencies: + object-assign "^4.1.0" + string-width "^2.1.1" + optionalDependencies: + colors "^1.1.2" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + +clone@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + +cloneable-readable@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65" + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + +coa@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.1.tgz#f3f8b0b15073e35d70263fb1042cb2c023db38af" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.8.2, color-convert@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + dependencies: + color-name "^1.1.1" + +color-convert@^1.9.1: + version "1.9.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + dependencies: + color-name "1.1.1" + +color-name@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +color-name@^1.0.0, color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +color-string@^1.4.0, color-string@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.2.tgz#26e45814bc3c9a7cbd6751648a41434514a773a9" + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + +color@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/color/-/color-1.0.3.tgz#e48e832d85f14ef694fb468811c2d5cfe729b55d" + dependencies: + color-convert "^1.8.2" + color-string "^1.4.0" + +color@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colors@^1.1.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +commander@2.15.x, commander@^2.8.1, commander@~2.15.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + +commander@~2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + +commander@~2.17.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + +comment-regex@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/comment-regex/-/comment-regex-1.0.1.tgz#e070d2c4db33231955d0979d27c918fcb6f93565" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + +component-emitter@1.2.1, component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + +compose-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f" + dependencies: + arity-n "^1.0.4" + +compressible@~2.0.14: + version "2.0.15" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.15.tgz#857a9ab0a7e5a07d8d837ed43fe2defff64fe212" + dependencies: + mime-db ">= 1.36.0 < 2" + +compression@^1.5.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.14" + debug "2.6.9" + on-headers "~1.0.1" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +connect-history-api-fallback@^1.3.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +consolidate@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" + dependencies: + bluebird "^3.1.1" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +convert-source-map@^0.3.3: + version "0.3.5" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" + +convert-source-map@^1.1.0, convert-source-map@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0: + version "2.5.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + +core-js@^2.5.3: + version "2.6.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cosmiconfig@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + require-from-string "^2.0.1" + +cosmiconfig@^5.0.0: + version "5.0.5" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.5.tgz#a809e3c2306891ce17ab70359dc8bdf661fe2cd0" + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +css-declaration-sorter@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-3.0.1.tgz#d0e3056b0fd88dc1ea9dceff435adbe9c702a7f8" + dependencies: + postcss "^6.0.0" + timsort "^0.3.0" + +css-loader@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.0.tgz#42952ac22bca5d076978638e9813abce49b8f0cc" + dependencies: + icss-utils "^4.0.0" + loader-utils "^1.2.1" + lodash "^4.17.11" + postcss "^7.0.6" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^2.0.3" + postcss-modules-scope "^2.0.0" + postcss-modules-values "^2.0.0" + postcss-value-parser "^3.3.0" + schema-utils "^1.0.0" + +css-select-base-adapter@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz#0102b3d14630df86c3eb9fa9f5456270106cf990" + +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-select@~1.3.0-rc0: + version "1.3.0-rc0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.3.0-rc0.tgz#6f93196aaae737666ea1036a8cb14a8fcb7a9231" + dependencies: + boolbase "^1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "^1.0.1" + +css-selector-tokenizer@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +css-tree@1.0.0-alpha.29: + version "1.0.0-alpha.29" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39" + dependencies: + mdn-data "~1.1.0" + source-map "^0.5.3" + +css-tree@1.0.0-alpha25: + version "1.0.0-alpha25" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha25.tgz#1bbfabfbf6eeef4f01d9108ff2edd0be2fe35597" + dependencies: + mdn-data "^1.0.0" + source-map "^0.5.3" + +css-unit-converter@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" + +css-url-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + +css@^2.0.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" + dependencies: + inherits "^2.0.3" + source-map "^0.6.1" + source-map-resolve "^0.5.2" + urix "^0.1.0" + +cssdb@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-1.6.0.tgz#3360c4163e07cf4d1efe58c1bc15170535f4d393" + +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + +cssesc@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-1.0.1.tgz#ef7bd8d0229ed6a3a7051ff7771265fe7330e0a8" + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + +cssnano-preset-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.0.tgz#c334287b4f7d49fb2d170a92f9214655788e3b6b" + dependencies: + css-declaration-sorter "^3.0.0" + cssnano-util-raw-cache "^4.0.0" + postcss "^6.0.0" + postcss-calc "^6.0.0" + postcss-colormin "^4.0.0" + postcss-convert-values "^4.0.0" + postcss-discard-comments "^4.0.0" + postcss-discard-duplicates "^4.0.0" + postcss-discard-empty "^4.0.0" + postcss-discard-overridden "^4.0.0" + postcss-merge-longhand "^4.0.0" + postcss-merge-rules "^4.0.0" + postcss-minify-font-values "^4.0.0" + postcss-minify-gradients "^4.0.0" + postcss-minify-params "^4.0.0" + postcss-minify-selectors "^4.0.0" + postcss-normalize-charset "^4.0.0" + postcss-normalize-display-values "^4.0.0" + postcss-normalize-positions "^4.0.0" + postcss-normalize-repeat-style "^4.0.0" + postcss-normalize-string "^4.0.0" + postcss-normalize-timing-functions "^4.0.0" + postcss-normalize-unicode "^4.0.0" + postcss-normalize-url "^4.0.0" + postcss-normalize-whitespace "^4.0.0" + postcss-ordered-values "^4.0.0" + postcss-reduce-initial "^4.0.0" + postcss-reduce-transforms "^4.0.0" + postcss-svgo "^4.0.0" + postcss-unique-selectors "^4.0.0" + +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + +cssnano-util-raw-cache@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.0.tgz#be0a2856e25f185f5f7a2bcc0624e28b7f179a9f" + dependencies: + postcss "^6.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.0.tgz#d2a3de1039aa98bc4ec25001fa050330c2a16dac" + +cssnano@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.0.3.tgz#b694d626906bf1844f573465ecc166b2240b8699" + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.0" + is-resolvable "^1.0.0" + postcss "^6.0.0" + +csso@^3.5.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" + dependencies: + css-tree "1.0.0-alpha.29" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + +date-fns@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@=3.1.0, debug@^3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +debug@^3.2.5: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + dependencies: + ms "^2.1.1" + +debug@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" + dependencies: + ms "^2.1.1" + +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decamelize@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" + dependencies: + xregexp "4.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + +default-gateway@^2.6.0: + version "2.7.2" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f" + dependencies: + execa "^0.10.0" + ip-regex "^2.1.0" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +del@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" + dependencies: + globby "^6.1.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + p-map "^1.1.1" + pify "^3.0.0" + rimraf "^2.2.8" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + dependencies: + buffer-indexof "^1.0.0" + +dom-converter@~0.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" + dependencies: + utila "~0.3" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + +domelementtype@1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" + dependencies: + domelementtype "1" + +domutils@1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-prop@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +electron-to-chromium@^1.3.103: + version "1.3.112" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.112.tgz#1f40a68ceda6328f95218dffeda0f4f3d5412a2f" + +electron-to-chromium@^1.3.47: + version "1.3.48" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz#d3b0d8593814044e092ece2108fc3ac9aea4b900" + +electron-to-chromium@^1.3.52: + version "1.3.52" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" + +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +engine.io-client@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +enhanced-resolve@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.7" + +enhanced-resolve@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.5.1, es-abstract@^1.6.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.45" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + next-tick "1" + +es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.1, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-map@^0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" + +es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" + +es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + +es6-weak-map@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^3.7.1, eslint-scope@~3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + dependencies: + estraverse "^4.1.0" + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + dependencies: + d "1" + es5-ext "~0.10.14" + +"eventemitter3@>=2 <4", eventemitter3@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + dependencies: + cross-spawn "^6.0.0" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + 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" + +express@^4.16.2: + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + range-parser "~1.2.0" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +external-editor@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.0.tgz#dc35c48c6f98a30ca27a20e9687d7f3c77704bb6" + dependencies: + chardet "^0.5.0" + iconv-lite "^0.4.22" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + 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" + +fancy-log@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" + dependencies: + ansi-gray "^0.1.1" + color-support "^1.1.3" + time-stamp "^1.0.0" + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fastparse@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + dependencies: + websocket-driver ">=0.5.1" + +feather-icons@^4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/feather-icons/-/feather-icons-4.10.0.tgz#5c2ba00ecf6f0529e99ab445d054fa6bd0b9c8d6" + dependencies: + classnames "^2.2.5" + core-js "^2.5.3" + +figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + +find-cache-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d" + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^3.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + dependencies: + locate-path "^3.0.0" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +flush-write-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +follow-redirects@^1.0.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.6.1.tgz#514973c44b5757368bad8bddfe52f81f015c94cb" + dependencies: + debug "=3.1.0" + +follow-redirects@^1.2.3, follow-redirects@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.0.tgz#234f49cf770b7f35b40e790f636ceba0c3a0ab77" + dependencies: + debug "^3.1.0" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +fork-ts-checker-webpack-plugin@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-0.5.2.tgz#a73b3630bd0a69409a6e4824e54c03a62fe82d8f" + dependencies: + babel-code-frame "^6.22.0" + chalk "^2.4.1" + chokidar "^2.0.4" + micromatch "^3.1.10" + minimatch "^3.0.4" + tapable "^1.0.0" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.1.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +fsevents@^1.2.2, fsevents@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +function-bind@^1.1.0, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +gather-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + 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" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +glob-all@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.1.0.tgz#8913ddfb5ee1ac7812656241b03d5217c64b02ab" + dependencies: + glob "^7.0.5" + yargs "~1.2.6" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + dependencies: + 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@^7.0.5, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + 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" + +global-modules-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.1.0.tgz#923ec524e8726bb0c1a4ed4b8e21e1ff80c88bbb" + +globals@^11.1.0: + version "11.5.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +graceful-fs@^4.1.15: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + +has@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.2.tgz#1a64bfe4b52e67fb87b9822503d97c019fb6ba42" + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash-sum@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +he@1.1.x, he@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +html-entities@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + +html-minifier@^3.2.3: + version "3.5.16" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.16.tgz#39f5aabaf78bdfc057fe67334226efd7f3851175" + dependencies: + camel-case "3.0.x" + clean-css "4.1.x" + commander "2.15.x" + he "1.1.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.3.x" + +html-webpack-plugin@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b" + dependencies: + html-minifier "^3.2.3" + loader-utils "^0.2.16" + lodash "^4.17.3" + pretty-error "^2.0.2" + tapable "^1.0.0" + toposort "^1.0.0" + util.promisify "1.0.0" + +htmlparser2@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" + dependencies: + domelementtype "1" + domhandler "2.1" + domutils "1.1" + readable-stream "1.0" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.4.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8" + +http-proxy-middleware@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" + dependencies: + http-proxy "^1.16.2" + is-glob "^4.0.0" + lodash "^4.17.5" + micromatch "^3.1.9" + +http-proxy@^1.16.2: + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + dependencies: + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +iconv-lite@0.4.23, iconv-lite@^0.4.22, iconv-lite@^0.4.4: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + +icss-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.0.0.tgz#d52cf4bcdcfa1c45c2dbefb4ffdf6b00ef608098" + dependencies: + postcss "^7.0.5" + +ieee754@^1.1.11, ieee754@^1.1.4: + version "1.1.11" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +import-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + dependencies: + import-from "^2.1.0" + +import-from@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + dependencies: + resolve-from "^3.0.0" + +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +inquirer@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.0.0.tgz#e8c20303ddc15bbfc2c12a6213710ccd9e1413d8" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.0" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.1.0" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +internal-ip@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-3.0.1.tgz#df5c99876e1d2eb2ea2d74f520e3f669a00ece27" + dependencies: + default-gateway "^2.6.0" + ipaddr.js "^1.5.2" + +interpret@^1.0.0, interpret@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" + +invariant@^2.2.0, invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + +ipaddr.js@^1.5.2: + version "1.8.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.1.tgz#fa4b79fa47fd3def5e3b159825161c0a519c9427" + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-arrayish@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.1.tgz#c2dfc386abaa0c3e33c48db3fe87059e69065efd" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-odd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + dependencies: + is-number "^4.0.0" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" + dependencies: + html-comment-regex "^1.1.0" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +jquery@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + +js-base64@^2.1.9: + version "2.4.5" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.5.tgz#e293cd3c7c82f070d700fc7a1ca0a2e69f101f92" + +js-levenshtein@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + +js-yaml@^3.9.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-loader@^0.5.4: + version "0.5.7" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" + +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json3@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.5.0, json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + dependencies: + minimist "^1.2.0" + +json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + dependencies: + minimist "^1.2.0" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + optionalDependencies: + graceful-fs "^4.1.6" + +killable@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + dependencies: + invert-kv "^2.0.0" + +leb@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/leb/-/leb-0.3.0.tgz#32bee9fad168328d6aea8522d833f4180eed1da3" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + +loader-utils@^0.2.16: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + +loader-utils@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash._reinterpolate@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + +lodash.assign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.assign@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash.clone@^4.3.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + +lodash.defaults@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" + dependencies: + lodash.assign "^3.0.0" + lodash.restparam "^3.0.0" + +lodash.defaults@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + +lodash.get@^4.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + +lodash.has@^4.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.some@^4.2.2: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + +lodash.template@^4.2.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + dependencies: + lodash._reinterpolate "~3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + dependencies: + lodash._reinterpolate "~3.0.0" + +lodash.toarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +"lodash@>=3.5 <5", lodash@^4.17, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +lodash@^4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + +loglevel@^1.4.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" + +long@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + +lru-cache@^4.0.1, lru-cache@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^4.1.2: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + dependencies: + yallist "^3.0.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + dependencies: + pify "^3.0.0" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +mdn-data@^1.0.0, mdn-data@~1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +mem@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.1.0.tgz#aeb9be2d21f47e78af29e4ac5978e8afa2ca5b8a" + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^1.0.0" + p-is-promise "^2.0.0" + +memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +merge-source-map@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" + dependencies: + source-map "^0.6.1" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + 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" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +"mime-db@>= 1.36.0 < 2", mime-db@~1.37.0: + version "1.37.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + +mime-types@~2.1.17, mime-types@~2.1.18: + version "2.1.21" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + dependencies: + mime-db "~1.37.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +mime@^2.3.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +mini-css-extract-plugin@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0" + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@0.5.x, mkdirp@^0.5, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment@^2.18.1: + version "2.22.2" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nanomatch@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + dependencies: + 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-odd "^2.0.0" + 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" + +needle@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +neo-async@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee" + +next-tick@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + dependencies: + lower-case "^1.1.1" + +node-emoji@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.8.1.tgz#6eec6bfb07421e2148c75c6bba72421f8530a826" + dependencies: + lodash.toarray "^4.4.0" + +node-forge@0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz#6e4ef5bb5c5203c6552448828c852c40111aac46" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.0" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.1.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^1.0.0-alpha.10: + version "1.0.0-alpha.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.0-alpha.10.tgz#61c8d5f9b5b2e05d84eba941d05b6f5202f68a2a" + dependencies: + semver "^5.3.0" + +node-releases@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.7.tgz#b09a10394d0ed8f7778f72bb861dde68b146303b" + dependencies: + semver "^5.3.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-url@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.2.0.tgz#98d0948afc82829f374320f405fe9ca55a5f8567" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.10" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@^1.0.1, nth-check@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object-path@^0.9.2: + version "0.9.2" + resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.9.2.tgz#0fd9a74fc5fad1ae3968b586bda5c632bd6c05a5" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +object.values@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +opn@^5.1.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.4.0.tgz#cb545e7aab78562beb11aa3bfabc7042e1761035" + dependencies: + is-wsl "^1.1.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-locale@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-2.0.1.tgz#f53118282f5f553c2799541792b723a4c71430c0" + dependencies: + graceful-fs "^4.1.11" + is-plain-obj "^1.1.0" + mkdirp "^0.5.1" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-is-promise@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" + +p-limit@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.1.0.tgz#1d5a0d20fb12707c758a655f6bbc4386b5930d68" + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + dependencies: + p-limit "^2.0.0" + +p-map@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +p-try@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + dependencies: + no-case "^2.2.0" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + dependencies: + better-assert "~1.0.0" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +pbkdf2@^3.0.3: + version "3.0.16" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +perfectionist@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/perfectionist/-/perfectionist-2.4.0.tgz#c147ad3714e126467f1764129ee72df861d47ea0" + dependencies: + comment-regex "^1.0.0" + defined "^1.0.0" + minimist "^1.2.0" + postcss "^5.0.8" + postcss-scss "^0.3.0" + postcss-value-parser "^3.3.0" + read-file-stdin "^0.2.0" + string.prototype.repeat "^0.2.0" + vendors "^1.0.0" + write-file-stdout "0.0.2" + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + dependencies: + find-up "^3.0.0" + +plugin-error@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c" + dependencies: + ansi-colors "^1.0.1" + arr-diff "^4.0.0" + arr-union "^3.1.0" + extend-shallow "^3.0.2" + +portfinder@^1.0.9: + version "1.0.20" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +postcss-advanced-variables@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/postcss-advanced-variables/-/postcss-advanced-variables-2.3.3.tgz#80ac5b05988d02f63352974491e319910f33337e" + dependencies: + "@csstools/sass-import-resolve" "^1" + postcss "^6" + +postcss-apply@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/postcss-apply/-/postcss-apply-0.9.0.tgz#a152e6e34a6c55d0895751929319c262c5d8c289" + dependencies: + babel-runtime "^6.23.0" + balanced-match "^0.4.2" + postcss "^6.0.0" + +postcss-atroot@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/postcss-atroot/-/postcss-atroot-0.1.3.tgz#6752c0230c745140549345b2b0e30ebeda01a405" + dependencies: + postcss "^5.0.5" + +postcss-attribute-case-insensitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-2.0.0.tgz#94dc422c8f90997f16bd33a3654bbbec084963b4" + dependencies: + postcss "^6.0.0" + postcss-selector-parser "^2.2.3" + +postcss-calc@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-6.0.1.tgz#3d24171bbf6e7629d422a436ebfe6dd9511f4330" + dependencies: + css-unit-converter "^1.1.1" + postcss "^6.0.0" + postcss-selector-parser "^2.2.2" + reduce-css-calc "^2.0.0" + +postcss-color-hex-alpha@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-3.0.0.tgz#1e53e6c8acb237955e8fd08b7ecdb1b8b8309f95" + dependencies: + color "^1.0.3" + postcss "^6.0.1" + postcss-message-helpers "^2.0.0" + +postcss-color-mod-function@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-2.4.2.tgz#bdf408f152bc3201517a4c38b7eb5cd2996114fb" + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^6.0.19" + postcss-values-parser "^1.3.2" + +postcss-color-rebeccapurple@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-3.1.0.tgz#ce1269ecc2d0d8bf92aab44bd884e633124c33ec" + dependencies: + postcss "^6.0.22" + postcss-values-parser "^1.5.0" + +postcss-color-rgb@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-rgb/-/postcss-color-rgb-2.0.0.tgz#14539c8a7131494b482e0dd1cc265ff6514b5263" + dependencies: + postcss "^6.0.1" + postcss-value-parser "^3.3.0" + +postcss-colormin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.1.tgz#6f1c18a0155bc69613f2ff13843e2e4ae8ff0bbe" + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.0.tgz#77d77d9aed1dc4e6956e651cc349d53305876f62" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-custom-media@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-6.0.0.tgz#be532784110ecb295044fb5395a18006eb21a737" + dependencies: + postcss "^6.0.1" + +postcss-custom-properties@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-7.0.0.tgz#24dc4fbe6d6ed550ea4fd3b11204660e9ffa3b33" + dependencies: + balanced-match "^1.0.0" + postcss "^6.0.18" + +postcss-custom-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-4.0.1.tgz#781382f94c52e727ef5ca4776ea2adf49a611382" + dependencies: + postcss "^6.0.1" + postcss-selector-matches "^3.0.0" + +postcss-dir-pseudo-class@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-3.0.0.tgz#31a18af3b9b1b33be635599b998a9829896c3fed" + dependencies: + postcss "^6.0.20" + postcss-selector-parser "^3.1.1" + +postcss-discard-comments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.0.tgz#9684a299e76b3e93263ef8fd2adbf1a1c08fd88d" + dependencies: + postcss "^6.0.0" + +postcss-discard-duplicates@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.0.tgz#42f3c267f85fa909e042c35767ecfd65cb2bd72c" + dependencies: + postcss "^6.0.0" + +postcss-discard-empty@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.0.tgz#55e18a59c74128e38c7d2804bcfa4056611fb97f" + dependencies: + postcss "^6.0.0" + +postcss-discard-overridden@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.0.tgz#4a0bf85978784cf1f81ed2c1c1fd9d964a1da1fa" + dependencies: + postcss "^6.0.0" + +postcss-extend-rule@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-extend-rule/-/postcss-extend-rule-1.1.0.tgz#11e4d590ffe4253b853ef1fc03be7167da607d38" + dependencies: + postcss "^6.0.11" + postcss-nesting "^4.2.1" + +postcss-focus-visible@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-2.0.0.tgz#a6b9881f6710f6251790e2f151c94b161e23eeb6" + dependencies: + postcss "^6.0" + +postcss-font-family-system-ui@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-family-system-ui/-/postcss-font-family-system-ui-3.0.0.tgz#675fe7a9e029669f05f8dba2e44c2225ede80623" + dependencies: + postcss "^6.0" + +postcss-font-variant@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-3.0.0.tgz#08ccc88f6050ba82ed8ef2cc76c0c6a6b41f183e" + dependencies: + postcss "^6.0.1" + +postcss-functions@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-functions/-/postcss-functions-3.0.0.tgz#0e94d01444700a481de20de4d55fb2640564250e" + dependencies: + glob "^7.1.2" + object-assign "^4.1.1" + postcss "^6.0.9" + postcss-value-parser "^3.3.0" + +postcss-import@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-11.1.0.tgz#55c9362c9192994ec68865d224419df1db2981f0" + dependencies: + postcss "^6.0.1" + postcss-value-parser "^3.2.3" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-initial@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-2.0.0.tgz#72715f7336e0bb79351d99ee65c4a253a8441ba4" + dependencies: + lodash.template "^4.2.4" + postcss "^6.0.1" + +postcss-js@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-2.0.0.tgz#f75b70470009eb37f998ee9bb516a2899c19ef8d" + dependencies: + camelcase-css "^2.0.0" + postcss "^7.0.0" + +postcss-load-config@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484" + dependencies: + cosmiconfig "^4.0.0" + import-cwd "^2.0.0" + +postcss-loader@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + dependencies: + loader-utils "^1.1.0" + postcss "^7.0.0" + postcss-load-config "^2.0.0" + schema-utils "^1.0.0" + +postcss-logical@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-1.1.1.tgz#bcabf0638d8aa747743b32bc52f9d90d4a3313d2" + dependencies: + postcss "^6.0.20" + +postcss-media-minmax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-3.0.0.tgz#675256037a43ef40bc4f0760bfd06d4dc69d48d2" + dependencies: + postcss "^6.0.1" + +postcss-merge-longhand@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.2.tgz#a2bcd7b0f9dca41ee84ba0cee23a5e6cb465ec3a" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.1.tgz#430fd59b3f2ed2e8afcd0b31278eda39854abb10" + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.0.tgz#4cc33d283d6a81759036e757ef981d92cbd85bed" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.0.tgz#3fc3916439d27a9bb8066db7cdad801650eb090e" + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.0.tgz#05e9166ee48c05af651989ce84d39c1b4d790674" + dependencies: + alphanum-sort "^1.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.0.tgz#b1e9f6c463416d3fcdcb26e7b785d95f61578aad" + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.4.tgz#a000bb07e4f57f412ba35c904d035cfd4a7b9446" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^7.0.6" + postcss-value-parser "^3.3.1" + +postcss-modules-scope@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.0.1.tgz#2c0f2394cde4cd09147db054c68917e38f6d43a4" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^7.0.6" + +postcss-modules-values@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^7.0.6" + +postcss-nested@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-3.0.0.tgz#cde40bd07a078565f3df72e2dc2665871c724852" + dependencies: + postcss "^6.0.14" + postcss-selector-parser "^3.1.1" + +postcss-nested@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-4.1.1.tgz#2074e6641583bf7151d951908d68fa95039fe340" + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + +postcss-nesting@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-4.2.1.tgz#0483bce338b3f0828ced90ff530b29b98b00300d" + dependencies: + postcss "^6.0.11" + +postcss-normalize-charset@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.0.tgz#24527292702d5e8129eafa3d1de49ed51a6ab730" + dependencies: + postcss "^6.0.0" + +postcss-normalize-display-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz#950e0c7be3445770a160fffd6b6644c3c0cd8f89" + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.0.tgz#ee9343ab981b822c63ab72615ecccd08564445a3" + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.0.tgz#b711c592cf16faf9ff575e42fa100b6799083eff" + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.0.tgz#718cb6d30a6fac6ac6a830e32c06c07dbc66fe5d" + dependencies: + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.0.tgz#0351f29886aa981d43d91b2c2bd1aea6d0af6d23" + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.0.tgz#5acd5d47baea5d17674b2ccc4ae5166fa88cdf97" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.0.tgz#b7a9c8ad26cf26694c146eb2d68bd0cf49956f0d" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.0.tgz#1da7e76b10ae63c11827fa04fc3bb4a1efe99cc0" + dependencies: + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.0.0.tgz#58b40c74f72e022eb34152c12e4b0f9354482fc2" + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-page-break@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-1.0.0.tgz#09a63b6e03db092d38569b33dcba42a343ace60b" + dependencies: + postcss "^6.0.16" + +postcss-preset-env@^3.2.2, postcss-preset-env@^3.4.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-3.5.0.tgz#b3aae2c65e5b3fa61d735b70392fa758a665b785" + dependencies: + "@csstools/postcss-image-set-function" "^1.0.0" + browserslist "^3.2.4" + caniuse-lite "^1.0.30000823" + cssdb "^1.6.0" + postcss "^6.0.21" + postcss-apply "^0.9.0" + postcss-attribute-case-insensitive "^2.0.0" + postcss-color-hex-alpha "^3.0.0" + postcss-color-mod-function "^2.4.2" + postcss-color-rebeccapurple "^3.0.0" + postcss-color-rgb "^2.0.0" + postcss-custom-media "^6.0.0" + postcss-custom-properties "^7.0.0" + postcss-custom-selectors "^4.0.1" + postcss-dir-pseudo-class "^3.0.0" + postcss-focus-visible "^2.0.0" + postcss-font-family-system-ui "^3.0.0" + postcss-font-variant "^3.0.0" + postcss-initial "^2.0.0" + postcss-logical "^1.1.1" + postcss-media-minmax "^3.0.0" + postcss-nesting "^4.2.1" + postcss-page-break "^1.0.0" + postcss-pseudo-class-any-link "^4.0.0" + postcss-replace-overflow-wrap "^2.0.0" + postcss-selector-matches "^3.0.1" + postcss-selector-not "^3.0.1" + +postcss-property-lookup@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-property-lookup/-/postcss-property-lookup-2.0.0.tgz#c995d1df42a75420f2aea834c2cbe296b2c15922" + dependencies: + object-assign "^4.0.1" + postcss "^6.0.6" + tcomb "^3.2.21" + +postcss-pseudo-class-any-link@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-4.0.0.tgz#9152a0613d3450720513e8892854bae42d0ee68e" + dependencies: + postcss "^6.0.1" + postcss-selector-parser "^2.2.3" + +postcss-reduce-initial@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.1.tgz#f2d58f50cea2b0c5dc1278d6ea5ed0ff5829c293" + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^6.0.0" + +postcss-reduce-transforms@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.0.tgz#f645fc7440c35274f40de8104e14ad7163edf188" + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + +postcss-replace-overflow-wrap@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-2.0.0.tgz#794db6faa54f8db100854392a93af45768b4e25b" + dependencies: + postcss "^6.0.1" + +postcss-scss@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-0.3.1.tgz#65c610d8e2a7ee0e62b1835b71b8870734816e4b" + dependencies: + postcss "^5.2.4" + +postcss-selector-matches@^3.0.0, postcss-selector-matches@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-3.0.1.tgz#e5634011e13950881861bbdd58c2d0111ffc96ab" + dependencies: + balanced-match "^0.4.2" + postcss "^6.0.1" + +postcss-selector-not@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-3.0.1.tgz#2e4db2f0965336c01e7cec7db6c60dff767335d9" + dependencies: + balanced-match "^0.4.2" + postcss "^6.0.1" + +postcss-selector-parser@^2.2.2, postcss-selector-parser@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^3.0.0, postcss-selector-parser@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" + dependencies: + dot-prop "^4.1.1" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^5.0.0, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^5.0.0-rc.3: + version "5.0.0-rc.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0-rc.3.tgz#c4525dcc8eb90166c53dcbf0cb9317ceff5a15b5" + dependencies: + babel-eslint "^8.2.3" + cssesc "^1.0.1" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.0.tgz#c0bbad02520fc636c9d78b0e8403e2e515c32285" + dependencies: + is-svg "^3.0.0" + postcss "^6.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.0.tgz#04c1e9764c75874261303402c41f0e9769fc5501" + dependencies: + alphanum-sort "^1.0.0" + postcss "^6.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + +postcss-values-parser@^1.3.2, postcss-values-parser@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-1.5.0.tgz#5d9fa63e2bcb0179ce48f3235303765eb89f3047" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss@^5.0.5, postcss@^5.0.8, postcss@^5.2.4: + version "5.2.18" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.2.3" + +postcss@^6, postcss@^6.0, postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.14, postcss@^6.0.16, postcss@^6.0.18, postcss@^6.0.19, postcss@^6.0.20, postcss@^6.0.21, postcss@^6.0.22, postcss@^6.0.6, postcss@^6.0.9: + version "6.0.22" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.22.tgz#e23b78314905c3b90cbd61702121e7a78848f2a3" + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + +postcss@^7.0.0, postcss@^7.0.11, postcss@^7.0.14, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +precss@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/precss/-/precss-3.1.2.tgz#c82c0aa4ca5fe1e879799d697db0fac6d15d23bc" + dependencies: + postcss "^6.0.19" + postcss-advanced-variables "^2.3.3" + postcss-atroot "^0.1.3" + postcss-extend-rule "^1.1.0" + postcss-nested "^3.0.0" + postcss-preset-env "^3.2.2" + postcss-property-lookup "^2.0.0" + +prettier@1.16.3: + version "1.16.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d" + +pretty-error@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" + dependencies: + renderkid "^2.0.1" + utila "~0.4" + +pretty-hrtime@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" + +private@^0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + +purgecss-webpack-plugin@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/purgecss-webpack-plugin/-/purgecss-webpack-plugin-1.1.0.tgz#96c993b11ddf2a6a179a28704da75906be72c21f" + dependencies: + purgecss "^1.0.0" + webpack "^4.8.3" + webpack-sources "^1.1.0" + +purgecss@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-1.0.0.tgz#827ff21052813b18d03564c61d2f794c2a2edaae" + dependencies: + glob "^7.1.2" + postcss "^6.0.22" + postcss-selector-parser "^5.0.0-rc.3" + yargs "^11.0.0" + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + +qs@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +querystringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.0.3, range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +rc@^1.1.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + dependencies: + pify "^2.3.0" + +read-file-stdin@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/read-file-stdin/-/read-file-stdin-0.2.1.tgz#25eccff3a153b6809afacb23ee15387db9e0ee61" + dependencies: + gather-stream "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + 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" + +readable-stream@1.0: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^3.0.6: + version "3.1.1" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +reduce-css-calc@^2.0.0: + version "2.1.4" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.4.tgz#c20e9cda8445ad73d4ff4bea960c6f8353791708" + dependencies: + css-unit-converter "^1.1.1" + postcss-value-parser "^3.3.0" + +regenerate-unicode-properties@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-6.0.0.tgz#0fc26f9d5142289df4e177dec58f303d2d097c16" + dependencies: + regenerate "^1.3.3" + +regenerate-unicode-properties@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c" + dependencies: + regenerate "^1.4.0" + +regenerate@^1.2.1, regenerate@^1.3.3, regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@^0.13.3: + version "0.13.3" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" + dependencies: + private "^0.1.6" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regex-parser@^2.2.9: + version "2.2.10" + resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.10.tgz#9e66a8f73d89a107616e63b39d4deddfee912b37" + +regexp-tree@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.1.tgz#27b455f9b138ca2e84c090e9aff1ffe2a04d97fa" + dependencies: + cli-table3 "^0.5.0" + colors "^1.1.2" + yargs "^12.0.5" + +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regexpu-core@^4.1.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.1.5.tgz#57fdfe1148f8a7a069086228515130cf1820ddd0" + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^6.0.0" + regjsgen "^0.4.0" + regjsparser "^0.3.0" + unicode-match-property-ecmascript "^1.0.3" + unicode-match-property-value-ecmascript "^1.0.1" + +regexpu-core@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.4.0.tgz#8d43e0d1266883969720345e70c275ee0aec0d32" + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^7.0.0" + regjsgen "^0.5.0" + regjsparser "^0.6.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.0.2" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsgen@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.4.0.tgz#c1eb4c89a209263f8717c782591523913ede2561" + +regjsgen@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +regjsparser@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.3.0.tgz#3c326da7fcfd69fa0d332575a41c8c0cdf588c96" + dependencies: + jsesc "~0.5.0" + +regjsparser@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" + dependencies: + jsesc "~0.5.0" + +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +renderkid@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.1.tgz#898cabfc8bede4b7b91135a3ffd323e58c0db319" + dependencies: + css-select "^1.1.0" + dom-converter "~0.1" + htmlparser2 "~3.3.0" + strip-ansi "^3.0.0" + utila "~0.3" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-from-string@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-url-loader@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.0.0.tgz#c47eeca1fc8d62b08dc2eef12b3af5af3e775c74" + dependencies: + adjust-sourcemap-loader "^1.1.0" + camelcase "^4.1.0" + compose-function "^3.0.3" + convert-source-map "^1.5.1" + es6-iterator "^2.0.3" + loader-utils "^1.1.0" + lodash.defaults "^4.0.0" + postcss "^7.0.0" + rework "^1.0.1" + rework-visit "^1.0.0" + source-map "^0.5.7" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@^1.1.7, resolve@^1.3.2: + version "1.7.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +rework-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rework-visit/-/rework-visit-1.0.0.tgz#9945b2803f219e2f7aca00adb8bc9f640f842c9a" + +rework@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rework/-/rework-1.0.1.tgz#30806a841342b54510aa4110850cd48534144aa7" + dependencies: + convert-source-map "^0.3.3" + css "^2.0.0" + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + +rxjs@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.0.tgz#e024d0e180b72756a83c2aaea8f25423751ba978" + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sax@^1.2.4, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +schema-utils@^0.4.4, schema-utils@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + +selfsigned@^1.9.1: + version "1.10.4" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd" + dependencies: + node-forge "0.7.5" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +semver@^5.0.1, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serialize-javascript@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" + +serve-index@^1.7.2: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + dependencies: + is-arrayish "^0.3.1" + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + 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" + +socket.io-client@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.3.1" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + dependencies: + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" + json3 "^3.3.2" + url-parse "^1.4.3" + +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + +source-list-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" + +source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.9: + version "0.5.10" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + dependencies: + safe-buffer "^5.1.1" + +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + dependencies: + figgy-pudding "^3.5.1" + +stable@~0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string.prototype.repeat@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz#aba36de08dcee6a5a337d49b2ea1da1b28fc0ecf" + +string_decoder@^1.0.0, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-comments@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-1.0.2.tgz#82b9c45e7f05873bee53f37168af930aa368679d" + dependencies: + babel-extract-comments "^1.0.0" + babel-plugin-transform-object-rest-spread "^6.26.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +style-loader@^0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + +stylehacks@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.0.tgz#64b323951c4a24e5fc7b2ec06c137bf32d155e8a" + dependencies: + browserslist "^4.0.0" + postcss "^6.0.0" + postcss-selector-parser "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +supports-color@^4.2.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" + dependencies: + has-flag "^2.0.0" + +supports-color@^5.1.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" + +supports-color@^5.3.0, supports-color@^5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + dependencies: + has-flag "^3.0.0" + +svgo@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.0.5.tgz#7040364c062a0538abacff4401cea6a26a7a389a" + dependencies: + coa "~2.0.1" + colors "~1.1.2" + css-select "~1.3.0-rc0" + css-select-base-adapter "~0.1.0" + css-tree "1.0.0-alpha25" + css-url-regex "^1.1.0" + csso "^3.5.0" + js-yaml "~3.10.0" + mkdirp "~0.5.1" + object.values "^1.0.4" + sax "~1.2.4" + stable "~0.1.6" + unquote "~1.1.1" + util.promisify "~1.0.0" + +tailwindcss@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-0.7.4.tgz#fb7926821d42eacdc12e6621a49d21f37a3ff9e9" + dependencies: + autoprefixer "^9.4.5" + bytes "^3.0.0" + chalk "^2.4.1" + css.escape "^1.5.1" + fs-extra "^4.0.2" + lodash "^4.17.5" + node-emoji "^1.8.1" + perfectionist "^2.4.0" + postcss "^7.0.11" + postcss-functions "^3.0.0" + postcss-js "^2.0.0" + postcss-nested "^4.1.1" + postcss-selector-parser "^5.0.0" + pretty-hrtime "^1.0.3" + strip-comments "^1.0.2" + +tapable@^0.2.7: + version "0.2.8" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" + +tapable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" + +tapable@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.1.tgz#4d297923c5a72a42360de2ab52dadfaaec00018e" + +tar@^4: + version "4.4.4" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +tcomb@^3.2.21: + version "3.2.27" + resolved "https://registry.yarnpkg.com/tcomb/-/tcomb-3.2.27.tgz#f4928bfc536b959d21a47e5f5f1ca2b2e4b7188a" + +terser-webpack-plugin@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.1.tgz#7545da9ae5f4f9ae6a0ac961eb46f5e7c845cc26" + dependencies: + cacache "^11.0.2" + find-cache-dir "^2.0.0" + schema-utils "^1.0.0" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + terser "^3.8.1" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +terser@^3.8.1: + version "3.16.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.16.0.tgz#04028e6e5da461d91691cedd75fa53a17f2f20d9" + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + source-map-support "~0.5.9" + +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through@^2.3.6, through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +thunky@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" + +time-stamp@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + dependencies: + setimmediate "^1.0.4" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toposort@^1.0.0: + version "1.0.7" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +ts-loader@^5.3.3: + version "5.3.3" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-5.3.3.tgz#8b4af042e773132d86b3c99ef0acf3b4d325f473" + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + loader-utils "^1.0.2" + micromatch "^3.1.4" + semver "^5.0.1" + +tslib@^1.9.0: + version "1.9.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.2.tgz#8be0cc9a1f6dc7727c38deb16c2ebd1a2892988e" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +typescript@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.1.tgz#6de14e1db4b8a006ac535e482c8ba018c55f750b" + +uglify-es@^3.3.4: + version "3.3.9" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + +uglify-js@3.3.x: + version "3.3.28" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.28.tgz#0efb9a13850e11303361c1051f64d2ec68d9be06" + dependencies: + commander "~2.15.0" + source-map "~0.6.1" + +uglify-js@^2.8.29: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-js@^3.0.0: + version "3.4.9" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uglifyjs-webpack-plugin@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" + dependencies: + source-map "^0.5.6" + uglify-js "^2.8.29" + webpack-sources "^1.0.1" + +uglifyjs-webpack-plugin@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz#2ef8387c8f1a903ec5e44fa36f9f3cbdcea67641" + dependencies: + cacache "^10.0.4" + find-cache-dir "^1.0.0" + schema-utils "^0.4.5" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +uglifyjs-webpack-plugin@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-2.1.1.tgz#6937d7513a37280d4792f1fb536bef35e08e420a" + dependencies: + cacache "^11.2.0" + find-cache-dir "^2.0.0" + schema-utils "^1.0.0" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-js "^3.0.0" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +unicode-canonical-property-names-ecmascript@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.3.tgz#f6119f417467593c0086357c85546b6ad5abc583" + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + +unicode-match-property-ecmascript@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.3.tgz#db9b1cb4ffc67e0c5583780b1b59370e4cbe97b9" + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.2" + unicode-property-aliases-ecmascript "^1.0.3" + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.1.tgz#fea059120a016f403afd3bf586162b4db03e0604" + +unicode-match-property-value-ecmascript@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz#9f1dc76926d6ccf452310564fd834ace059663d4" + +unicode-property-aliases-ecmascript@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.3.tgz#ac3522583b9e630580f916635333e00c5ead690d" + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +unique-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + +universalify@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.0.0, upath@^1.0.5, upath@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + +uri-js@^4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse@^1.4.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" + dependencies: + querystringify "^2.0.0" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" + dependencies: + kind-of "^6.0.2" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util.promisify@1.0.0, util.promisify@^1.0.0, util.promisify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + dependencies: + inherits "2.0.3" + +utila@~0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + +uuid@^3.0.1, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +v8-compile-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.0.tgz#526492e35fc616864284700b7043e01baee09f0a" + +validate-npm-package-license@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validator@^8.1.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-8.2.0.tgz#3c1237290e37092355344fef78c231249dab77b9" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +vee-validate@^2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/vee-validate/-/vee-validate-2.1.7.tgz#33984454d8a633cdc4825a2cf5857747d91bae67" + +vendors@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801" + +vinyl@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" + dependencies: + 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" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +vue-axios@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/vue-axios/-/vue-axios-2.1.1.tgz#6167f2db93065d9bcfc90e65d063ccf34f8b1d63" + +vue-devtools@^3.1.9: + version "3.1.9" + resolved "https://registry.yarnpkg.com/vue-devtools/-/vue-devtools-3.1.9.tgz#283b458c6853f569a987da0092e7c52e8243a436" + +vue-feather-icons@^4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/vue-feather-icons/-/vue-feather-icons-4.7.1.tgz#d8c55fbee7c9ad59689ebbaf07ad1e2f1e5c37da" + dependencies: + babel-helper-vue-jsx-merge-props "^2.0.2" + +vue-hot-reload-api@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.1.tgz#b2d3d95402a811602380783ea4f566eb875569a2" + +vue-i18n@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.6.0.tgz#63848b183cf6f100436bcdd84382416e43b07188" + +vue-loader@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.6.2.tgz#892741d96260936ff69e892f72ec361ba4d100d2" + dependencies: + "@vue/component-compiler-utils" "^2.5.1" + hash-sum "^1.0.2" + loader-utils "^1.1.0" + vue-hot-reload-api "^2.3.0" + vue-style-loader "^4.1.0" + +vue-mc@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/vue-mc/-/vue-mc-0.2.4.tgz#93569cb6e08e2d1c52968a74cce8a6b2c9bda66a" + dependencies: + axios "^0.16" + lodash "^4.17" + moment "^2.18.1" + validator "^8.1.0" + vue "^2.2" + +vue-router@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.1.tgz#d9b05ad9c7420ba0f626d6500d693e60092cc1e9" + +vue-style-loader@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.2.tgz#dedf349806f25ceb4e64f3ad7c0a44fba735fcf8" + dependencies: + hash-sum "^1.0.2" + loader-utils "^1.0.2" + +vue-template-compiler@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.4.tgz#0feacfe35e3386033bf4fe31ab4ff1dc1a0c5dec" + dependencies: + de-indent "^1.0.2" + he "^1.1.0" + +vue-template-es2015-compiler@^1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.8.2.tgz#dd73e80ba58bb65dd7a8aa2aeef6089cf6116f2a" + +vue@^2.2: + version "2.5.16" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.16.tgz#07edb75e8412aaeed871ebafa99f4672584a0085" + +vue@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.4.tgz#8a5a44e5740d8b8423a420c8655c97663421fb4d" + +vueify-insert-css@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/vueify-insert-css/-/vueify-insert-css-1.0.0.tgz#57e5d791907e8c9d87ae6de099a2174bd0a7f990" + +vuex-router-sync@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/vuex-router-sync/-/vuex-router-sync-5.0.0.tgz#1a225c17a1dd9e2f74af0a1b2c62072e9492b305" + +vuex@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.1.tgz#e761352ebe0af537d4bb755a9b9dc4be3df7efd2" + +watchpack@^1.4.0, watchpack@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + dependencies: + minimalistic-assert "^1.0.0" + +webpack-assets-manifest@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/webpack-assets-manifest/-/webpack-assets-manifest-3.1.1.tgz#39bbc3bf2ee57fcd8ba07cda51c9ba4a3c6ae1de" + dependencies: + chalk "^2.0" + lodash.get "^4.0" + lodash.has "^4.0" + mkdirp "^0.5" + schema-utils "^1.0.0" + tapable "^1.0.0" + webpack-sources "^1.0.0" + +webpack-cli@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.0.3.tgz#1a8c6e09dee1fd45305f3b3828cf081903cee0f2" + dependencies: + chalk "^2.4.1" + cross-spawn "^6.0.5" + enhanced-resolve "^4.0.0" + global-modules-path "^2.1.0" + import-local "^1.0.0" + inquirer "^6.0.0" + interpret "^1.1.0" + loader-utils "^1.1.0" + supports-color "^5.4.0" + v8-compile-cache "^2.0.0" + yargs "^11.1.0" + +webpack-dev-middleware@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" + dependencies: + memory-fs "~0.4.1" + mime "^2.3.1" + range-parser "^1.0.3" + webpack-log "^2.0.0" + +webpack-dev-server@^3.1.14: + version "3.1.14" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469" + dependencies: + ansi-html "0.0.7" + bonjour "^3.5.0" + chokidar "^2.0.0" + compression "^1.5.2" + connect-history-api-fallback "^1.3.0" + debug "^3.1.0" + del "^3.0.0" + express "^4.16.2" + html-entities "^1.2.0" + http-proxy-middleware "~0.18.0" + import-local "^2.0.0" + internal-ip "^3.0.1" + ip "^1.1.5" + killable "^1.0.0" + loglevel "^1.4.1" + opn "^5.1.0" + portfinder "^1.0.9" + schema-utils "^1.0.0" + selfsigned "^1.9.1" + semver "^5.6.0" + serve-index "^1.7.2" + sockjs "0.3.19" + sockjs-client "1.3.0" + spdy "^4.0.0" + strip-ansi "^3.0.0" + supports-color "^5.1.0" + url "^0.11.0" + webpack-dev-middleware "3.4.0" + webpack-log "^2.0.0" + yargs "12.0.2" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-manifest-plugin@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-2.0.3.tgz#b42c5b08a0319cedb3ec45d9375a9ecee0acf5eb" + dependencies: + fs-extra "^0.30.0" + lodash ">=3.5 <5" + tapable "^1.0.0" + +webpack-shell-plugin@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/webpack-shell-plugin/-/webpack-shell-plugin-0.5.0.tgz#29b8a1d80ddeae0ddb10e729667f728653c2c742" + +webpack-sources@^1.0.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-sources@^1.0.1, webpack-sources@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-stream@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/webpack-stream/-/webpack-stream-4.0.3.tgz#96399fd7911b94c264bfc59e356738a89b5ca136" + dependencies: + fancy-log "^1.3.2" + lodash.clone "^4.3.2" + lodash.some "^4.2.2" + memory-fs "^0.4.1" + plugin-error "^1.0.1" + supports-color "^5.3.0" + through "^2.3.8" + vinyl "^2.1.0" + webpack "^3.4.1" + +webpack@^3.4.1: + version "3.12.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.12.0.tgz#3f9e34360370602fcf639e97939db486f4ec0d74" + dependencies: + acorn "^5.0.0" + acorn-dynamic-import "^2.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + async "^2.1.2" + enhanced-resolve "^3.4.0" + escope "^3.6.0" + interpret "^1.0.0" + json-loader "^0.5.4" + json5 "^0.5.1" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^4.2.1" + tapable "^0.2.7" + uglifyjs-webpack-plugin "^0.4.6" + watchpack "^1.4.0" + webpack-sources "^1.0.1" + yargs "^8.0.2" + +webpack@^4.29.0: + version "4.29.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.0.tgz#f2cfef83f7ae404ba889ff5d43efd285ca26e750" + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/wasm-edit" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + acorn "^6.0.5" + acorn-dynamic-import "^4.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^0.4.4" + tapable "^1.1.0" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" + +webpack@^4.8.3: + version "4.10.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.10.2.tgz#d6a4cc3e2fa748f96ca62a70f91eaaa939ef3858" + dependencies: + "@webassemblyjs/ast" "1.5.9" + "@webassemblyjs/wasm-edit" "1.5.9" + "@webassemblyjs/wasm-opt" "1.5.9" + "@webassemblyjs/wasm-parser" "1.5.9" + acorn "^5.0.0" + acorn-dynamic-import "^3.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^0.1.1" + enhanced-resolve "^4.0.0" + eslint-scope "^3.7.1" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^0.4.4" + tapable "^1.0.0" + uglifyjs-webpack-plugin "^1.2.4" + watchpack "^1.5.0" + webpack-sources "^1.0.1" + +websocket-driver@>=0.5.1: + version "0.7.0" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + dependencies: + http-parser-js ">=0.4.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-stdout@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/write-file-stdout/-/write-file-stdout-0.0.2.tgz#c252d7c7c5b1b402897630e3453c7bfe690d9ca1" + +ws-wrapper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ws-wrapper/-/ws-wrapper-2.0.0.tgz#598f67a9fdf13d532abaf593d8ce8889f94b5a2a" + dependencies: + eventemitter3 ">=2 <4" + +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + dependencies: + async-limiter "~1.0.0" + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + +xregexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +xterm@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.5.1.tgz#d2e62ab26108a771b7bd1b7be4f6578fb4aff922" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + +yargs-parser@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + dependencies: + camelcase "^4.1.0" + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + dependencies: + camelcase "^4.1.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + +yargs@12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" + dependencies: + cliui "^4.0.0" + decamelize "^2.0.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^10.1.0" + +yargs@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" + +yargs@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + +yargs@~1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b" + dependencies: + minimist "^0.1.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"